From b5672b9c43112b2a808727f9e88c0f5fd24a6d73 Mon Sep 17 00:00:00 2001 From: Lowe Thiderman Date: Sat, 22 Feb 2014 09:02:46 +0100 Subject: Add Arch dependency instructions to README.md Also accidentally clear trailing whitespace in README. vim autocommands ftw. --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b7f464c1ea..86f7dc47e8 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Neovim is a project that seeks to aggressively refactor vim source code in order - Simplify maintenance to improve the speed that bug fixes and features get merged. - Split the work between multiple developers. -- Enable the implementation of new/modern user interfaces without any modifications to the core source. +- Enable the implementation of new/modern user interfaces without any modifications to the core source. - Improve the extensibility power with a new plugin architecture based on coprocesses. Plugins will be written in any programming language without any explicit support from the editor. By achieving those goals new developers will soon join the community, consequently improving the editor for all users. @@ -65,7 +65,7 @@ libuv is a modern multi-platform library with functions to perform common system All code supporting embedded scripting language interpreters will be replaced by a new plugin system that will support extensions written in any programming language. -Compatibility layers will be provided for vim plugins written in some of the currently supported scripting languages such as python or ruby. Most plugins should work on neovim with little modifications, if any. +Compatibility layers will be provided for vim plugins written in some of the currently supported scripting languages such as python or ruby. Most plugins should work on neovim with little modifications, if any. This is how the new plugin system will work: @@ -86,7 +86,7 @@ plugin -> neovim: {"id": 2, "method": "showPopup", "params": {"size": {"width": plugin -> neovim: {"id": 2, "result": true}} ``` -That shows an hypothetical conversation between neovim and completion plugin that displays completions when the user presses Ctrl+Space. The above scheme gives neovim near limitless extensibility and also improves stability as plugins will automatically be isolated from the main executable. +That shows an hypothetical conversation between neovim and completion plugin that displays completions when the user presses Ctrl+Space. The above scheme gives neovim near limitless extensibility and also improves stability as plugins will automatically be isolated from the main executable. This system can also easily emulate the current scripting languages interfaces to vim. For example, a plugin can emulate the python interface by running python scripts sent by vim in its own context and by exposing a 'vim' module with an API matching the current one. Calls to the API would simply be translated to json-rpc messages sent to vim. @@ -138,7 +138,7 @@ Here's a diagram that illustrates how a client-server process tree might look li ``` Server daemon listening on tcp sockets <------ GUI 1 (attach/detach to running instances using tcp sockets) | | - ---> Neovim | + ---> Neovim | | GUI 2 (sharing the same session with GUI 1) ---> Plugin 1 | @@ -182,16 +182,19 @@ For OsX: * Install sha1sum Via MacPorts: - + sudo port install md5sha1sum cmake libtool Via Homebrew: - + brew install md5sha1sum cmake libtool +For Arch Linux: + + sudo pacman -S base-devel cmake ncurses + TODO: release the Dockerfile which has this in it -TODO: Arch instructions ###Building -- cgit From 7cadf15eee1f377e9a7bb147180b86cf9637b2c6 Mon Sep 17 00:00:00 2001 From: aph Date: Sat, 22 Feb 2014 11:57:44 +0000 Subject: include a copy of the Vim License --- README.md | 19 ++++++++++++++ vim-license.txt | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 vim-license.txt diff --git a/README.md b/README.md index b7f464c1ea..2cba2b2b8d 100644 --- a/README.md +++ b/README.md @@ -207,3 +207,22 @@ To build and run the tests: ### Community Join the community on IRC in #neovim on Freenode. + +### License + +Vim itself is distributed under the terms of the Vim License. +See vim-license.txt for details. + +Vim also includes a message along the following lines: + + Vim is Charityware. You can use and copy it as much as you like, but you are + encouraged to make a donation for needy children in Uganda. Please see the + kcc section of the vim docs or visit the ICCF web site, available at these URLs: + + http://iccf-holland.org/ + http://www.vim.org/iccf/ + http://www.iccf.nl/ + + You can also sponsor the development of Vim. Vim sponsors can vote for + features. The money goes to Uganda anyway. + diff --git a/vim-license.txt b/vim-license.txt new file mode 100644 index 0000000000..dd685292ba --- /dev/null +++ b/vim-license.txt @@ -0,0 +1,78 @@ +VIM LICENSE + +I) There are no restrictions on distributing unmodified copies of Vim except + that they must include this license text. You can also distribute + unmodified parts of Vim, likewise unrestricted except that they must + include this license text. You are also allowed to include executables + that you made from the unmodified Vim sources, plus your own usage + examples and Vim scripts. + +II) It is allowed to distribute a modified (or extended) version of Vim, + including executables and/or source code, when the following four + conditions are met: + 1) This license text must be included unmodified. + 2) The modified Vim must be distributed in one of the following five ways: + a) If you make changes to Vim yourself, you must clearly describe in + the distribution how to contact you. When the maintainer asks you + (in any way) for a copy of the modified Vim you distributed, you + must make your changes, including source code, available to the + maintainer without fee. The maintainer reserves the right to + include your changes in the official version of Vim. What the + maintainer will do with your changes and under what license they + will be distributed is negotiable. If there has been no negotiation + then this license, or a later version, also applies to your changes. + The current maintainer is Bram Moolenaar . If this + changes it will be announced in appropriate places (most likely + vim.sf.net, www.vim.org and/or comp.editors). When it is completely + impossible to contact the maintainer, the obligation to send him + your changes ceases. Once the maintainer has confirmed that he has + received your changes they will not have to be sent again. + b) If you have received a modified Vim that was distributed as + mentioned under a) you are allowed to further distribute it + unmodified, as mentioned at I). If you make additional changes the + text under a) applies to those changes. + c) Provide all the changes, including source code, with every copy of + the modified Vim you distribute. This may be done in the form of a + context diff. You can choose what license to use for new code you + add. The changes and their license must not restrict others from + making their own changes to the official version of Vim. + d) When you have a modified Vim which includes changes as mentioned + under c), you can distribute it without the source code for the + changes if the following three conditions are met: + - The license that applies to the changes permits you to distribute + the changes to the Vim maintainer without fee or restriction, and + permits the Vim maintainer to include the changes in the official + version of Vim without fee or restriction. + - You keep the changes for at least three years after last + distributing the corresponding modified Vim. When the maintainer + or someone who you distributed the modified Vim to asks you (in + any way) for the changes within this period, you must make them + available to him. + - You clearly describe in the distribution how to contact you. This + contact information must remain valid for at least three years + after last distributing the corresponding modified Vim, or as long + as possible. + e) When the GNU General Public License (GPL) applies to the changes, + you can distribute the modified Vim under the GNU GPL version 2 or + any later version. + 3) A message must be added, at least in the output of the ":version" + command and in the intro screen, such that the user of the modified Vim + is able to see that it was modified. When distributing as mentioned + under 2)e) adding the message is only required for as far as this does + not conflict with the license used for the changes. + 4) The contact information as required under 2)a) and 2)d) must not be + removed or changed, except that the person himself can make + corrections. + +III) If you distribute a modified version of Vim, you are encouraged to use + the Vim license for your changes and make them available to the + maintainer, including the source code. The preferred way to do this is + by e-mail or by uploading the files to a server and e-mailing the URL. + If the number of changes is small (e.g., a modified Makefile) e-mailing a + context diff will do. The e-mail address to be used is + + +IV) It is not allowed to remove this license from the distribution of the Vim + sources, parts of it or from a modified version. You may use this + license for previous Vim releases instead of the license that they came + with, at your option. -- cgit From 6ab89686854e437b1ffb4de8b6e9daeeec09ccc6 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Fri, 21 Feb 2014 19:55:12 -0800 Subject: Cleanup refactoring in main --- src/main.c | 263 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 175 insertions(+), 88 deletions(-) diff --git a/src/main.c b/src/main.c index 02da51fb59..8eb0a605b3 100644 --- a/src/main.c +++ b/src/main.c @@ -71,6 +71,15 @@ static void init_locale __ARGS((void)); # endif static void parse_command_name __ARGS((mparm_T *parmp)); static void command_line_scan __ARGS((mparm_T *parmp)); +static void init_params __ARGS((mparm_T *parmp, int argc, char **argv)); +static void init_startuptime __ARGS((mparm_T *parmp)); +static void allocate_generic_buffers __ARGS((void)); +static void check_and_set_isatty __ARGS((mparm_T *parmp)); +static char_u* get_fname __ARGS((mparm_T *parmp)); +static void set_window_layout __ARGS((mparm_T *parmp)); +static void load_plugins __ARGS((void)); +static void handle_quickfix __ARGS((mparm_T *parmp)); +static void handle_tag __ARGS((char_u *tagname)); static void check_tty __ARGS((mparm_T *parmp)); static void read_stdin __ARGS((void)); static void create_windows __ARGS((mparm_T *parmp)); @@ -113,10 +122,6 @@ main(argc, argv) char_u *fname = NULL; /* file name from command line */ mparm_T params; /* various parameters passed between * main() and other functions. */ -#ifdef STARTUPTIME - int i; -#endif - /* * Do any system-specific initialisations. These can NOT use IObuff or * NameBuff. Thus emsg2() cannot be called! @@ -126,30 +131,13 @@ main(argc, argv) /* Many variables are in "params" so that we can pass them to invoked * functions without a lot of arguments. "argc" and "argv" are also * copied, so that they can be changed. */ - vim_memset(¶ms, 0, sizeof(params)); - params.argc = argc; - params.argv = argv; - params.want_full_screen = TRUE; - params.use_debug_break_level = -1; - params.window_count = -1; - - + init_params(¶ms, argc, argv); #ifdef MEM_PROFILE atexit(vim_mem_profile_dump); #endif -#ifdef STARTUPTIME - for (i = 1; i < argc; ++i) { - if (STRICMP(argv[i], "--startuptime") == 0 && i + 1 < argc) { - time_fd = mch_fopen(argv[i + 1], "a"); - TIME_MSG("--- VIM STARTING ---"); - break; - } - } -#endif - starttime = time(NULL); - + init_startuptime(¶ms); (void)mb_init(); /* init mb_bytelen_tab[] to ones */ eval_init(); /* init global variables */ @@ -165,11 +153,7 @@ main(argc, argv) * Allocate space for the generic buffers (needed for set_init_1() and * EMSG2()). */ - if ((IObuff = alloc(IOSIZE)) == NULL - || (NameBuff = alloc(MAXPATHL)) == NULL) - mch_exit(0); - TIME_MSG("Allocated generic buffers"); - + allocate_generic_buffers(); #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) /* @@ -178,18 +162,15 @@ main(argc, argv) * work until set_init_1() has been called! */ init_locale(); - TIME_MSG("locale set"); #endif - /* * Check if we have an interactive window. * On the Amiga: If there is no window, we open one with a newcli command * (needed for :! to * work). mch_check_win() will also handle the -d or * -dev argument. */ - params.stdout_isatty = (mch_check_win(params.argc, params.argv) != FAIL); - TIME_MSG("window checked"); + check_and_set_isatty(¶ms); /* * Allocate the first window and buffer. @@ -227,7 +208,6 @@ main(argc, argv) * argument list "global_alist". */ command_line_scan(¶ms); - TIME_MSG("parsing arguments"); /* * On some systems, when we compile with the GUI, we always use it. On Mac @@ -235,23 +215,8 @@ main(argc, argv) * :gui. */ - if (GARGCOUNT > 0) { -#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) - /* - * Expand wildcards in file names. - */ - if (!params.literal) { - /* Temporarily add '(' and ')' to 'isfname'. These are valid - * filename characters but are excluded from 'isfname' to make - * "gf" work on a file name in parenthesis (e.g.: see vim.h). */ - do_cmdline_cmd((char_u *)":set isf+=(,)"); - alist_expand(NULL, 0); - do_cmdline_cmd((char_u *)":set isf&"); - } -#endif - fname = alist_name(&GARGLIST[0]); - } - + if (GARGCOUNT > 0) + fname = get_fname(¶ms); TIME_MSG("expanding arguments"); @@ -342,18 +307,10 @@ main(argc, argv) * Read all the plugin files. * Only when compiled with +eval, since most plugins need it. */ - if (p_lpl) { - source_runtime((char_u *)"plugin/**/*.vim", TRUE); - TIME_MSG("loading plugins"); - } + load_plugins(); /* Decide about window layout for diff mode after reading vimrc. */ - if (params.diff_mode && params.window_layout == 0) { - if (diffopt_horizontal()) - params.window_layout = WIN_HOR; /* use horizontal split */ - else - params.window_layout = WIN_VER; /* use vertical split */ - } + set_window_layout(¶ms); /* * Recovery mode without a file name: List swap files. @@ -401,17 +358,7 @@ main(argc, argv) * "-q errorfile": Load the error file now. * If the error file can't be read, exit before doing anything else. */ - if (params.edit_type == EDIT_QF) { - if (params.use_ef != NULL) - set_string_option_direct((char_u *)"ef", -1, - params.use_ef, OPT_FREE, SID_CARG); - vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef); - if (qf_init(NULL, p_ef, p_efm, TRUE, IObuff) < 0) { - out_char('\n'); - mch_exit(3); - } - TIME_MSG("reading errorfile"); - } + handle_quickfix(¶ms); /* * Start putting things on the screen. @@ -469,8 +416,7 @@ main(argc, argv) /* * Don't clear the screen when starting in Ex mode, unless using the GUI. */ - if (exmode_active - ) + if (exmode_active) must_redraw = CLEAR; else { screenclear(); /* clear screen */ @@ -534,21 +480,7 @@ main(argc, argv) * Need to jump to the tag before executing the '-c command'. * Makes "vim -c '/return' -t main" work. */ - if (params.tagname != NULL) { -#if defined(HAS_SWAP_EXISTS_ACTION) - swap_exists_did_quit = FALSE; -#endif - - vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname); - do_cmdline_cmd(IObuff); - TIME_MSG("jumping to tag"); - -#if defined(HAS_SWAP_EXISTS_ACTION) - /* If the user doesn't want to edit the file then we quit here. */ - if (swap_exists_did_quit) - getout(1); -#endif - } + handle_tag(params.tagname); /* Execute any "+", "-c" and "-S" arguments. */ if (params.n_commands > 0) @@ -942,6 +874,7 @@ static void init_locale() { vim_free(p); textdomain(VIMPACKAGE); } + TIME_MSG("locale set"); } #endif @@ -1500,6 +1433,160 @@ scripterror: vim_free(p); } } + TIME_MSG("parsing arguments"); +} + +/* + * Many variables are in "params" so that we can pass them to invoked + * functions without a lot of arguments. "argc" and "argv" are also + * copied, so that they can be changed. */ +static void init_params(paramp, argc, argv) + mparm_T *paramp; + int argc; + char **argv; +{ + vim_memset(paramp, 0, sizeof(*paramp)); + paramp->argc = argc; + paramp->argv = argv; + paramp->want_full_screen = TRUE; + paramp->use_debug_break_level = -1; + paramp->window_count = -1; +} + +/* + * Initialize global startuptime file if "--startuptime" passed as an argument. + */ +static void init_startuptime(paramp) + mparm_T *paramp; +{ +#ifdef STARTUPTIME + int i; + for (i = 1; i < paramp->argc; ++i) { + if (STRICMP(paramp->argv[i], "--startuptime") == 0 && i + 1 < paramp->argc) { + time_fd = mch_fopen(paramp->argv[i + 1], "a"); + TIME_MSG("--- VIM STARTING ---"); + break; + } + } +#endif + starttime = time(NULL); +} + +/* + * Allocate space for the generic buffers (needed for set_init_1() and + * EMSG2()). + */ +static void allocate_generic_buffers() +{ + if ((IObuff = alloc(IOSIZE)) == NULL + || (NameBuff = alloc(MAXPATHL)) == NULL) + mch_exit(0); + TIME_MSG("Allocated generic buffers"); +} + +/* + * Check if we have an interactive window. + * On the Amiga: If there is no window, we open one with a newcli command + * (needed for :! to * work). mch_check_win() will also handle the -d or + * -dev argument. + */ +static void check_and_set_isatty(paramp) + mparm_T *paramp; +{ + paramp->stdout_isatty = (mch_check_win(paramp->argc, paramp->argv) != FAIL); + TIME_MSG("window checked"); +} + +/* + * Get filename from command line, given that there is one. + */ +static char_u* get_fname(parmp) + mparm_T *parmp; +{ +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + /* + * Expand wildcards in file names. + */ + if (!parmp->literal) { + /* Temporarily add '(' and ')' to 'isfname'. These are valid + * filename characters but are excluded from 'isfname' to make + * "gf" work on a file name in parenthesis (e.g.: see vim.h). */ + do_cmdline_cmd((char_u *)":set isf+=(,)"); + alist_expand(NULL, 0); + do_cmdline_cmd((char_u *)":set isf&"); + } +#endif + return alist_name(&GARGLIST[0]); +} + +/* + * Decide about window layout for diff mode after reading vimrc. + */ +static void set_window_layout(paramp) + mparm_T *paramp; +{ + if (paramp->diff_mode && paramp->window_layout == 0) { + if (diffopt_horizontal()) + paramp->window_layout = WIN_HOR; /* use horizontal split */ + else + paramp->window_layout = WIN_VER; /* use vertical split */ + } +} + +/* + * Read all the plugin files. + * Only when compiled with +eval, since most plugins need it. + */ +static void load_plugins() +{ + if (p_lpl) { + source_runtime((char_u *)"plugin/**/*.vim", TRUE); + TIME_MSG("loading plugins"); + } +} + +/* + * "-q errorfile": Load the error file now. + * If the error file can't be read, exit before doing anything else. + */ +static void handle_quickfix(paramp) + mparm_T *paramp; +{ + if (paramp->edit_type == EDIT_QF) { + if (paramp->use_ef != NULL) + set_string_option_direct((char_u *)"ef", -1, + paramp->use_ef, OPT_FREE, SID_CARG); + vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef); + if (qf_init(NULL, p_ef, p_efm, TRUE, IObuff) < 0) { + out_char('\n'); + mch_exit(3); + } + TIME_MSG("reading errorfile"); + } +} + +/* + * Need to jump to the tag before executing the '-c command'. + * Makes "vim -c '/return' -t main" work. + */ +static void handle_tag(tagname) + char_u *tagname; +{ + if (tagname != NULL) { +#if defined(HAS_SWAP_EXISTS_ACTION) + swap_exists_did_quit = FALSE; +#endif + + vim_snprintf((char *)IObuff, IOSIZE, "ta %s", tagname); + do_cmdline_cmd(IObuff); + TIME_MSG("jumping to tag"); + +#if defined(HAS_SWAP_EXISTS_ACTION) + /* If the user doesn't want to edit the file then we quit here. */ + if (swap_exists_did_quit) + getout(1); +#endif + } } /* -- cgit From 3d171b6be215718353d7bf5c2b908841340e7904 Mon Sep 17 00:00:00 2001 From: Ashley Hewson Date: Sat, 22 Feb 2014 15:26:49 +0000 Subject: README.md: link to the Contributing wiki page --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7553eca3ba..7f28c49bef 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,10 @@ To build and run the tests: Join the community on IRC in #neovim on Freenode. +### Contributing + +...would be awesome! See [the wiki](https://github.com/neovim/neovim/wiki/Contributing) for more details. + ### License Vim itself is distributed under the terms of the Vim License. -- cgit From b4a1237f2a37ddc80f6a9fa8f108460c9f491f17 Mon Sep 17 00:00:00 2001 From: Kornel Lugosi Date: Sat, 22 Feb 2014 17:26:55 +0100 Subject: Remove trailing spaces from gitignore --- .gitignore | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index c0ce35dc48..b013dd8c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,14 +10,14 @@ build/ *.pyc src/po/vim.pot -src/po/*.ck +src/po/*.ck # Files generated by the tests -src/testdir/mbyte.vim -src/testdir/mzscheme.vim -src/testdir/lua.vim -src/testdir/small.vim -src/testdir/tiny.vim +src/testdir/mbyte.vim +src/testdir/mzscheme.vim +src/testdir/lua.vim +src/testdir/small.vim +src/testdir/tiny.vim src/testdir/test*.out src/testdir/test.log src/testdir/test.ok -- cgit From 2d32735bd9a120e0c429406d5281fd49df9c9379 Mon Sep 17 00:00:00 2001 From: Carl Martin Rosenberg Date: Fri, 21 Feb 2014 23:55:21 +0100 Subject: Added automake as a dependency when building on OS X. Otherwise build complaints of missing aclocal. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f28c49bef..a6420c4c67 100644 --- a/README.md +++ b/README.md @@ -183,16 +183,17 @@ For OsX: Via MacPorts: - sudo port install md5sha1sum cmake libtool + sudo port install md5sha1sum cmake libtool automake Via Homebrew: - brew install md5sha1sum cmake libtool + brew install md5sha1sum cmake libtool automake For Arch Linux: sudo pacman -S base-devel cmake ncurses + TODO: release the Dockerfile which has this in it -- cgit From 8d2fb5f8557c1dfe0f3fa398ca58bdb9441fa107 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sat, 22 Feb 2014 14:29:21 -0300 Subject: Add travis-ci configuration --- .travis.yml | 2 ++ README.md | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..bb82ce1e4c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +language: c +script: make cmake && make test diff --git a/README.md b/README.md index 7f28c49bef..7c605aa148 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # neovim ([bountysource fundraiser](https://www.bountysource.com/fundraisers/539-neovim-first-iteration)) +[![Build Status](https://travis-ci.org/neovim/neovim.png)](https://travis-ci.org/neovim/neovim) + ### Introduction Vim is a powerful text editor with a big community that is constantly growing. Even though the editor is about two decades old, people still extend and want to improve it, mostly using vimscript or one of the supported scripting languages. -- cgit From 87fdb40a03063b09811d4e3f303432f62b12e25d Mon Sep 17 00:00:00 2001 From: Sean Long Date: Fri, 21 Feb 2014 21:32:35 -0800 Subject: First pass on getting build working on FreeBSD. --- README.md | 4 ++++ scripts/common.sh | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 71beae8eba..291acaa653 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,10 @@ For Ubuntu 12.04: sudo apt-get install build-essential cmake libncurses5-dev +For FreeBSD 10: + + sudo pkg install cmake libtool sha + For OsX: * Install [Xcode](https://developer.apple.com/) diff --git a/scripts/common.sh b/scripts/common.sh index d7653c6aa1..8c5d8a61ab 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -1,3 +1,16 @@ +platform='unknown' +unameval=`uname` +if [ "$unameval" == 'Linux' ]; then + platform='linux' +elif [ "$unameval" == 'FreeBSD' ]; then + platform='freebsd' +fi + +sha1sumcmd='sha1sum' +if [ "$platform" == 'freebsd' ]; then + sha1sumcmd='shasum' +fi + pkgroot="$(pwd)" deps="$pkgroot/.deps" prefix="$deps/usr" @@ -17,7 +30,7 @@ download() { # download, untar and calculate sha1 sum in one pass (wget "$url" -O - | tee "$fifo" | \ (cd "$tgt"; tar --strip-components=1 -xvzf -)) & - sum=$(sha1sum < "$fifo" | cut -d ' ' -f1) + sum=$("$sha1sumcmd" < "$fifo" | cut -d ' ' -f1) rm -rf "$tmp_dir" if [ "$sum" != "$sha1" ]; then echo "SHA1 sum doesn't match, expected '$sha1' got '$sum'" -- cgit From 19296296dbdbbb23538cb58b3ec0b0c6f5036bb1 Mon Sep 17 00:00:00 2001 From: Mitchell Rosen Date: Sat, 22 Feb 2014 12:38:23 -0800 Subject: Clean up main.c:parse_command_name --- src/main.c | 61 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main.c b/src/main.c index 8eb0a605b3..d073fbe9a9 100644 --- a/src/main.c +++ b/src/main.c @@ -70,6 +70,8 @@ static int get_number_arg __ARGS((char_u *p, int *idx, int def)); static void init_locale __ARGS((void)); # endif static void parse_command_name __ARGS((mparm_T *parmp)); +static bool parse_char_i __ARGS((char_u **input, char val)); +static bool parse_string __ARGS((char_u **input, char* val, int len)); static void command_line_scan __ARGS((mparm_T *parmp)); static void init_params __ARGS((mparm_T *parmp, int argc, char **argv)); static void init_startuptime __ARGS((mparm_T *parmp)); @@ -91,7 +93,7 @@ static void main_start_gui __ARGS((void)); # if defined(HAS_SWAP_EXISTS_ACTION) static void check_swap_exists_action __ARGS((void)); # endif -#endif +#endif /* NO_VIM_MAIN */ /* @@ -899,39 +901,33 @@ static void parse_command_name(parmp) set_vim_var_string(VV_PROGNAME, initstr, -1); - if (TOLOWER_ASC(initstr[0]) == 'r') { + if (STRNICMP(initstr, "editor", 6) == 0) + return; + + if (parse_char_i(&initstr, 'r')) restricted = TRUE; - ++initstr; - } - /* Use evim mode for "evim" and "egvim", not for "editor". */ - if (TOLOWER_ASC(initstr[0]) == 'e' - && (TOLOWER_ASC(initstr[1]) == 'v' - || TOLOWER_ASC(initstr[1]) == 'g')) { + if (parse_char_i(&initstr, 'e')) parmp->evim_mode = TRUE; - ++initstr; - } /* "gvim" starts the GUI. Also accept "Gvim" for MS-Windows. */ - if (TOLOWER_ASC(initstr[0]) == 'g') { + if (parse_char_i(&initstr, 'g')) main_start_gui(); - } - if (STRNICMP(initstr, "view", 4) == 0) { + if (parse_string(&initstr, "view", 4)) { readonlymode = TRUE; curbuf->b_p_ro = TRUE; p_uc = 10000; /* don't update very often */ - initstr += 4; - } else if (STRNICMP(initstr, "vim", 3) == 0) - initstr += 3; + } else { + parse_string(&initstr, "vim", 3); /* consume "vim" if it's there */ + } /* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */ - if (STRICMP(initstr, "diff") == 0) { + if (parse_string(&initstr, "diff", 4)) parmp->diff_mode = TRUE; - } - if (STRNICMP(initstr, "ex", 2) == 0) { - if (STRNICMP(initstr + 2, "im", 2) == 0) + if (parse_string(&initstr, "ex", 2)) { + if (parse_string(&initstr, "im", 2)) exmode_active = EXMODE_VIM; else exmode_active = EXMODE_NORMAL; @@ -939,6 +935,29 @@ static void parse_command_name(parmp) } } +static bool parse_char_i(input, val) + char_u **input; + char val; +{ + if (TOLOWER_ASC(**input) == val) { + *input += 1; /* or (*input)++ WITH parens */ + return true; + } + return false; +} + +static bool parse_string(input, val, len) + char_u **input; + char *val; + int len; +{ + if (STRNICMP(*input, val, len) == 0) { + *input += len; + return true; + } + return false; +} + /* * Scan the command line arguments. */ @@ -2062,7 +2081,7 @@ static void main_start_gui() { mch_exit(2); } -#endif /* NO_VIM_MAIN */ +#endif /* NO_VIM_MAIN */ /* * Get an environment variable, and execute it as Ex commands. -- cgit From f32a091f0aa41ef4fcc1803e7af0633f081c6871 Mon Sep 17 00:00:00 2001 From: Marek Å uppa Date: Sat, 22 Feb 2014 13:07:39 -0800 Subject: Fixed travis image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 291acaa653..020ea7b555 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # neovim ([bountysource fundraiser](https://www.bountysource.com/fundraisers/539-neovim-first-iteration)) -[![Build Status](https://travis-ci.org/neovim/neovim.png)](https://travis-ci.org/neovim/neovim) +[![Build Status](https://travis-ci.org/neovim/neovim.png?branch=master)](https://travis-ci.org/neovim/neovim) ### Introduction -- cgit From cebac0fc59cda330b8e26a2bab2bd2c1fb09df13 Mon Sep 17 00:00:00 2001 From: Ashley Hewson Date: Sun, 23 Feb 2014 11:47:53 +0000 Subject: README.md: fix ubuntu/debian deps --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 020ea7b555..6ac5eee2e1 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,9 @@ and what is currently being worked on: ###Dependencies -For Ubuntu 12.04: +For Debian/Ubuntu: - sudo apt-get install build-essential cmake libncurses5-dev + sudo apt-get install libtool autoconf cmake libncurses5-dev g++ For FreeBSD 10: @@ -200,9 +200,6 @@ For Arch Linux: sudo pacman -S base-devel cmake ncurses -TODO: release the Dockerfile which has this in it - - ###Building -- cgit From da2906f28e1f5ee4cbff5fa2e0c0ec88777b838a Mon Sep 17 00:00:00 2001 From: jdiez17 Date: Sun, 23 Feb 2014 16:49:16 +0000 Subject: Added 'neovim' to the feature list, following discussion on #44 --- src/eval.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eval.c b/src/eval.c index bcf9c75730..28706c0d3d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -10734,6 +10734,7 @@ typval_T *rettv; #ifdef FEAT_XTERM_SAVE "xterm_save", #endif + "neovim", NULL }; -- cgit From 6241a499431ce56b012facd1971a380b73a15dab Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Sun, 23 Feb 2014 15:01:41 -0500 Subject: scripts/common.sh: remove a couple bashisms This allows the scripts to work on systems that don't have /bin/bash as /bin/sh--such as Debian. --- scripts/common.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/common.sh b/scripts/common.sh index 8c5d8a61ab..f42c000c6f 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -1,13 +1,13 @@ platform='unknown' unameval=`uname` -if [ "$unameval" == 'Linux' ]; then +if [ "$unameval" = 'Linux' ]; then platform='linux' -elif [ "$unameval" == 'FreeBSD' ]; then +elif [ "$unameval" = 'FreeBSD' ]; then platform='freebsd' fi sha1sumcmd='sha1sum' -if [ "$platform" == 'freebsd' ]; then +if [ "$platform" = 'freebsd' ]; then sha1sumcmd='shasum' fi -- cgit From eaa4f2b9ce99eeddef0b21c7ba3f913d36d038eb Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sun, 23 Feb 2014 14:08:33 -0700 Subject: Adding neovim formula for Homebrew --- neovim.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 neovim.rb diff --git a/neovim.rb b/neovim.rb new file mode 100644 index 0000000000..f8c7c1b087 --- /dev/null +++ b/neovim.rb @@ -0,0 +1,15 @@ +require 'formula' + +class Neovim < Formula + homepage 'http://neovim.org' + head 'https://github.com/neovim/neovim.git' + + depends_on 'md5sha1sum' + depends_on 'cmake' + depends_on 'libtool' + depends_on 'automake' + + def install + system "make", "PREFIX=#{prefix}", "cmake" + end +end -- cgit From 2acddd7cb26a46cccb5a40416bcdcdc491230175 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sun, 23 Feb 2014 14:28:07 -0700 Subject: Adding `make` step --- neovim.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/neovim.rb b/neovim.rb index f8c7c1b087..45e8b4018a 100644 --- a/neovim.rb +++ b/neovim.rb @@ -11,5 +11,6 @@ class Neovim < Formula def install system "make", "PREFIX=#{prefix}", "cmake" + system "make", "PREFIX=#{prefix}" end end -- cgit From 8614983e4ede98195db1586ef6ef3acb83310f3e Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sun, 23 Feb 2014 14:28:31 -0700 Subject: Updating README file to use Homebrew for local builds --- README.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6ac5eee2e1..3c1f1b523d 100644 --- a/README.md +++ b/README.md @@ -181,26 +181,16 @@ For Debian/Ubuntu: For FreeBSD 10: sudo pkg install cmake libtool sha - -For OsX: - -* Install [Xcode](https://developer.apple.com/) -* Install sha1sum - Via MacPorts: - - sudo port install md5sha1sum cmake libtool automake +For OsX: - Via Homebrew: +* Install [Xcode](https://developer.apple.com/) and [Homebrew][http://brew.sh] - brew install md5sha1sum cmake libtool automake For Arch Linux: sudo pacman -S base-devel cmake ncurses - - ###Building To generate the `Makefile`s: @@ -211,6 +201,10 @@ To build and run the tests: make test +Using Homebrew on Mac: + + brew install neovim/neovim/neovim + ### Community Join the community on IRC in #neovim on Freenode. -- cgit From d0f2cbeceb4d83e768731d8126571dbbd46e43c8 Mon Sep 17 00:00:00 2001 From: "David Z. Chen" Date: Sun, 23 Feb 2014 18:49:49 -0800 Subject: Issue #97 - Add documentation on installing root SSL certificates on OS X, which is required for retrieving the libuv archive before building. --- README.md | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6ac5eee2e1..e3ca041283 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ Travis will also be used for continuous integration, so pull requests will be au Here's a list of things that have been done so far: - Source tree was cleaned up, leaving only files necessary for compilation/testing of the core. -- Source files were processed with [unifdef](http://freecode.com/projects/unifdef) to remove tons of FEAT_* macros +- Source files were processed with [unifdef](http://freecode.com/projects/unifdef) to remove tons of `FEAT_*` macros - Files were processed with [uncrustify](http://uncrustify.sourceforge.net/) to normalize source code formatting. - The autotools build system was replaced by [cmake](http://www.cmake.org/) @@ -172,17 +172,17 @@ and what is currently being worked on: - Port all IO to libuv -###Dependencies +### Dependencies -For Debian/Ubuntu: +#### For Debian/Ubuntu: sudo apt-get install libtool autoconf cmake libncurses5-dev g++ -For FreeBSD 10: +#### For FreeBSD 10: sudo pkg install cmake libtool sha - -For OsX: + +#### For OS X: * Install [Xcode](https://developer.apple.com/) * Install sha1sum @@ -195,13 +195,24 @@ For OsX: brew install md5sha1sum cmake libtool automake -For Arch Linux: +If you run into wget certificate errors, you may be missing the root SSL +certificates or have not set them up correctly: - sudo pacman -S base-devel cmake ncurses + Via MacPorts: + + sudo port install curl-ca-bundle + echo CA_CERTIFICATE=/opt/local/share/curl/curl-ca-bundle.crt >> ~/.wgetrc + Via Homebrew: + + brew install curl-ca-bundle + echo CA_CERTIFICATE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt >> ~/.wgetrc +#### For Arch Linux: + + sudo pacman -S base-devel cmake ncurses -###Building +### Building To generate the `Makefile`s: -- cgit From a302c65dc65896776d6cb9e2c89a6ccc77ada530 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 10:01:50 +0000 Subject: Squashed 'third-party/libuv/' content from commit 3c40224 git-subtree-dir: third-party/libuv git-subtree-split: 3c4022464acd92607f21c6eef69330fb071d0400 --- .gitignore | 62 + .mailmap | 24 + AUTHORS | 114 + CONTRIBUTING.md | 177 + ChangeLog | 1012 ++++++ LICENSE | 42 + Makefile.am | 302 ++ Makefile.mingw | 77 + README.md | 143 + android-configure | 20 + autogen.sh | 46 + checksparse.sh | 231 ++ common.gypi | 208 ++ configure.ac | 55 + gyp_uv.py | 99 + include/pthread-fixes.h | 59 + include/stdint-msvc2008.h | 247 ++ include/tree.h | 768 ++++ include/uv-bsd.h | 34 + include/uv-darwin.h | 63 + include/uv-errno.h | 373 ++ include/uv-linux.h | 36 + include/uv-sunos.h | 44 + include/uv-unix.h | 329 ++ include/uv-win.h | 589 ++++ include/uv.h | 2135 ++++++++++++ libuv.pc.in | 11 + m4/.gitignore | 2 + m4/dtrace.m4 | 58 + samples/.gitignore | 22 + samples/socks5-proxy/.gitignore | 21 + samples/socks5-proxy/LICENSE | 53 + samples/socks5-proxy/Makefile | 46 + samples/socks5-proxy/build.gyp | 46 + samples/socks5-proxy/client.c | 737 ++++ samples/socks5-proxy/defs.h | 139 + samples/socks5-proxy/getopt.c | 131 + samples/socks5-proxy/main.c | 99 + samples/socks5-proxy/s5.c | 271 ++ samples/socks5-proxy/s5.h | 94 + samples/socks5-proxy/server.c | 241 ++ samples/socks5-proxy/util.c | 72 + src/fs-poll.c | 223 ++ src/inet.c | 294 ++ src/queue.h | 92 + src/unix/aix.c | 399 +++ src/unix/async.c | 290 ++ src/unix/atomic-ops.h | 60 + src/unix/core.c | 787 +++++ src/unix/darwin-proctitle.c | 203 ++ src/unix/darwin.c | 324 ++ src/unix/dl.c | 83 + src/unix/freebsd.c | 425 +++ src/unix/fs.c | 971 ++++++ src/unix/fsevents.c | 899 +++++ src/unix/getaddrinfo.c | 135 + src/unix/internal.h | 296 ++ src/unix/kqueue.c | 403 +++ src/unix/linux-core.c | 816 +++++ src/unix/linux-inotify.c | 257 ++ src/unix/linux-syscalls.c | 388 +++ src/unix/linux-syscalls.h | 151 + src/unix/loop-watcher.c | 63 + src/unix/loop.c | 163 + src/unix/netbsd.c | 367 ++ src/unix/openbsd.c | 388 +++ src/unix/pipe.c | 216 ++ src/unix/poll.c | 107 + src/unix/process.c | 517 +++ src/unix/proctitle.c | 102 + src/unix/pthread-fixes.c | 80 + src/unix/signal.c | 465 +++ src/unix/spinlock.h | 53 + src/unix/stream.c | 1511 ++++++++ src/unix/sunos.c | 734 ++++ src/unix/tcp.c | 312 ++ src/unix/thread.c | 464 +++ src/unix/threadpool.c | 280 ++ src/unix/timer.c | 153 + src/unix/tty.c | 184 + src/unix/udp.c | 595 ++++ src/unix/uv-dtrace.d | 25 + src/uv-common.c | 446 +++ src/uv-common.h | 187 + src/version.c | 63 + src/win/async.c | 99 + src/win/atomicops-inl.h | 56 + src/win/core.c | 362 ++ src/win/dl.c | 86 + src/win/error.c | 169 + src/win/fs-event.c | 527 +++ src/win/fs.c | 2043 +++++++++++ src/win/getaddrinfo.c | 344 ++ src/win/handle-inl.h | 179 + src/win/handle.c | 154 + src/win/internal.h | 379 ++ src/win/loop-watcher.c | 124 + src/win/pipe.c | 1747 ++++++++++ src/win/poll.c | 617 ++++ src/win/process-stdio.c | 510 +++ src/win/process.c | 1120 ++++++ src/win/req-inl.h | 224 ++ src/win/req.c | 25 + src/win/signal.c | 352 ++ src/win/stream-inl.h | 67 + src/win/stream.c | 253 ++ src/win/tcp.c | 1417 ++++++++ src/win/thread.c | 716 ++++ src/win/threadpool.c | 81 + src/win/timer.c | 254 ++ src/win/tty.c | 1873 ++++++++++ src/win/udp.c | 749 ++++ src/win/util.c | 990 ++++++ src/win/winapi.c | 159 + src/win/winapi.h | 4648 +++++++++++++++++++++++++ src/win/winsock.c | 560 +++ src/win/winsock.h | 171 + test/benchmark-async-pummel.c | 119 + test/benchmark-async.c | 141 + test/benchmark-fs-stat.c | 136 + test/benchmark-getaddrinfo.c | 91 + test/benchmark-list.h | 163 + test/benchmark-loop-count.c | 90 + test/benchmark-million-async.c | 112 + test/benchmark-million-timers.c | 85 + test/benchmark-multi-accept.c | 445 +++ test/benchmark-ping-pongs.c | 220 ++ test/benchmark-pound.c | 350 ++ test/benchmark-pump.c | 470 +++ test/benchmark-sizes.c | 45 + test/benchmark-spawn.c | 163 + test/benchmark-tcp-write-batch.c | 144 + test/benchmark-thread.c | 64 + test/benchmark-udp-pummel.c | 243 ++ test/blackhole-server.c | 121 + test/dns-server.c | 340 ++ test/echo-server.c | 384 ++ test/fixtures/empty_file | 0 test/fixtures/load_error.node | 1 + test/run-benchmarks.c | 64 + test/run-tests.c | 159 + test/runner-unix.c | 356 ++ test/runner-unix.h | 36 + test/runner-win.c | 369 ++ test/runner-win.h | 43 + test/runner.c | 455 +++ test/runner.h | 170 + test/task.h | 207 ++ test/test-active.c | 84 + test/test-async-null-cb.c | 55 + test/test-async.c | 136 + test/test-barrier.c | 98 + test/test-callback-order.c | 77 + test/test-callback-stack.c | 206 ++ test/test-close-fd.c | 77 + test/test-close-order.c | 80 + test/test-condvar.c | 173 + test/test-connection-fail.c | 152 + test/test-cwd-and-chdir.c | 64 + test/test-delayed-accept.c | 190 + test/test-dlerror.c | 58 + test/test-embed.c | 139 + test/test-emfile.c | 111 + test/test-error.c | 50 + test/test-fail-always.c | 29 + test/test-fs-event.c | 730 ++++ test/test-fs-poll.c | 146 + test/test-fs.c | 1955 +++++++++++ test/test-get-currentexe.c | 65 + test/test-get-loadavg.c | 36 + test/test-get-memory.c | 38 + test/test-getaddrinfo.c | 149 + test/test-getsockname.c | 358 ++ test/test-hrtime.c | 54 + test/test-idle.c | 99 + test/test-ip4-addr.c | 46 + test/test-ip6-addr.c | 99 + test/test-ipc-send-recv.c | 226 ++ test/test-ipc.c | 648 ++++ test/test-list.h | 537 +++ test/test-loop-alive.c | 68 + test/test-loop-handles.c | 337 ++ test/test-loop-stop.c | 73 + test/test-loop-time.c | 34 + test/test-multiple-listen.c | 109 + test/test-mutexes.c | 63 + test/test-osx-select.c | 82 + test/test-pass-always.c | 28 + test/test-ping-pong.c | 263 ++ test/test-pipe-bind-error.c | 136 + test/test-pipe-connect-error.c | 95 + test/test-pipe-server-close.c | 91 + test/test-platform-output.c | 103 + test/test-poll-close.c | 73 + test/test-poll.c | 581 ++++ test/test-process-title.c | 53 + test/test-ref.c | 443 +++ test/test-run-nowait.c | 46 + test/test-run-once.c | 49 + test/test-semaphore.c | 111 + test/test-shutdown-close.c | 108 + test/test-shutdown-eof.c | 182 + test/test-signal-multiple-loops.c | 289 ++ test/test-signal.c | 152 + test/test-spawn.c | 1051 ++++++ test/test-stdio-over-pipes.c | 255 ++ test/test-tcp-bind-error.c | 199 ++ test/test-tcp-bind6-error.c | 161 + test/test-tcp-close-accept.c | 183 + test/test-tcp-close-while-connecting.c | 82 + test/test-tcp-close.c | 136 + test/test-tcp-connect-error-after-write.c | 98 + test/test-tcp-connect-error.c | 73 + test/test-tcp-connect-timeout.c | 89 + test/test-tcp-connect6-error.c | 71 + test/test-tcp-flags.c | 52 + test/test-tcp-open.c | 182 + test/test-tcp-read-stop.c | 76 + test/test-tcp-shutdown-after-write.c | 138 + test/test-tcp-try-write.c | 144 + test/test-tcp-unexpected-read.c | 117 + test/test-tcp-write-to-half-open-connection.c | 141 + test/test-tcp-writealot.c | 176 + test/test-thread.c | 209 ++ test/test-threadpool-cancel.c | 311 ++ test/test-threadpool.c | 76 + test/test-timer-again.c | 140 + test/test-timer-from-check.c | 80 + test/test-timer.c | 294 ++ test/test-tty.c | 123 + test/test-udp-dgram-too-big.c | 91 + test/test-udp-ipv6.c | 166 + test/test-udp-multicast-join.c | 148 + test/test-udp-multicast-ttl.c | 94 + test/test-udp-open.c | 164 + test/test-udp-options.c | 88 + test/test-udp-send-and-recv.c | 211 ++ test/test-walk-handles.c | 78 + test/test-watcher-cross-stop.c | 101 + uv.gyp | 532 +++ vcbuild.bat | 144 + 241 files changed, 68152 insertions(+) create mode 100644 .gitignore create mode 100644 .mailmap create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 Makefile.am create mode 100644 Makefile.mingw create mode 100644 README.md create mode 100755 android-configure create mode 100755 autogen.sh create mode 100755 checksparse.sh create mode 100644 common.gypi create mode 100644 configure.ac create mode 100755 gyp_uv.py create mode 100644 include/pthread-fixes.h create mode 100644 include/stdint-msvc2008.h create mode 100644 include/tree.h create mode 100644 include/uv-bsd.h create mode 100644 include/uv-darwin.h create mode 100644 include/uv-errno.h create mode 100644 include/uv-linux.h create mode 100644 include/uv-sunos.h create mode 100644 include/uv-unix.h create mode 100644 include/uv-win.h create mode 100644 include/uv.h create mode 100644 libuv.pc.in create mode 100644 m4/.gitignore create mode 100644 m4/dtrace.m4 create mode 100644 samples/.gitignore create mode 100644 samples/socks5-proxy/.gitignore create mode 100644 samples/socks5-proxy/LICENSE create mode 100644 samples/socks5-proxy/Makefile create mode 100644 samples/socks5-proxy/build.gyp create mode 100644 samples/socks5-proxy/client.c create mode 100644 samples/socks5-proxy/defs.h create mode 100644 samples/socks5-proxy/getopt.c create mode 100644 samples/socks5-proxy/main.c create mode 100644 samples/socks5-proxy/s5.c create mode 100644 samples/socks5-proxy/s5.h create mode 100644 samples/socks5-proxy/server.c create mode 100644 samples/socks5-proxy/util.c create mode 100644 src/fs-poll.c create mode 100644 src/inet.c create mode 100644 src/queue.h create mode 100644 src/unix/aix.c create mode 100644 src/unix/async.c create mode 100644 src/unix/atomic-ops.h create mode 100644 src/unix/core.c create mode 100644 src/unix/darwin-proctitle.c create mode 100644 src/unix/darwin.c create mode 100644 src/unix/dl.c create mode 100644 src/unix/freebsd.c create mode 100644 src/unix/fs.c create mode 100644 src/unix/fsevents.c create mode 100644 src/unix/getaddrinfo.c create mode 100644 src/unix/internal.h create mode 100644 src/unix/kqueue.c create mode 100644 src/unix/linux-core.c create mode 100644 src/unix/linux-inotify.c create mode 100644 src/unix/linux-syscalls.c create mode 100644 src/unix/linux-syscalls.h create mode 100644 src/unix/loop-watcher.c create mode 100644 src/unix/loop.c create mode 100644 src/unix/netbsd.c create mode 100644 src/unix/openbsd.c create mode 100644 src/unix/pipe.c create mode 100644 src/unix/poll.c create mode 100644 src/unix/process.c create mode 100644 src/unix/proctitle.c create mode 100644 src/unix/pthread-fixes.c create mode 100644 src/unix/signal.c create mode 100644 src/unix/spinlock.h create mode 100644 src/unix/stream.c create mode 100644 src/unix/sunos.c create mode 100644 src/unix/tcp.c create mode 100644 src/unix/thread.c create mode 100644 src/unix/threadpool.c create mode 100644 src/unix/timer.c create mode 100644 src/unix/tty.c create mode 100644 src/unix/udp.c create mode 100644 src/unix/uv-dtrace.d create mode 100644 src/uv-common.c create mode 100644 src/uv-common.h create mode 100644 src/version.c create mode 100644 src/win/async.c create mode 100644 src/win/atomicops-inl.h create mode 100644 src/win/core.c create mode 100644 src/win/dl.c create mode 100644 src/win/error.c create mode 100644 src/win/fs-event.c create mode 100644 src/win/fs.c create mode 100644 src/win/getaddrinfo.c create mode 100644 src/win/handle-inl.h create mode 100644 src/win/handle.c create mode 100644 src/win/internal.h create mode 100644 src/win/loop-watcher.c create mode 100644 src/win/pipe.c create mode 100644 src/win/poll.c create mode 100644 src/win/process-stdio.c create mode 100644 src/win/process.c create mode 100644 src/win/req-inl.h create mode 100644 src/win/req.c create mode 100644 src/win/signal.c create mode 100644 src/win/stream-inl.h create mode 100644 src/win/stream.c create mode 100644 src/win/tcp.c create mode 100644 src/win/thread.c create mode 100644 src/win/threadpool.c create mode 100644 src/win/timer.c create mode 100644 src/win/tty.c create mode 100644 src/win/udp.c create mode 100644 src/win/util.c create mode 100644 src/win/winapi.c create mode 100644 src/win/winapi.h create mode 100644 src/win/winsock.c create mode 100644 src/win/winsock.h create mode 100644 test/benchmark-async-pummel.c create mode 100644 test/benchmark-async.c create mode 100644 test/benchmark-fs-stat.c create mode 100644 test/benchmark-getaddrinfo.c create mode 100644 test/benchmark-list.h create mode 100644 test/benchmark-loop-count.c create mode 100644 test/benchmark-million-async.c create mode 100644 test/benchmark-million-timers.c create mode 100644 test/benchmark-multi-accept.c create mode 100644 test/benchmark-ping-pongs.c create mode 100644 test/benchmark-pound.c create mode 100644 test/benchmark-pump.c create mode 100644 test/benchmark-sizes.c create mode 100644 test/benchmark-spawn.c create mode 100644 test/benchmark-tcp-write-batch.c create mode 100644 test/benchmark-thread.c create mode 100644 test/benchmark-udp-pummel.c create mode 100644 test/blackhole-server.c create mode 100644 test/dns-server.c create mode 100644 test/echo-server.c create mode 100644 test/fixtures/empty_file create mode 100644 test/fixtures/load_error.node create mode 100644 test/run-benchmarks.c create mode 100644 test/run-tests.c create mode 100644 test/runner-unix.c create mode 100644 test/runner-unix.h create mode 100644 test/runner-win.c create mode 100644 test/runner-win.h create mode 100644 test/runner.c create mode 100644 test/runner.h create mode 100644 test/task.h create mode 100644 test/test-active.c create mode 100644 test/test-async-null-cb.c create mode 100644 test/test-async.c create mode 100644 test/test-barrier.c create mode 100644 test/test-callback-order.c create mode 100644 test/test-callback-stack.c create mode 100644 test/test-close-fd.c create mode 100644 test/test-close-order.c create mode 100644 test/test-condvar.c create mode 100644 test/test-connection-fail.c create mode 100644 test/test-cwd-and-chdir.c create mode 100644 test/test-delayed-accept.c create mode 100644 test/test-dlerror.c create mode 100644 test/test-embed.c create mode 100644 test/test-emfile.c create mode 100644 test/test-error.c create mode 100644 test/test-fail-always.c create mode 100644 test/test-fs-event.c create mode 100644 test/test-fs-poll.c create mode 100644 test/test-fs.c create mode 100644 test/test-get-currentexe.c create mode 100644 test/test-get-loadavg.c create mode 100644 test/test-get-memory.c create mode 100644 test/test-getaddrinfo.c create mode 100644 test/test-getsockname.c create mode 100644 test/test-hrtime.c create mode 100644 test/test-idle.c create mode 100644 test/test-ip4-addr.c create mode 100644 test/test-ip6-addr.c create mode 100644 test/test-ipc-send-recv.c create mode 100644 test/test-ipc.c create mode 100644 test/test-list.h create mode 100644 test/test-loop-alive.c create mode 100644 test/test-loop-handles.c create mode 100644 test/test-loop-stop.c create mode 100644 test/test-loop-time.c create mode 100644 test/test-multiple-listen.c create mode 100644 test/test-mutexes.c create mode 100644 test/test-osx-select.c create mode 100644 test/test-pass-always.c create mode 100644 test/test-ping-pong.c create mode 100644 test/test-pipe-bind-error.c create mode 100644 test/test-pipe-connect-error.c create mode 100644 test/test-pipe-server-close.c create mode 100644 test/test-platform-output.c create mode 100644 test/test-poll-close.c create mode 100644 test/test-poll.c create mode 100644 test/test-process-title.c create mode 100644 test/test-ref.c create mode 100644 test/test-run-nowait.c create mode 100644 test/test-run-once.c create mode 100644 test/test-semaphore.c create mode 100644 test/test-shutdown-close.c create mode 100644 test/test-shutdown-eof.c create mode 100644 test/test-signal-multiple-loops.c create mode 100644 test/test-signal.c create mode 100644 test/test-spawn.c create mode 100644 test/test-stdio-over-pipes.c create mode 100644 test/test-tcp-bind-error.c create mode 100644 test/test-tcp-bind6-error.c create mode 100644 test/test-tcp-close-accept.c create mode 100644 test/test-tcp-close-while-connecting.c create mode 100644 test/test-tcp-close.c create mode 100644 test/test-tcp-connect-error-after-write.c create mode 100644 test/test-tcp-connect-error.c create mode 100644 test/test-tcp-connect-timeout.c create mode 100644 test/test-tcp-connect6-error.c create mode 100644 test/test-tcp-flags.c create mode 100644 test/test-tcp-open.c create mode 100644 test/test-tcp-read-stop.c create mode 100644 test/test-tcp-shutdown-after-write.c create mode 100644 test/test-tcp-try-write.c create mode 100644 test/test-tcp-unexpected-read.c create mode 100644 test/test-tcp-write-to-half-open-connection.c create mode 100644 test/test-tcp-writealot.c create mode 100644 test/test-thread.c create mode 100644 test/test-threadpool-cancel.c create mode 100644 test/test-threadpool.c create mode 100644 test/test-timer-again.c create mode 100644 test/test-timer-from-check.c create mode 100644 test/test-timer.c create mode 100644 test/test-tty.c create mode 100644 test/test-udp-dgram-too-big.c create mode 100644 test/test-udp-ipv6.c create mode 100644 test/test-udp-multicast-join.c create mode 100644 test/test-udp-multicast-ttl.c create mode 100644 test/test-udp-open.c create mode 100644 test/test-udp-options.c create mode 100644 test/test-udp-send-and-recv.c create mode 100644 test/test-walk-handles.c create mode 100644 test/test-watcher-cross-stop.c create mode 100644 uv.gyp create mode 100644 vcbuild.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..d11c90bbf0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +*.swp +*.[oa] +*.l[oa] +*.opensdf +*.orig +*.pyc +*.sdf +*.suo +core +vgcore.* +.buildstamp +.dirstamp +.deps/ +/.libs/ +/aclocal.m4 +/ar-lib +/autom4te.cache/ +/compile +/config.guess +/config.log +/config.status +/config.sub +/configure +/depcomp +/install-sh +/libtool +/libuv.a +/libuv.dylib +/libuv.pc +/libuv.so +/ltmain.sh +/missing +/test-driver +Makefile +Makefile.in + +# Generated by dtrace(1) when doing an in-tree build. +/include/uv-dtrace.h + +# Generated by gyp for android +*.target.mk + +/out/ +/build/gyp + +/run-tests +/run-tests.exe +/run-tests.dSYM +/run-benchmarks +/run-benchmarks.exe +/run-benchmarks.dSYM + +*.sln +*.vcproj +*.vcxproj +*.vcxproj.filters +*.vcxproj.user +_UpgradeReport_Files/ +UpgradeLog*.XML +Debug +Release +ipch diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..0f1d843ce8 --- /dev/null +++ b/.mailmap @@ -0,0 +1,24 @@ +Alan Gutierrez +Andrius Bentkus +Bert Belder +Bert Belder +Brandon Philips +Brian White +Brian White +Christoph Iserlohn +Frank Denis +Isaac Z. Schlueter +Keno Fischer +Keno Fischer +Maciej MaÅ‚ecki +Marc Schlaich +Robert Mustacchi +Ryan Dahl +Ryan Emery +San-Tai Hsu +Saúl Ibarra Corretgé +Shigeki Ohtsu +Timothy J. Fontaine +Yasuhiro Matsumoto +Yazhong Liu +Yuki Okumura diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..6633f0651e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,114 @@ +# Authors ordered by first contribution. +Ryan Dahl +Bert Belder +Josh Roesslein +Alan Gutierrez +Joshua Peek +Igor Zinkovsky +San-Tai Hsu +Ben Noordhuis +Henry Rawas +Robert Mustacchi +Matt Stevens +Paul Querna +Shigeki Ohtsu +Tom Hughes +Peter Bright +Jeroen Janssen +Andrea Lattuada +Augusto Henrique Hentz +Clifford Heath +Jorge Chamorro Bieling +Luis Lavena +Matthew Sporleder +Erick Tryzelaar +Isaac Z. Schlueter +Pieter Noordhuis +Marek Jelen +Fedor Indutny +Saúl Ibarra Corretgé +Felix Geisendörfer +Yuki Okumura +Roman Shtylman +Frank Denis +Carter Allen +Tj Holowaychuk +Shimon Doodkin +Ryan Emery +Bruce Mitchener +Maciej MaÅ‚ecki +Yasuhiro Matsumoto +Daisuke Murase +Paddy Byers +Dan VerWeire +Brandon Benvie +Brandon Philips +Nathan Rajlich +Charlie McConnell +Vladimir Dronnikov +Aaron Bieber +Bulat Shakirzyanov +Brian White +Erik Dubbelboer +Keno Fischer +Ira Cooper +Andrius Bentkus +Iñaki Baz Castillo +Mark Cavage +George Yohng +Xidorn Quan +Roman Neuhauser +Shuhei Tanuma +Bryan Cantrill +Trond Norbye +Tim Holy +Prancesco Pertugio +Leonard Hecker +Andrew Paprocki +Luigi Grilli +Shannen Saez +Artur Adib +Hiroaki Nakamura +Ting-Yu Lin +Stephen Gallagher +Shane Holloway +Andrew Shaffer +Vlad Tudose +Ben Leslie +Tim Bradshaw +Timothy J. Fontaine +Marc Schlaich +Brian Mazza +Elliot Saba +Ben Kelly +Kristian Evensen +Nils Maier +Nicholas Vavilov +Miroslav BajtoÅ¡ +Sean Silva +Wynn Wilkes +Linus MÃ¥rtensson +Andrei Sedoi +Navaneeth Kedaram Nambiathan +Alex Crichton +Brent Cook +Brian Kaisner +Luca Bruno +Reini Urban +Maks Naumov +Sean Farrell +Chris Bank +Geert Jansen +Christoph Iserlohn +Steven Kabbes +Alex Gaynor +huxingyi +Tenor Biel +Andrej Manduch +Joshua Neuheisel +Alexis Campailla +Yazhong Liu +Sam Roberts +River Tarnell +Nathan Sweet +Trevor Norris diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..960a9450ae --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,177 @@ +# CONTRIBUTING + +The libuv project welcomes new contributors. This document will guide you +through the process. + + +### FORK + +Fork the project [on GitHub](https://github.com/joyent/libuv) and check out +your copy. + +``` +$ git clone https://github.com/username/libuv.git +$ cd libuv +$ git remote add upstream https://github.com/joyent/libuv.git +``` + +Now decide if you want your feature or bug fix to go into the master branch +or the stable branch. As a rule of thumb, bug fixes go into the stable branch +while new features go into the master branch. + +The stable branch is effectively frozen; patches that change the libuv +API/ABI or affect the run-time behavior of applications get rejected. + +In case of doubt, open an issue in the [issue tracker][], post your question +to the [libuv mailing list], or contact one of project maintainers +(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][]. + +Especially do so if you plan to work on something big. Nothing is more +frustrating than seeing your hard work go to waste because your vision +does not align with that of a project maintainers. + + +### BRANCH + +Okay, so you have decided on the proper branch. Create a feature branch +and start hacking: + +``` +$ git checkout -b my-feature-branch -t origin/v0.10 +``` + +(Where v0.10 is the latest stable branch as of this writing.) + +### CODE + +Please adhere to libuv's code style. In general it follows the conventions from +the [Google C/C++ style guide]. Some of the key points, as well as some +additional guidelines, are enumerated below. + +* Code that is specific to unix-y platforms should be placed in `src/unix`, and + declarations go into `src/uv-unix.h`. + +* Source code that is Windows-specific goes into `src/win`, and related + publicly exported types, functions and macro declarations should generally + be declared in `include/uv-win.h`. + +* Names should be descriptive and concise. + +* All the symbols and types that libuv makes available publicly should be + prefixed with `uv_` (or `UV_` in case of macros). + +* Internal, non-static functions should be prefixed with `uv__`. + +* Use two spaces and no tabs. + +* Lines should be wrapped at 80 characters. + +* Ensure that lines have no trailing whitespace, and use unix-style (LF) line + endings. + +* Use C89-compliant syntax. In other words, variables can only be declared at + the top of a scope (function, if/for/while-block). + +* When writing comments, use properly constructed sentences, including + punctuation. + +* When documenting APIs and/or source code, don't make assumptions or make + implications about race, gender, religion, political orientation or anything + else that isn't relevant to the project. + +* Remember that source code usually gets written once and read often: ensure + the reader doesn't have to make guesses. Make sure that the purpose and inner + logic are either obvious to a reasonably skilled professional, or add a + comment that explains it. + + +### COMMIT + +Make sure git knows your name and email address: + +``` +$ git config --global user.name "J. Random User" +$ git config --global user.email "j.random.user@example.com" +``` + +Writing good commit logs is important. A commit log should describe what +changed and why. Follow these guidelines when writing one: + +1. The first line should be 50 characters or less and contain a short + description of the change prefixed with the name of the changed + subsystem (e.g. "net: add localAddress and localPort to Socket"). +2. Keep the second line blank. +3. Wrap all other lines at 72 columns. + +A good commit log looks like this: + +``` +subsystem: explaining the commit in one line + +Body of commit message is a few lines of text, explaining things +in more detail, possibly giving some background about the issue +being fixed, etc etc. + +The body of the commit message can be several paragraphs, and +please do proper word-wrap and keep columns shorter than about +72 characters or so. That way `git log` will show things +nicely even when it is indented. +``` + +The header line should be meaningful; it is what other people see when they +run `git shortlog` or `git log --oneline`. + +Check the output of `git log --oneline files_that_you_changed` to find out +what subsystem (or subsystems) your changes touch. + + +### REBASE + +Use `git rebase` (not `git merge`) to sync your work from time to time. + +``` +$ git fetch upstream +$ git rebase upstream/v0.10 # or upstream/master +``` + + +### TEST + +Bug fixes and features should come with tests. Add your tests in the +`test/` directory. Tests also need to be registered in `test/test-list.h`. +Look at other tests to see how they should be structured (license boilerplate, +the way entry points are declared, etc.). + +``` +$ make test +``` + +Make sure that there are no test regressions. + +### PUSH + +``` +$ git push origin my-feature-branch +``` + +Go to https://github.com/username/libuv and select your feature branch. Click +the 'Pull Request' button and fill out the form. + +Pull requests are usually reviewed within a few days. If there are comments +to address, apply your changes in a separate commit and push that to your +feature branch. Post a comment in the pull request afterwards; GitHub does +not send out notifications when you add commits. + + +### CONTRIBUTOR LICENSE AGREEMENT + +The current state of affairs is that, in order to get a patch accepted, you need +to sign Node.js's [contributor license agreement][]. You only need to do that +once. + + +[issue tracker]: https://github.com/joyent/libuv/issues +[libuv mailing list]: http://groups.google.com/group/libuv +[IRC]: http://webchat.freelibuv.net/?channels=libuv +[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[contributor license agreement]: http://nodejs.org/cla.html diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..ad3cbb504c --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1012 @@ +2014.01.30, Version 0.11.19 (Unstable) + +Changes since version 0.11.18: + +* linux: move sscanf() out of the assert() (Trevor Norris) + +* linux: fix C99/C++ comment (Fedor Indutny) + + +2014.01.23, Version 0.11.18 (Unstable), d47962e9d93d4a55a9984623feaf546406c9cdbb + +Changes since version 0.11.17: + +* osx: Fix a possible segfault in uv__io_poll (Alex Crichton) + +* windows: improved handling of invalid FDs (Alexis Campailla) + +* doc: adding ARCHS flag to OS X build command (Nathan Sweet) + +* tcp: reveal bind-time errors before listen (Alexis Campailla) + +* tcp: uv_tcp_dualstack() (Fedor Indutny) + +* linux: relax assumption on /proc/stat parsing (Luca Bruno) + +* openbsd: fix obvious bug in uv_cpu_info (Fedor Indutny) + +* process: close stdio after dup2'ing it (Fedor Indutny) + +* linux: move sscanf() out of the assert() (Trevor Norris) + + +2014.01.23, Version 0.10.23 (Stable), dbd218e699fec8be311d85e4788be9e28ae884f8 + +Changes since version 0.10.22: + +* linux: relax assumption on /proc/stat parsing (Luca Bruno) + +* openbsd: fix obvious bug in uv_cpu_info (Fedor Indutny) + +* process: close stdio after dup2'ing it (Fedor Indutny) + + +2014.01.08, Version 0.10.22 (Stable), f526c90eeff271d9323a9107b9a64a4671fd3103 + +Changes since version 0.10.21: + +* windows: avoid assertion failure when pipe server is closed (Bert Belder) + + +2013.12.32, Version 0.11.17 (Unstable), 589c224d4c2e79fec65db01d361948f1e4976858 + +Changes since version 0.11.16: + +* stream: allow multiple buffers for uv_try_write (Fedor Indutny) + +* unix: fix a possible memory leak in uv_fs_readdir (Alex Crichton) + +* unix, windows: add uv_loop_alive() function (Sam Roberts) + +* windows: avoid assertion failure when pipe server is closed (Bert Belder) + +* osx: Fix a possible segfault in uv__io_poll (Alex Crichton) + +* stream: fix uv__stream_osx_select (Fedor Indutny) + + +2013.12.14, Version 0.11.16 (Unstable), ae0ed8c49d0d313c935c22077511148b6e8408a4 + +Changes since version 0.11.15: + +* fsevents: remove kFSEventStreamCreateFlagNoDefer polyfill (ci-innoq) + +* libuv: add more getaddrinfo errors (Steven Kabbes) + +* unix: fix accept() EMFILE error handling (Ben Noordhuis) + +* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis) + +* fsevents: fix subfolder check (Fedor Indutny) + +* fsevents: fix invalid memory access (huxingyi) + +* windows/timer: fix uv_hrtime discontinuity (Bert Belder) + +* unix: fix various memory leaks and undef behavior (Fedor Indutny) + +* unix, windows: always update loop time (Saúl Ibarra Corretgé) + +* windows: translate system errors in uv_spawn (Alexis Campailla) + +* windows: uv_spawn code refactor (Alexis Campailla) + +* unix, windows: detect errors in uv_ip4/6_addr (Yorkie) + +* stream: introduce uv_try_write(...) (Fedor Indutny) + + +2013.12.13, Version 0.10.20 (Stable), 04141464dd0fba90ace9aa6f7003ce139b888a40 + +Changes since version 0.10.19: + +* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis) + +* fs-event: fix invalid memory access (huxingyi) + + +2013.11.21, Version 0.11.15 (Unstable), bfe645ed7e99ca5670d9279ad472b604c129d2e5 + +Changes since version 0.11.14: + +* fsevents: report errors to user (Fedor Indutny) + +* include: UV_FS_EVENT_RECURSIVE is a flag (Fedor Indutny) + +* linux: use CLOCK_MONOTONIC_COARSE if available (Ben Noordhuis) + +* build: make systemtap probes work with gyp build (Ben Noordhuis) + +* unix: update events from pevents between polls (Fedor Indutny) + +* fsevents: support japaneese characters in path (Chris Bank) + +* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis) + +* queue: strengthen type checks (Ben Noordhuis) + +* include: remove uv_strlcat() and uv_strlcpy() (Ben Noordhuis) + +* build: fix windows smp build with gyp (Geert Jansen) + +* unix: return exec errors from uv_spawn, not async (Alex Crichton) + +* fsevents: use native character encoding file paths (Ben Noordhuis) + +* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis) + +* windows: use _snwprintf(), not swprintf() (Ben Noordhuis) + +* fsevents: use FlagNoDefer for FSEventStreamCreate (Fedor Indutny) + +* unix: fix reopened fd bug (Fedor Indutny) + +* core: fix fake watcher list and count preservation (Fedor Indutny) + +* unix: set close-on-exec flag on received fds (Ben Noordhuis) + +* netbsd, openbsd: enable futimes() wrapper (Ben Noordhuis) + +* unix: nicer error message when kqueue() fails (Ben Noordhuis) + +* samples: add socks5 proxy sample application (Ben Noordhuis) + + +2013.11.13, Version 0.10.19 (Stable), 33959f7524090b8d2c6c41e2400ca77e31755059 + +Changes since version 0.10.18: + +* darwin: avoid calling GetCurrentProcess (Fedor Indutny) + +* unix: update events from pevents between polls (Fedor Indutny) + +* fsevents: support japaneese characters in path (Chris Bank) + +* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis) + +* build: fix windows smp build with gyp (Geert Jansen) + +* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis) + +* unix: fix reopened fd bug (Fedor Indutny) + +* core: fix fake watcher list and count preservation (Fedor Indutny) + + +2013.10.30, Version 0.11.14 (Unstable), d7a6482f45c1b4eb4a853dbe1a9ce8090a35633a + +Changes since version 0.11.13: + +* darwin: create fsevents thread on demand (Ben Noordhuis) + +* fsevents: FSEvents is most likely not thread-safe (Fedor Indutny) + +* fsevents: use shared FSEventStream (Fedor Indutny) + +* windows: make uv_fs_chmod() report errors correctly (Bert Belder) + +* windows: make uv_shutdown() for write-only pipes work (Bert Belder) + +* windows/fs: wrap multi-statement macros in do..while block (Bert Belder) + +* windows/fs: make uv_fs_open() report EINVAL correctly (Bert Belder) + +* windows/fs: handle _open_osfhandle() failure correctly (Bert Belder) + +* windows/fs: wrap multi-statement macros in do..while block (Bert Belder) + +* windows/fs: make uv_fs_open() report EINVAL correctly (Bert Belder) + +* windows/fs: handle _open_osfhandle() failure correctly (Bert Belder) + +* build: clarify instructions for Windows (Brian Kaisner) + +* build: remove GCC_WARN_ABOUT_MISSING_NEWLINE (Ben Noordhuis) + +* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis) + +* windows: run close callbacks after polling for i/o (Saúl Ibarra Corretgé) + +* include: clarify uv_tcp_bind() behavior (Ben Noordhuis) + +* include: clean up includes in uv.h (Ben Noordhuis) + +* include: remove UV_IO_PRIVATE_FIELDS macro (Ben Noordhuis) + +* include: fix typo in comment in uv.h (Ben Noordhuis) + +* include: update uv_is_active() documentation (Ben Noordhuis) + +* include: make uv_process_options_t.cwd const (Ben Noordhuis) + +* unix: wrap long lines at 80 columns (Ben Noordhuis) + +* unix, windows: make uv_is_*() always return 0 or 1 (Ben Noordhuis) + +* bench: measure total/init/dispatch/cleanup times (Ben Noordhuis) + +* build: use -pthread on sunos (Timothy J. Fontaine) + +* windows: remove duplicate check in stream.c (Ben Noordhuis) + +* unix: sanity-check fds before closing (Ben Noordhuis) + +* unix: remove uv__pipe_accept() (Ben Noordhuis) + +* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis) + +* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis) + +* unix: revert recent FSEvent changes (Ben Noordhuis) + +* fsevents: fix clever rescheduling (Fedor Indutny) + +* linux: ignore fractional time in uv_uptime() (Ben Noordhuis) + +* unix: fix SIGCHLD waitpid() race in process.c (Ben Noordhuis) + +* unix, windows: add uv_fs_event_start/stop functions (Saúl Ibarra Corretgé) + +* unix: fix non-synchronized access in signal.c (Ben Noordhuis) + +* unix: add atomic-ops.h (Ben Noordhuis) + +* unix: add spinlock.h (Ben Noordhuis) + +* unix: clean up uv_tty_set_mode() a little (Ben Noordhuis) + +* unix: make uv_tty_reset_mode() async signal-safe (Ben Noordhuis) + +* include: add E2BIG status code mapping (Ben Noordhuis) + +* windows: fix duplicate case build error (Ben Noordhuis) + +* windows: remove unneeded check (Saúl Ibarra Corretgé) + +* include: document pipe path truncation behavior (Ben Noordhuis) + +* fsevents: increase stack size for OSX 10.9 (Fedor Indutny) + +* windows: _snprintf expected wrong parameter type in string (Maks Naumov) + +* windows: "else" keyword is missing (Maks Naumov) + +* windows: incorrect check for SOCKET_ERROR (Maks Naumov) + +* windows: add stdlib.h to satisfy reference to abort (Sean Farrell) + +* build: fix check target for mingw (Sean Farrell) + +* unix: move uv_shutdown() assertion (Keno Fischer) + +* darwin: avoid calling GetCurrentProcess (Fedor Indutny) + + +2013.10.19, Version 0.10.18 (Stable), 9ec52963b585e822e87bdc5de28d6143aff0d2e5 + +Changes since version 0.10.17: + +* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis) + +* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis) + +* unix: revert recent FSEvent changes (Ben Noordhuis) + +* unix: fix non-synchronized access in signal.c (Ben Noordhuis) + + +2013.09.25, Version 0.10.17 (Stable), 9670e0a93540c2f0d86c84a375f2303383c11e7e + +Changes since version 0.10.16: + +* build: remove GCC_WARN_ABOUT_MISSING_NEWLINE (Ben Noordhuis) + +* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis) + + +2013.09.06, Version 0.10.16 (Stable), 2bce230d81f4853a23662cbeb26fe98010b1084b + +Changes since version 0.10.15: + +* windows: make uv_shutdown() for write-only pipes work (Bert Belder) + +* windows: make uv_fs_open() report EINVAL when invalid arguments are passed + (Bert Belder) + +* windows: make uv_fs_open() report _open_osfhandle() failure correctly (Bert + Belder) + +* windows: make uv_fs_chmod() report errors correctly (Bert Belder) + +* windows: wrap multi-statement macros in do..while block (Bert Belder) + + +2013.09.05, Version 0.11.13 (Unstable), f5b6db6c1d7f93d28281207fd47c3841c9a9792e + +Changes since version 0.11.12: + +* unix: define _GNU_SOURCE, exposes glibc-isms (Ben Noordhuis) + +* windows: check for nonconforming swprintf arguments (Brent Cook) + +* build: include internal headers in source list (Brent Cook) + +* include: merge uv_tcp_bind and uv_tcp_bind6 (Ben Noordhuis) + +* include: merge uv_tcp_connect and uv_tcp_connect6 (Ben Noordhuis) + +* include: merge uv_udp_bind and uv_udp_bind6 (Ben Noordhuis) + +* include: merge uv_udp_send and uv_udp_send6 (Ben Noordhuis) + + +2013.09.03, Version 0.11.12 (Unstable), 82d01d5f6780d178f5176a01425ec297583c0811 + +Changes since version 0.11.11: + +* test: fix epoll_wait() usage in test-embed.c (Ben Noordhuis) + +* include: uv_alloc_cb now takes uv_buf_t* (Ben Noordhuis) + +* include: uv_read{2}_cb now takes const uv_buf_t* (Ben Noordhuis) + +* include: uv_ip[46]_addr now takes sockaddr_in* (Ben Noordhuis) + +* include: uv_tcp_bind{6} now takes sockaddr_in* (Ben Noordhuis) + +* include: uv_tcp_connect{6} now takes sockaddr_in* (Ben Noordhuis) + +* include: uv_udp_recv_cb now takes const uv_buf_t* (Ben Noordhuis) + +* include: uv_udp_bind{6} now takes sockaddr_in* (Ben Noordhuis) + +* include: uv_udp_send{6} now takes sockaddr_in* (Ben Noordhuis) + +* include: uv_spawn takes const uv_process_options_t* (Ben Noordhuis) + +* include: make uv_write{2} const correct (Ben Noordhuis) + +* windows: fix flags assignment in uv_fs_readdir() (Ben Noordhuis) + +* windows: fix stray comments (Ben Noordhuis) + +* windows: remove unused is_path_dir() function (Ben Noordhuis) + + +2013.08.30, Version 0.11.11 (Unstable), ba876d53539ed0427c52039012419cd9374c6f0d + +Changes since version 0.11.10: + +* unix, windows: add thread-local storage API (Ben Noordhuis) + +* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis) + +* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis) + +* windows: make uv_shutdown() for write-only pipes work (Bert Belder) + +* include: update uv_udp_open() / uv_udp_bind() docs (Ben Noordhuis) + +* unix: req queue must be empty when destroying loop (Ben Noordhuis) + +* unix: move loop functions from core.c to loop.c (Ben Noordhuis) + +* darwin: remove CoreFoundation dependency (Ben Noordhuis) + +* windows: make autotools build system work with mingw (Keno Fischer) + +* windows: fix mingw build (Alex Crichton) + +* windows: tweak Makefile.mingw for easier usage (Alex Crichton) + +* build: remove _GNU_SOURCE macro definition (Ben Noordhuis) + + +2013.08.25, Version 0.11.10 (Unstable), 742dadcb7154cc7bb89c0c228a223b767a36cf0d + +* windows: Re-implement uv_fs_stat. The st_ctime field now contains the change + time, not the creation time, like on unix systems. st_dev, st_ino, st_blocks + and st_blksize are now also filled out. (Bert Belder) + +* linux: fix setsockopt(SO_REUSEPORT) error handling (Ben Noordhuis) + +* windows: report uv_process_t exit code correctly (Bert Belder) + +* windows: make uv_fs_chmod() report errors correctly (Bert Belder) + +* windows: make some more NT apis available for libuv's internal use (Bert + Belder) + +* windows: squelch some compiler warnings (Bert Belder) + + +2013.08.24, Version 0.11.9 (Unstable), a2d29b5b068cbac93dc16138fb30a74e2669daad + +Changes since version 0.11.8: + +* fsevents: share FSEventStream between multiple FS watchers, which removes a + limit on the maximum number of file watchers that can be created on OS X. + (Fedor Indutny) + +* process: the `exit_status` parameter for a uv_process_t's exit callback now + is an int64_t, and no longer an int. (Bert Belder) + +* process: make uv_spawn() return some types of errors immediately on windows, + instead of passing the error code the the exit callback. This brings it on + par with libuv's behavior on unix. (Bert Belder) + + +2013.08.24, Version 0.10.15 (Stable), 221078a8fdd9b853c6b557b3d9a5dd744b4fdd6b + +Changes since version 0.10.14: + +* fsevents: create FSEvents thread on demand (Ben Noordhuis) + +* fsevents: use a single thread for interacting with FSEvents, because it's not + thread-safe. (Fedor Indutny) + +* fsevents: share FSEventStream between multiple FS watchers, which removes a + limit on the maximum number of file watchers that can be created on OS X. + (Fedor Indutny) + + +2013.08.22, Version 0.11.8 (Unstable), a5260462db80ab0deab6b9e6a8991dd8f5a9a2f8 + +Changes since version 0.11.7: + +* unix: fix missing return value warning in stream.c (Ben Noordhuis) + +* build: serial-tests was added in automake v1.12 (Ben Noordhuis) + +* windows: fix uninitialized local variable warning (Ben Noordhuis) + +* windows: fix missing return value warning (Ben Noordhuis) + +* build: fix string comparisons in autogen.sh (Ben Noordhuis) + +* windows: move INLINE macro, remove UNUSED (Ben Noordhuis) + +* unix: clean up __attribute__((quux)) usage (Ben Noordhuis) + +* sunos: remove futimes() macro (Ben Noordhuis) + +* unix: fix uv__signal_unlock() prototype (Ben Noordhuis) + +* unix, windows: allow NULL async callback (Ben Noordhuis) + +* build: apply dtrace -G to all object files (Timothy J. Fontaine) + +* darwin: fix indentation in uv__hrtime() (Ben Noordhuis) + +* darwin: create fsevents thread on demand (Ben Noordhuis) + +* darwin: reduce fsevents thread stack size (Ben Noordhuis) + +* darwin: call pthread_setname_np() if available (Ben Noordhuis) + +* build: fix automake serial-tests check again (Ben Noordhuis) + +* unix: retry waitpid() on EINTR (Ben Noordhuis) + +* darwin: fix ios build error (Ben Noordhuis) + +* darwin: fix ios compiler warning (Ben Noordhuis) + +* test: simplify test-ip6-addr.c (Ben Noordhuis) + +* unix, windows: fix ipv6 link-local address parsing (Ben Noordhuis) + +* fsevents: FSEvents is most likely not thread-safe (Fedor Indutny) + +* windows: omit stdint.h, fix msvc 2008 build error (Ben Noordhuis) + + +2013.08.22, Version 0.10.14 (Stable), 15d64132151c18b26346afa892444b95e2addad0 + +Changes since version 0.10.13: + +* unix: retry waitpid() on EINTR (Ben Noordhuis) + + +2013.08.07, Version 0.11.7 (Unstable), 3cad361f8776f70941b39d65bd9426bcb1aa817b + +Changes since version 0.11.6: + +* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis) + +* unix, windows: remove unused variables (Brian White) + +* test: fix signed/unsigned comparison warnings (Ben Noordhuis) + +* build: dtrace shouldn't break out of tree builds (Timothy J. Fontaine) + +* unix, windows: don't read/recv if buf.len==0 (Ben Noordhuis) + +* build: add mingw makefile (Ben Noordhuis) + +* unix, windows: add MAC to uv_interface_addresses() (Brian White) + +* build: enable AM_INIT_AUTOMAKE([subdir-objects]) (Ben Noordhuis) + +* unix, windows: make buf arg to uv_fs_write const (Ben Noordhuis) + +* sunos: fix build breakage introduced in e3a657c (Ben Noordhuis) + +* aix: fix build breakage introduced in 3ee4d3f (Ben Noordhuis) + +* windows: fix mingw32 build, define JOB_OBJECT_XXX (Yasuhiro Matsumoto) + +* windows: fix mingw32 build, include limits.h (Yasuhiro Matsumoto) + +* test: replace sprintf() with snprintf() (Ben Noordhuis) + +* test: replace strcpy() with strncpy() (Ben Noordhuis) + +* openbsd: fix uv_ip6_addr() unused variable warnings (Ben Noordhuis) + +* openbsd: fix dlerror() const correctness warning (Ben Noordhuis) + +* openbsd: fix uv_fs_sendfile() unused variable warnings (Ben Noordhuis) + +* build: disable parallel automake tests (Ben Noordhuis) + +* test: add windows-only snprintf() function (Ben Noordhuis) + +* build: add automake serial-tests version check (Ben Noordhuis) + + +2013.07.26, Version 0.10.13 (Stable), 381312e1fe6fecbabc943ccd56f0e7d114b3d064 + +Changes since version 0.10.12: + +* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis) + + +2013.07.21, Version 0.11.6 (Unstable), 6645b93273e0553d23823c576573b82b129bf28c + +Changes since version 0.11.5: + +* test: open stdout fd in write-only mode (Ben Noordhuis) + +* windows: uv_spawn shouldn't reject reparse points (Bert Belder) + +* windows: use WSAGetLastError(), not errno (Ben Noordhuis) + +* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis) + +* test: fix signed/unsigned compiler warning (Ben Noordhuis) + +* test: add 'start timer from check handle' test (Ben Noordhuis) + +* build: `all` now builds static and dynamic lib (Ben Noordhuis) + +* unix, windows: add extra fields to uv_stat_t (Saúl Ibarra Corretgé) + +* build: add install target to the makefile (Navaneeth Kedaram Nambiathan) + +* build: switch to autotools (Ben Noordhuis) + +* build: use AM_PROG_AR conditionally (Ben Noordhuis) + +* test: fix fs_fstat test on sunos (Ben Noordhuis) + +* test: fix fs_chown when running as root (Ben Noordhuis) + +* test: fix spawn_setgid_fails and spawn_setuid_fails (Ben Noordhuis) + +* build: use AM_SILENT_RULES conditionally (Ben Noordhuis) + +* build: add DTrace detection for autotools (Timothy J. Fontaine) + +* linux,darwin,win: link-local IPv6 addresses (Miroslav BajtoÅ¡) + +* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis) + +* unix, windows: return error codes directly (Ben Noordhuis) + + +2013.07.10, Version 0.10.12 (Stable), 58a46221bba726746887a661a9f36fe9ff204209 + +Changes since version 0.10.11: + +* linux: add support for MIPS (Andrei Sedoi) + +* windows: uv_spawn shouldn't reject reparse points (Bert Belder) + +* windows: use WSAGetLastError(), not errno (Ben Noordhuis) + +* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis) + +* build: `all` now builds static and dynamic lib (Ben Noordhuis) + +* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis) + + +2013.06.27, Version 0.11.5 (Unstable), e3c63ff1627a14e96f54c1c62b0d68b446d8425b + +Changes since version 0.11.4: + +* build: remove CSTDFLAG, use only CFLAGS (Ben Noordhuis) + +* unix: support for android builds (Linus MÃ¥rtensson) + +* unix: avoid extra read, short-circuit on POLLHUP (Ben Noordhuis) + +* uv: support android libuv standalone build (Linus MÃ¥rtensson) + +* src: make queue.h c++ compatible (Ben Noordhuis) + +* unix: s/ngx-queue.h/queue.h/ in checksparse.sh (Ben Noordhuis) + +* unix: unconditionally stop handle on close (Ben Noordhuis) + +* freebsd: don't enable dtrace if it's not available (Brian White) + +* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine) + +* unix: remove overzealous assert (Ben Noordhuis) + +* unix: remove unused function uv_fatal_error() (Ben Noordhuis) + +* unix, windows: clean up uv_thread_create() (Ben Noordhuis) + +* queue: fix pointer truncation on LLP64 platforms (Bert Belder) + +* build: set OS=="android" for android builds (Linus MÃ¥rtensson) + +* windows: don't use uppercase in include filename (Ben Noordhuis) + +* stream: add an API to make streams do blocking writes (Henry Rawas) + +* windows: use WSAGetLastError(), not errno (Ben Noordhuis) + + +2013.06.13, Version 0.10.11 (Stable), c3b75406a66a10222a589cb173e8f469e9665c7e + +Changes since version 0.10.10: + +* unix: unconditionally stop handle on close (Ben Noordhuis) + +* freebsd: don't enable dtrace if it's not available (Brian White) + +* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine) + +* unix: remove overzealous assert (Ben Noordhuis) + +* unix: clear UV_STREAM_SHUTTING after shutdown() (Ben Noordhuis) + +* unix: fix busy loop, write if POLLERR or POLLHUP (Ben Noordhuis) + + +2013.06.05, Version 0.10.10 (Stable), 0d95a88bd35fce93863c57a460be613aea34d2c5 + +Changes since version 0.10.9: + +* include: document uv_update_time() and uv_now() (Ben Noordhuis) + +* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis) + +* linux: fix a memory leak in uv_cpu_info() error path (Ben Noordhuis) + +* linux: don't ignore out-of-memory errors in uv_cpu_info() (Ben Noordhuis) + +* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis) + +* test: fix a compilation problem in test-osx-select.c that was caused by the + use of c-style comments (Bert Belder) + +* darwin: use uv_fs_sendfile() use the sendfile api correctly (Wynn Wilkes) + + +2013.05.30, Version 0.11.4 (Unstable), e43e5b3d954a0989db5588aa110e1fe4fe6e0219 + +Changes since version 0.11.3: + +* windows: make uv_spawn not fail when the libuv embedding application is run + under external job control (Bert Belder) + +* darwin: assume CFRunLoopStop() isn't thread-safe, fixing a race condition + when stopping the 'stdin select hack' thread (Fedor Indutny) + +* win: fix UV_EALREADY not being reported correctly to the libuv user in some + cases (Bert Belder) + +* darwin: make the uv__cf_loop_runner and uv__cf_loop_cb functions static (Ben + Noordhuis) + +* darwin: task_info() cannot fail (Ben Noordhuis) + +* unix: add error mapping for ENETDOWN (Ben Noordhuis) + +* unix: implicitly signal write errors to the libuv user (Ben Noordhuis) + +* unix: fix assertion error on signal pipe overflow (Bert Belder) + +* unix: turn off POLLOUT after stream connect (Ben Noordhuis) + +* unix: fix stream refcounting buglet (Ben Noordhuis) + +* unix: remove assert statements that are no longer correct (Ben Noordhuis) + +* unix: appease warning about non-standard `inline` (Sean Silva) + +* unix: add uv__is_closing() macro (Ben Noordhuis) + +* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis) + +* include: document uv_update_time() and uv_now() (Ben Noordhuis) + +* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis) + +* linux: fix a memory leak in uv_cpu_info() error path (Ben Noordhuis) + +* linux: don't ignore out-of-memory errors in uv_cpu_info() (Ben Noordhuis) + +* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis) + +* test: fix a compilation problem in test-osx-select.c that was caused by the + use of c-style comments (Bert Belder) + +* darwin: use uv_fs_sendfile() use the sendfile api correctly (Wynn Wilkes) + +* windows: call idle handles on every loop iteration, something the unix + implementation already did (Bert Belder) + +* test: update the idle-starvation test to verify that idle handles are called + in every loop iteration (Bert Belder) + +* unix, windows: ensure that uv_run() in RUN_ONCE mode calls timers that expire + after blocking (Ben Noordhuis) + + +2013.05.29, Version 0.10.9 (Stable), a195f9ace23d92345baf57582678bfc3017e6632 + +Changes since version 0.10.8: + +* unix: fix stream refcounting buglet (Ben Noordhuis) + +* unix: remove erroneous asserts (Ben Noordhuis) + +* unix: add uv__is_closing() macro (Ben Noordhuis) + +* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis) + + +2013.05.25, Version 0.10.8 (Stable), 0f39be12926fe2d8766a9f025797a473003e6504 + +Changes since version 0.10.7: + +* windows: make uv_spawn not fail under job control (Bert Belder) + +* darwin: assume CFRunLoopStop() isn't thread-safe (Fedor Indutny) + +* win: fix UV_EALREADY incorrectly set (Bert Belder) + +* darwin: make two uv__cf_*() functions static (Ben Noordhuis) + +* darwin: task_info() cannot fail (Ben Noordhuis) + +* unix: add mapping for ENETDOWN (Ben Noordhuis) + +* unix: implicitly signal write errors to libuv user (Ben Noordhuis) + +* unix: fix assert on signal pipe overflow (Bert Belder) + +* unix: turn off POLLOUT after stream connect (Ben Noordhuis) + + +2013.05.16, Version 0.11.3 (Unstable), 0a48c05b5988aea84c605751900926fa25443b34 + +Changes since version 0.11.2: + +* unix: clean up uv_accept() (Ben Noordhuis) + +* unix: remove errno preserving code (Ben Noordhuis) + +* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis) + +* windows: kill child processes when the parent dies (Bert Belder) + +* build: set soname in shared library (Ben Noordhuis) + +* build: make `make test` link against .a again (Ben Noordhuis) + +* build: only set soname on shared object builds (Timothy J. Fontaine) + +* build: convert predefined $PLATFORM to lower case (Elliot Saba) + +* test: fix process_title failing on linux (Miroslav BajtoÅ¡) + +* test, sunos: disable process_title test (Miroslav BajtoÅ¡) + +* test: add error logging to tty unit test (Miroslav BajtoÅ¡) + + +2013.05.15, Version 0.10.7 (Stable), 028baaf0846b686a81e992cb2f2f5a9b8e841fcf + +Changes since version 0.10.6: + +* windows: kill child processes when the parent dies (Bert Belder) + + +2013.05.15, Version 0.10.6 (Stable), 11e6613e6260d95c8cf11bf89a2759c24649319a + +Changes since version 0.10.5: + +* stream: fix osx select hack (Fedor Indutny) + +* stream: fix small nit in select hack, add test (Fedor Indutny) + +* build: link with libkvm on openbsd (Ben Noordhuis) + +* stream: use harder sync restrictions for osx-hack (Fedor Indutny) + +* unix: fix EMFILE error handling (Ben Noordhuis) + +* darwin: fix unnecessary include headers (Daisuke Murase) + +* darwin: rename darwin-getproctitle.m (Ben Noordhuis) + +* build: convert predefined $PLATFORM to lower case (Elliot Saba) + +* build: set soname in shared library (Ben Noordhuis) + +* build: make `make test` link against .a again (Ben Noordhuis) + +* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis) + +* build: only set soname on shared object builds (Timothy J. Fontaine) + + +2013.05.11, Version 0.11.2 (Unstable), 3fba0bf65f091b91a9760530c05c6339c658d88b + +Changes since version 0.11.1: + +* darwin: look up file path with F_GETPATH (Ben Noordhuis) + +* unix, windows: add uv_has_ref() function (Saúl Ibarra Corretgé) + +* build: avoid double / in paths for dtrace (Timothy J. Fontaine) + +* unix: remove src/unix/cygwin.c (Ben Noordhuis) + +* windows: deal with the fact that GetTickCount might lag (Bert Belder) + +* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis) + +* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis) + + +2013.04.24, Version 0.10.5 (Stable), 6595a7732c52eb4f8e57c88655f72997a8567a67 + +Changes since version 0.10.4: + +* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis) + +* windows: make timers handle large timeouts (Miroslav BajtoÅ¡) + +* windows: remove superfluous assert statement (Bert Belder) + +* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis) + +* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis) + + +2013.04.12, Version 0.10.4 (Stable), 85827e26403ac6dfa331af8ec9916ea7e27bd833 + +Changes since version 0.10.3: + +* include: update uv_backend_fd() documentation (Ben Noordhuis) + +* unix: include uv.h in src/version.c (Ben Noordhuis) + +* unix: don't write more than IOV_MAX iovecs (Fedor Indutny) + +* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier) + +* build: gyp disable thin archives (Timothy J. Fontaine) + +* sunos: re-export entire library when static (Timothy J. Fontaine) + +* unix: dtrace probes for tick-start and tick-stop (Timothy J. Fontaine) + +* windows: fix memory leak in fs__sendfile (Shannen Saez) + +* windows: remove double initialization in uv_tty_init (Shannen Saez) + +* build: fix dtrace-enabled out of tree build (Ben Noordhuis) + +* build: squelch -Wdollar-in-identifier-extension warnings (Ben Noordhuis) + +* inet: snprintf returns int, not size_t (Brian White) + +* win: refactor uv_cpu_info (Bert Belder) + +* build: add support for Visual Studio 2012 (Nicholas Vavilov) + +* build: -Wno-dollar-in-identifier-extension is clang only (Ben Noordhuis) + + +2013.04.11, Version 0.11.1 (Unstable), 5c10e82ae0bc99eff86d4b9baff1f1aa0bf84c0a + +This is the first versioned release from the current unstable libuv branch. + +Changes since Node.js v0.11.0: + +* all platforms: nanosecond resolution support for uv_fs_[fl]stat (Timothy J. + Fontaine) + +* all platforms: add netmask to uv_interface_address (Ben Kelly) + +* unix: make sure the `status` parameter passed to the `uv_getaddrinfo` is 0 or + -1 (Ben Noordhuis) + +* unix: limit the number of iovecs written in a single `writev` syscall to + IOV_MAX (Fedor Indutny) + +* unix: add dtrace probes for tick-start and tick-stop (Timothy J. Fontaine) + +* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier) + +* windows: fix memory leak in fs__sendfile (Shannen Saez) + +* windows: fix edge case bugs in uv_cpu_info (Bert Belder) + +* include: no longer ship with / include ngx-queue.h (Ben Noordhuis) + +* include: remove UV_VERSION_* macros from uv.h (Ben Noordhuis) + +* documentation updates (Kristian Evensen, Ben Kelly, Ben Noordhuis) + +* build: fix dtrace-enabled builds (Ben Noordhuis, Timothy J. Fontaine) + +* build: gyp disable thin archives (Timothy J. Fontaine) + +* build: add support for Visual Studio 2012 (Nicholas Vavilov) + + +2013.03.28, Version 0.10.3 (Stable), 31ebe23973dd98fd8a24c042b606f37a794e99d0 + +Changes since version 0.10.2: + +* include: remove extraneous const from uv_version() (Ben Noordhuis) + +* doc: update README, replace `OS` by `PLATFORM` (Ben Noordhuis) + +* build: simplify .buildstamp rule (Ben Noordhuis) + +* build: disable -Wstrict-aliasing on darwin (Ben Noordhuis) + +* darwin: don't select(&exceptfds) in fallback path (Ben Noordhuis) + +* unix: don't clear flags after closing UDP handle (Saúl Ibarra Corretgé) + + +2013.03.25, Version 0.10.2 (Stable), 0f36a00568f3e7608f97f6c6cdb081f4800a50c9 + +This is the first officially versioned release of libuv. Starting now +libuv will make releases independently of Node.js. + +Changes since Node.js v0.10.0: + +* test: add tap output for windows (Timothy J. Fontaine) + +* unix: fix uv_tcp_simultaneous_accepts() logic (Ben Noordhuis) + +* include: bump UV_VERSION_MINOR (Ben Noordhuis) + +* unix: improve uv_guess_handle() implementation (Ben Noordhuis) + +* stream: run try_select only for pipes and ttys (Fedor Indutny) + +Changes since Node.js v0.10.1: + +* build: rename OS to PLATFORM (Ben Noordhuis) + +* unix: make uv_timer_init() initialize repeat (Brian Mazza) + +* unix: make timers handle large timeouts (Ben Noordhuis) + +* build: add OBJC makefile var (Ben Noordhuis) + +* Add `uv_version()` and `uv_version_string()` APIs (Bert Belder) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..8db13acf2c --- /dev/null +++ b/LICENSE @@ -0,0 +1,42 @@ +libuv is part of the Node project: http://nodejs.org/ +libuv may be distributed alone under Node's license: + +==== + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +==== + +This license applies to all parts of libuv that are not externally +maintained libraries. + +The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + + - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three + clause BSD license. + + - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile + Communications AB. Three clause BSD license. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..c1eae8cea0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,302 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ACLOCAL_AMFLAGS = -I m4 + +AM_CPPFLAGS = -I$(top_srcdir)/include \ + -I$(top_srcdir)/src + +include_HEADERS=include/uv.h include/uv-errno.h + +CLEANFILES = + +lib_LTLIBRARIES = libuv.la +libuv_la_CFLAGS = @CFLAGS@ +libuv_la_LDFLAGS = -no-undefined -version-info 11:0:0 +libuv_la_SOURCES = src/fs-poll.c \ + src/inet.c \ + src/queue.h \ + src/uv-common.c \ + src/uv-common.h \ + src/version.c + +if SUNOS +libuv_la_CFLAGS += -pthread +endif + +if WINNT + +include_HEADERS += include/uv-win.h include/tree.h +AM_CPPFLAGS += -I$(top_srcdir)/src/win \ + -DWIN32_LEAN_AND_MEAN \ + -D_WIN32_WINNT=0x0600 +LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 +libuv_la_SOURCES += src/win/async.c \ + src/win/atomicops-inl.h \ + src/win/core.c \ + src/win/dl.c \ + src/win/error.c \ + src/win/fs-event.c \ + src/win/fs.c \ + src/win/getaddrinfo.c \ + src/win/handle.c \ + src/win/handle-inl.h \ + src/win/internal.h \ + src/win/loop-watcher.c \ + src/win/pipe.c \ + src/win/poll.c \ + src/win/process-stdio.c \ + src/win/process.c \ + src/win/req.c \ + src/win/req-inl.h \ + src/win/signal.c \ + src/win/stream.c \ + src/win/stream-inl.h \ + src/win/tcp.c \ + src/win/thread.c \ + src/win/threadpool.c \ + src/win/timer.c \ + src/win/tty.c \ + src/win/udp.c \ + src/win/util.c \ + src/win/winapi.c \ + src/win/winapi.h \ + src/win/winsock.c \ + src/win/winsock.h + +else # WINNT + +include_HEADERS += include/uv-unix.h +AM_CPPFLAGS += -I$(top_srcdir)/src/unix +libuv_la_SOURCES += src/unix/async.c \ + src/unix/atomic-ops.h \ + src/unix/core.c \ + src/unix/dl.c \ + src/unix/fs.c \ + src/unix/getaddrinfo.c \ + src/unix/internal.h \ + src/unix/loop-watcher.c \ + src/unix/loop.c \ + src/unix/pipe.c \ + src/unix/poll.c \ + src/unix/process.c \ + src/unix/signal.c \ + src/unix/spinlock.h \ + src/unix/stream.c \ + src/unix/tcp.c \ + src/unix/thread.c \ + src/unix/threadpool.c \ + src/unix/timer.c \ + src/unix/tty.c \ + src/unix/udp.c + +endif # WINNT + +TESTS = test/run-tests +check_PROGRAMS = test/run-tests +test_run_tests_SOURCES = test/blackhole-server.c \ + test/dns-server.c \ + test/echo-server.c \ + test/run-tests.c \ + test/runner.c \ + test/runner.h \ + test/task.h \ + test/test-active.c \ + test/test-async.c \ + test/test-async-null-cb.c \ + test/test-barrier.c \ + test/test-callback-order.c \ + test/test-callback-stack.c \ + test/test-close-fd.c \ + test/test-close-order.c \ + test/test-condvar.c \ + test/test-connection-fail.c \ + test/test-cwd-and-chdir.c \ + test/test-delayed-accept.c \ + test/test-dlerror.c \ + test/test-embed.c \ + test/test-emfile.c \ + test/test-error.c \ + test/test-fail-always.c \ + test/test-fs-event.c \ + test/test-fs-poll.c \ + test/test-fs.c \ + test/test-get-currentexe.c \ + test/test-get-loadavg.c \ + test/test-get-memory.c \ + test/test-getaddrinfo.c \ + test/test-getsockname.c \ + test/test-hrtime.c \ + test/test-idle.c \ + test/test-ip4-addr.c \ + test/test-ip6-addr.c \ + test/test-ipc-send-recv.c \ + test/test-ipc.c \ + test/test-list.h \ + test/test-loop-handles.c \ + test/test-loop-alive.c \ + test/test-loop-stop.c \ + test/test-loop-time.c \ + test/test-multiple-listen.c \ + test/test-mutexes.c \ + test/test-osx-select.c \ + test/test-pass-always.c \ + test/test-ping-pong.c \ + test/test-pipe-bind-error.c \ + test/test-pipe-connect-error.c \ + test/test-pipe-server-close.c \ + test/test-platform-output.c \ + test/test-poll-close.c \ + test/test-poll.c \ + test/test-process-title.c \ + test/test-ref.c \ + test/test-run-nowait.c \ + test/test-run-once.c \ + test/test-semaphore.c \ + test/test-shutdown-close.c \ + test/test-shutdown-eof.c \ + test/test-signal-multiple-loops.c \ + test/test-signal.c \ + test/test-spawn.c \ + test/test-stdio-over-pipes.c \ + test/test-tcp-bind-error.c \ + test/test-tcp-bind6-error.c \ + test/test-tcp-close-accept.c \ + test/test-tcp-close-while-connecting.c \ + test/test-tcp-close.c \ + test/test-tcp-connect-error-after-write.c \ + test/test-tcp-connect-error.c \ + test/test-tcp-connect-timeout.c \ + test/test-tcp-connect6-error.c \ + test/test-tcp-flags.c \ + test/test-tcp-open.c \ + test/test-tcp-read-stop.c \ + test/test-tcp-shutdown-after-write.c \ + test/test-tcp-unexpected-read.c \ + test/test-tcp-write-to-half-open-connection.c \ + test/test-tcp-writealot.c \ + test/test-tcp-try-write.c \ + test/test-thread.c \ + test/test-threadpool-cancel.c \ + test/test-threadpool.c \ + test/test-timer-again.c \ + test/test-timer-from-check.c \ + test/test-timer.c \ + test/test-tty.c \ + test/test-udp-dgram-too-big.c \ + test/test-udp-ipv6.c \ + test/test-udp-multicast-join.c \ + test/test-udp-multicast-ttl.c \ + test/test-udp-open.c \ + test/test-udp-options.c \ + test/test-udp-send-and-recv.c \ + test/test-walk-handles.c \ + test/test-watcher-cross-stop.c +test_run_tests_LDADD = libuv.la + +if WINNT +test_run_tests_SOURCES += test/runner-win.c \ + test/runner-win.h +else +test_run_tests_SOURCES += test/runner-unix.c \ + test/runner-unix.h +endif + + + +if AIX +libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 +libuv_la_SOURCES += src/unix/aix.c +endif + +if DARWIN +include_HEADERS += include/uv-darwin.h +libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 +libuv_la_SOURCES += src/unix/darwin.c \ + src/unix/darwin-proctitle.c \ + src/unix/fsevents.c \ + src/unix/kqueue.c \ + src/unix/proctitle.c +endif + +if FREEBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +endif + +if LINUX +include_HEADERS += include/uv-linux.h +libuv_la_SOURCES += src/unix/linux-core.c \ + src/unix/linux-inotify.c \ + src/unix/linux-syscalls.c \ + src/unix/linux-syscalls.h \ + src/unix/proctitle.c +endif + +if NETBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c +endif + +if OPENBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c +endif + +if SUNOS +include_HEADERS += include/uv-sunos.h +libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +libuv_la_SOURCES += src/unix/sunos.c +endif + +if HAVE_DTRACE +BUILT_SOURCES = include/uv-dtrace.h +CLEANFILES += include/uv-dtrace.h +endif + +if DTRACE_NEEDS_OBJECTS +libuv_la_SOURCES += src/unix/uv-dtrace.d +libuv_la_DEPENDENCIES = src/unix/uv-dtrace.o +libuv_la_LIBADD = uv-dtrace.lo +CLEANFILES += src/unix/uv-dtrace.o src/unix/uv-dtrace.lo +endif + +if HAVE_PKG_CONFIG +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = @PACKAGE_NAME@.pc +endif + +if HAVE_DTRACE +include/uv-dtrace.h: src/unix/uv-dtrace.d + $(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -h -xnolibs -s $< -o $(top_srcdir)/$@ +endif + +if DTRACE_NEEDS_OBJECTS +SUFFIXES = .d + +src/unix/uv-dtrace.o: src/unix/uv-dtrace.d ${libuv_la_OBJECTS} + +# It's ok to specify the output here, because we have 1 .d file, and we process +# every created .o, most projects don't need to include more than one .d +.d.o: + $(AM_V_GEN)$(DTRACE) $(DTRACEFLAGS) -G -o $(top_builddir)/uv-dtrace.o -s $< \ + `find ${top_builddir}/src -name "*.o"` + $(AM_V_GEN)printf %s\\n \ + '# ${top_builddir}/uv-dtrace.lo - a libtool object file' \ + '# Generated by libtool (GNU libtool) 2.4' \ + '# libtool wants a .lo not a .o' \ + "pic_object='uv-dtrace.o'" \ + "non_pic_object='uv-dtrace.o'" \ + > ${top_builddir}/uv-dtrace.lo +endif diff --git a/Makefile.mingw b/Makefile.mingw new file mode 100644 index 0000000000..28a1e274d5 --- /dev/null +++ b/Makefile.mingw @@ -0,0 +1,77 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +CC = gcc + +CFLAGS += -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -Iinclude \ + -Isrc \ + -Isrc/win \ + -DWIN32_LEAN_AND_MEAN \ + -D_WIN32_WINNT=0x0600 + +INCLUDES = include/stdint-msvc2008.h \ + include/tree.h \ + include/uv-errno.h \ + include/uv-win.h \ + include/uv.h \ + src/queue.h \ + src/uv-common.h \ + src/win/atomicops-inl.h \ + src/win/handle-inl.h \ + src/win/internal.h \ + src/win/req-inl.h \ + src/win/stream-inl.h \ + src/win/winapi.h \ + src/win/winsock.h + +OBJS = src/fs-poll.o \ + src/inet.o \ + src/uv-common.o \ + src/version.o \ + src/win/async.o \ + src/win/core.o \ + src/win/dl.o \ + src/win/error.o \ + src/win/fs-event.o \ + src/win/fs.o \ + src/win/getaddrinfo.o \ + src/win/handle.o \ + src/win/loop-watcher.o \ + src/win/pipe.o \ + src/win/poll.o \ + src/win/process-stdio.o \ + src/win/process.o \ + src/win/req.o \ + src/win/signal.o \ + src/win/stream.o \ + src/win/tcp.o \ + src/win/thread.o \ + src/win/threadpool.o \ + src/win/timer.o \ + src/win/tty.o \ + src/win/udp.o \ + src/win/util.o \ + src/win/winapi.o \ + src/win/winsock.o + +all: libuv.a + +libuv.a: $(OBJS) + $(AR) crs $@ $^ + +# FIXME(bnoordhuis) Don't rebuild everything when a source file changes. +$(OBJS): $(OBJS:.o=.c) $(INCLUDES) diff --git a/README.md b/README.md new file mode 100644 index 0000000000..5704c39e27 --- /dev/null +++ b/README.md @@ -0,0 +1,143 @@ +# libuv + +libuv is a multi-platform support library with a focus on asynchronous I/O. It +was primarily developed for use by [Node.js](http://nodejs.org), but it's also +used by Mozilla's [Rust language](http://www.rust-lang.org/), +[Luvit](http://luvit.io/), [Julia](http://julialang.org/), +[pyuv](https://crate.io/packages/pyuv/), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). + +## Feature highlights + + * Full-featured event loop backed by epoll, kqueue, IOCP, event ports. + + * Asynchronous TCP and UDP sockets + + * Asynchronous DNS resolution + + * Asynchronous file and file system operations + + * File system events + + * ANSI escape code controlled TTY + + * IPC with socket sharing, using Unix domain sockets or named pipes (Windows) + + * Child processes + + * Thread pool + + * Signal handling + + * High resolution clock + + * Threading and synchronization primitives + + +## Community + + * [Mailing list](http://groups.google.com/group/libuv) + +## Documentation + + * [include/uv.h](https://github.com/joyent/libuv/blob/master/include/uv.h) + — API documentation in the form of detailed header comments. + * [An Introduction to libuv](http://nikhilm.github.com/uvbook/) + — An overview of libuv with tutorials. + * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) + — High-level introductory talk about libuv. + * [Tests and benchmarks](https://github.com/joyent/libuv/tree/master/test) + — API specification and usage examples. + * [libuv-dox](https://github.com/thlorenz/libuv-dox) + — Documenting types and methods of libuv, mostly by reading uv.h. + +## Build Instructions + +For GCC there are two methods building: via autotools or via [GYP][]. +GYP is a meta-build system which can generate MSVS, Makefile, and XCode +backends. It is best used for integration into other projects. + +To build with autotools: + + $ sh autogen.sh + $ ./configure + $ make + $ make check + $ make install + +### Windows + +First, Python 2.6 or 2.7 must be installed as it is required by [GYP][]. + +Also, the directory for the preferred Python executable must be specified +by the `PYTHON` or `Path` environment variables. + +To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell) +and run vcbuild.bat which will checkout the GYP code into build/gyp and +generate uv.sln as well as related project files. + +To have GYP generate build script for another system, checkout GYP into the +project tree manually: + + $ mkdir -p build + $ git clone https://git.chromium.org/external/gyp.git build/gyp + +### Unix + +Run: + + $ ./gyp_uv.py -f make + $ make -C out + +### OS X + +Run: + + $ ./gyp_uv.py -f xcode + $ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ + -configuration Release -target All + +Note to OS X users: + +Make sure that you specify the architecture you wish to build for in the +"ARCHS" flag. You can specify more than one by delimiting with a space +(e.g. "x86_64 i386"). + +### Android + +Run: + + $ source ./android-configure NDK_PATH gyp + $ make -C out + +Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and +`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically. + +### Running tests + +Run: + + $ ./gyp_uv.py -f make + $ make -C out + $ ./out/Debug/run-tests + +## Supported Platforms + +Microsoft Windows operating systems since Windows XP SP2. It can be built +with either Visual Studio or MinGW. Consider using +[Visual Studio Express 2010][] or later if you do not have a full Visual +Studio license. + +Linux using the GCC toolchain. + +OS X using the GCC or XCode toolchain. + +Solaris 121 and later using GCC toolchain. + +## patches + +See the [guidelines for contributing][]. + +[node.js]: http://nodejs.org/ +[GYP]: http://code.google.com/p/gyp/ +[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express +[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md diff --git a/android-configure b/android-configure new file mode 100755 index 0000000000..56625761fd --- /dev/null +++ b/android-configure @@ -0,0 +1,20 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain +mkdir -p $TOOLCHAIN +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=arm-linux-androideabi-4.7 \ + --arch=arm \ + --install-dir=$TOOLCHAIN \ + --platform=android-9 +export PATH=$TOOLCHAIN/bin:$PATH +export AR=arm-linux-androideabi-ar +export CC=arm-linux-androideabi-gcc +export CXX=arm-linux-androideabi-g++ +export LINK=arm-linux-androideabi-g++ +export PLATFORM=android + +if [ $2 -a $2 == 'gyp' ] + then + ./gyp_uv.py -Dtarget_arch=arm -DOS=android +fi diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000000..751b4f5562 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +cd `dirname "$0"` + +if [ "$LIBTOOLIZE" = "" ] && [ "`uname`" = "Darwin" ]; then + LIBTOOLIZE=glibtoolize +fi + +ACLOCAL=${ACLOCAL:-aclocal} +AUTOCONF=${AUTOCONF:-autoconf} +AUTOMAKE=${AUTOMAKE:-automake} +LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} + +automake_version=`"$AUTOMAKE" --version | head -n 1 | sed 's/[^.0-9]//g'` +automake_version_major=`echo "$automake_version" | cut -d. -f1` +automake_version_minor=`echo "$automake_version" | cut -d. -f2` + +UV_EXTRA_AUTOMAKE_FLAGS= +if test "$automake_version_major" -gt 1 || \ + test "$automake_version_major" -eq 1 && \ + test "$automake_version_minor" -gt 11; then + # serial-tests is available in v0.12 and newer. + UV_EXTRA_AUTOMAKE_FLAGS="$UV_EXTRA_AUTOMAKE_FLAGS serial-tests" +fi +echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ + > m4/libuv-extra-automake-flags.m4 + +set -ex +"$LIBTOOLIZE" +"$ACLOCAL" -I m4 +"$AUTOCONF" +"$AUTOMAKE" --add-missing --copy diff --git a/checksparse.sh b/checksparse.sh new file mode 100755 index 0000000000..54cd5805a8 --- /dev/null +++ b/checksparse.sh @@ -0,0 +1,231 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +SPARSE=${SPARSE:-sparse} + +SPARSE_FLAGS=${SPARSE_FLAGS:-" +-D__POSIX__ +-Wsparse-all +-Wno-do-while +-Wno-transparent-union +-Iinclude +-Isrc +"} + +SOURCES=" +include/tree.h +include/uv-unix.h +include/uv.h +src/fs-poll.c +src/inet.c +src/queue.h +src/unix/async.c +src/unix/core.c +src/unix/dl.c +src/unix/fs.c +src/unix/getaddrinfo.c +src/unix/internal.h +src/unix/loop-watcher.c +src/unix/loop.c +src/unix/pipe.c +src/unix/poll.c +src/unix/process.c +src/unix/signal.c +src/unix/stream.c +src/unix/tcp.c +src/unix/thread.c +src/unix/threadpool.c +src/unix/timer.c +src/unix/tty.c +src/unix/udp.c +src/uv-common.c +src/uv-common.h +" + +TESTS=" +test/benchmark-async-pummel.c +test/benchmark-async.c +test/benchmark-fs-stat.c +test/benchmark-getaddrinfo.c +test/benchmark-loop-count.c +test/benchmark-million-async.c +test/benchmark-million-timers.c +test/benchmark-multi-accept.c +test/benchmark-ping-pongs.c +test/benchmark-pound.c +test/benchmark-pump.c +test/benchmark-sizes.c +test/benchmark-spawn.c +test/benchmark-tcp-write-batch.c +test/benchmark-thread.c +test/benchmark-udp-pummel.c +test/blackhole-server.c +test/dns-server.c +test/echo-server.c +test/run-benchmarks.c +test/run-tests.c +test/runner-unix.c +test/runner-unix.h +test/runner.c +test/runner.h +test/task.h +test/test-active.c +test/test-async.c +test/test-barrier.c +test/test-callback-order.c +test/test-callback-stack.c +test/test-condvar.c +test/test-connection-fail.c +test/test-cwd-and-chdir.c +test/test-delayed-accept.c +test/test-dlerror.c +test/test-embed.c +test/test-error.c +test/test-fail-always.c +test/test-fs-event.c +test/test-fs-poll.c +test/test-fs.c +test/test-get-currentexe.c +test/test-get-loadavg.c +test/test-get-memory.c +test/test-getaddrinfo.c +test/test-getsockname.c +test/test-hrtime.c +test/test-idle.c +test/test-ip6-addr.c +test/test-ipc-send-recv.c +test/test-ipc.c +test/test-loop-handles.c +test/test-multiple-listen.c +test/test-mutexes.c +test/test-pass-always.c +test/test-ping-pong.c +test/test-pipe-bind-error.c +test/test-pipe-connect-error.c +test/test-pipe-server-close.c +test/test-platform-output.c +test/test-poll-close.c +test/test-poll.c +test/test-process-title.c +test/test-ref.c +test/test-run-nowait.c +test/test-run-once.c +test/test-semaphore.c +test/test-shutdown-close.c +test/test-shutdown-eof.c +test/test-signal-multiple-loops.c +test/test-signal.c +test/test-spawn.c +test/test-stdio-over-pipes.c +test/test-tcp-bind-error.c +test/test-tcp-bind6-error.c +test/test-tcp-close-while-connecting.c +test/test-tcp-close-accept.c +test/test-tcp-close.c +test/test-tcp-connect-error-after-write.c +test/test-tcp-connect-error.c +test/test-tcp-connect-timeout.c +test/test-tcp-connect6-error.c +test/test-tcp-flags.c +test/test-tcp-open.c +test/test-tcp-read-stop.c +test/test-tcp-shutdown-after-write.c +test/test-tcp-unexpected-read.c +test/test-tcp-write-error.c +test/test-tcp-write-to-half-open-connection.c +test/test-tcp-writealot.c +test/test-thread.c +test/test-threadpool-cancel.c +test/test-threadpool.c +test/test-timer-again.c +test/test-timer.c +test/test-tty.c +test/test-udp-dgram-too-big.c +test/test-udp-ipv6.c +test/test-udp-multicast-join.c +test/test-udp-multicast-ttl.c +test/test-udp-open.c +test/test-udp-options.c +test/test-udp-send-and-recv.c +test/test-walk-handles.c +test/test-watcher-cross-stop.c +" + +case `uname -s` in +AIX) + SPARSE_FLAGS="$SPARSE_FLAGS -D_AIX=1" + SOURCES="$SOURCES + src/unix/aix.c" + ;; +Darwin) + SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1" + SOURCES="$SOURCES + include/uv-bsd.h + src/unix/darwin.c + src/unix/kqueue.c + src/unix/fsevents.c" + ;; +DragonFly) + SPARSE_FLAGS="$SPARSE_FLAGS -D__DragonFly__=1" + SOURCES="$SOURCES + include/uv-bsd.h + src/unix/kqueue.c + src/unix/freebsd.c" + ;; +FreeBSD) + SPARSE_FLAGS="$SPARSE_FLAGS -D__FreeBSD__=1" + SOURCES="$SOURCES + include/uv-bsd.h + src/unix/kqueue.c + src/unix/freebsd.c" + ;; +Linux) + SPARSE_FLAGS="$SPARSE_FLAGS -D__linux__=1" + SOURCES="$SOURCES + include/uv-linux.h + src/unix/linux-inotify.c + src/unix/linux-core.c + src/unix/linux-syscalls.c + src/unix/linux-syscalls.h" + ;; +NetBSD) + SPARSE_FLAGS="$SPARSE_FLAGS -D__NetBSD__=1" + SOURCES="$SOURCES + include/uv-bsd.h + src/unix/kqueue.c + src/unix/netbsd.c" + ;; +OpenBSD) + SPARSE_FLAGS="$SPARSE_FLAGS -D__OpenBSD__=1" + SOURCES="$SOURCES + include/uv-bsd.h + src/unix/kqueue.c + src/unix/openbsd.c" + ;; +SunOS) + SPARSE_FLAGS="$SPARSE_FLAGS -D__sun=1" + SOURCES="$SOURCES + include/uv-sunos.h + src/unix/sunos.c" + ;; +esac + +for ARCH in __i386__ __x86_64__ __arm__ __mips__; do + $SPARSE $SPARSE_FLAGS -D$ARCH=1 $SOURCES +done + +# Tests are architecture independent. +$SPARSE $SPARSE_FLAGS -Itest $TESTS diff --git a/common.gypi b/common.gypi new file mode 100644 index 0000000000..7adbbbdcc9 --- /dev/null +++ b/common.gypi @@ -0,0 +1,208 @@ +{ + 'variables': { + 'visibility%': 'hidden', # V8's visibility setting + 'target_arch%': 'ia32', # set v8's target architecture + 'host_arch%': 'ia32', # set v8's host architecture + 'library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds + 'component%': 'static_library', # NB. these names match with what V8 expects + 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way + 'gcc_version%': 'unknown', + 'clang%': 0, + }, + + 'target_defaults': { + 'default_configuration': 'Debug', + 'configurations': { + 'Debug': { + 'defines': [ 'DEBUG', '_DEBUG' ], + 'cflags': [ '-g', '-O0', '-fwrapv' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['library=="static_library"', { + 'RuntimeLibrary': 1, # static debug + }, { + 'RuntimeLibrary': 3, # DLL debug + }], + ], + 'Optimization': 0, # /Od, no optimization + 'MinimalRebuild': 'false', + 'OmitFramePointers': 'false', + 'BasicRuntimeChecks': 3, # /RTC1 + }, + 'VCLinkerTool': { + 'LinkIncremental': 2, # enable incremental linking + }, + }, + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', + 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], + }, + 'conditions': [ + ['OS != "win"', { + 'defines': [ 'EV_VERIFY=2' ], + }], + ] + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'cflags': [ + '-O3', + '-fstrict-aliasing', + '-fomit-frame-pointer', + '-fdata-sections', + '-ffunction-sections', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['library=="static_library"', { + 'RuntimeLibrary': 0, # static release + }, { + 'RuntimeLibrary': 2, # debug release + }], + ], + 'Optimization': 3, # /Ox, full optimization + 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size + 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible + 'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG + 'OmitFramePointers': 'true', + 'EnableFunctionLevelLinking': 'true', + 'EnableIntrinsicFunctions': 'true', + }, + 'VCLibrarianTool': { + 'AdditionalOptions': [ + '/LTCG', # link time code generation + ], + }, + 'VCLinkerTool': { + 'LinkTimeCodeGeneration': 1, # link-time code generation + 'OptimizeReferences': 2, # /OPT:REF + 'EnableCOMDATFolding': 2, # /OPT:ICF + 'LinkIncremental': 1, # disable incremental linking + }, + }, + } + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'StringPooling': 'true', # pool string literals + 'DebugInformationFormat': 3, # Generate a PDB + 'WarningLevel': 3, + 'BufferSecurityCheck': 'true', + 'ExceptionHandling': 1, # /EHsc + 'SuppressStartupBanner': 'true', + 'WarnAsError': 'false', + 'AdditionalOptions': [ + '/MP', # compile across multiple CPUs + ], + }, + 'VCLibrarianTool': { + }, + 'VCLinkerTool': { + 'GenerateDebugInformation': 'true', + 'RandomizedBaseAddress': 2, # enable ASLR + 'DataExecutionPrevention': 2, # enable DEP + 'AllowIsolation': 'true', + 'SuppressStartupBanner': 'true', + 'target_conditions': [ + ['_type=="executable"', { + 'SubSystem': 1, # console executable + }], + ], + }, + }, + 'conditions': [ + ['OS == "win"', { + 'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin + 'defines': [ + 'WIN32', + # we don't really want VC++ warning us about + # how dangerous C functions are... + '_CRT_SECURE_NO_DEPRECATE', + # ... or that C implementations shouldn't use + # POSIX names + '_CRT_NONSTDC_NO_DEPRECATE', + ], + 'target_conditions': [ + ['target_arch=="x64"', { + 'msvs_configuration_platform': 'x64' + }] + ] + }], + ['OS in "freebsd linux openbsd solaris android"', { + 'cflags': [ '-Wall' ], + 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], + 'target_conditions': [ + ['_type=="static_library"', { + 'standalone_static_library': 1, # disable thin archive which needs binutils >= 2.19 + }], + ], + 'conditions': [ + [ 'host_arch != target_arch and target_arch=="ia32"', { + 'cflags': [ '-m32' ], + 'ldflags': [ '-m32' ], + }], + [ 'OS=="linux"', { + 'cflags': [ '-ansi' ], + }], + [ 'OS=="solaris"', { + 'cflags': [ '-pthreads' ], + 'ldflags': [ '-pthreads' ], + }], + [ 'OS not in "solaris android"', { + 'cflags': [ '-pthread' ], + 'ldflags': [ '-pthread' ], + }], + [ 'visibility=="hidden" and (clang==1 or gcc_version >= 40)', { + 'cflags': [ '-fvisibility=hidden' ], + }], + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'ALWAYS_SEARCH_USER_PATHS': 'NO', + 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks + 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic + # (Equivalent to -fPIC) + 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions + 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti + 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings + # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'PREBINDING': 'NO', # No -Wl,-prebind + 'USE_HEADERMAP': 'NO', + 'OTHER_CFLAGS': [ + '-fstrict-aliasing', + ], + 'WARNING_CFLAGS': [ + '-Wall', + '-Wendif-labels', + '-W', + '-Wno-unused-parameter', + ], + }, + 'conditions': [ + ['target_arch=="ia32"', { + 'xcode_settings': {'ARCHS': ['i386']}, + }], + ['target_arch=="x64"', { + 'xcode_settings': {'ARCHS': ['x86_64']}, + }], + ], + 'target_conditions': [ + ['_type!="static_library"', { + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, + }], + ], + }], + ['OS=="solaris"', { + 'cflags': [ '-fno-omit-frame-pointer' ], + # pull in V8's postmortem metadata + 'ldflags': [ '-Wl,-z,allextract' ] + }], + ], + }, +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000000..ffa09b45c2 --- /dev/null +++ b/configure.ac @@ -0,0 +1,55 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +AC_PREREQ(2.57) +AC_INIT([libuv], [0.11.19], [https://github.com/joyent/libuv/issues]) +AC_CONFIG_MACRO_DIR([m4]) +m4_include([m4/libuv-extra-automake-flags.m4]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) +AC_CANONICAL_HOST +AC_ENABLE_SHARED +AC_ENABLE_STATIC +AC_PROG_CC +AM_PROG_CC_C_O +# AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +LT_INIT +# TODO(bnoordhuis) Check for -pthread vs. -pthreads +AC_CHECK_LIB([dl], [dlopen]) +AC_CHECK_LIB([kstat], [kstat_lookup]) +AC_CHECK_LIB([kvm], [kvm_open]) +AC_CHECK_LIB([nsl], [gethostbyname]) +AC_CHECK_LIB([perfstat], [perfstat_cpu]) +AC_CHECK_LIB([pthread], [pthread_mutex_init]) +AC_CHECK_LIB([rt], [clock_gettime]) +AC_CHECK_LIB([sendfile], [sendfile]) +AC_CHECK_LIB([socket], [socket]) +AC_SYS_LARGEFILE +AM_CONDITIONAL([AIX], [AS_CASE([$host_os], [aix*], [true], [false])]) +AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os], [darwin*], [true], [false])]) +AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os], [freebsd*], [true], [false])]) +AM_CONDITIONAL([LINUX], [AS_CASE([$host_os], [linux*], [true], [false])]) +AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os], [netbsd*], [true], [false])]) +AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os], [openbsd*], [true], [false])]) +AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os], [solaris*], [true], [false])]) +AM_CONDITIONAL([WINNT], [AS_CASE([$host_os], [mingw*], [true], [false])]) +PANDORA_ENABLE_DTRACE +AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) +AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" = "xyes"]) +AS_IF([test "x$PKG_CONFIG" = "xyes"], [ + AC_CONFIG_FILES([libuv.pc]) +]) +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/gyp_uv.py b/gyp_uv.py new file mode 100755 index 0000000000..4ba69167d9 --- /dev/null +++ b/gyp_uv.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +import glob +import platform +import os +import subprocess +import sys + +CC = os.environ.get('CC', 'cc') +script_dir = os.path.dirname(__file__) +uv_root = os.path.normpath(script_dir) +output_dir = os.path.join(os.path.abspath(uv_root), 'out') + +sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib')) +try: + import gyp +except ImportError: + print('You need to install gyp in build/gyp first. See the README.') + sys.exit(42) + + +def host_arch(): + machine = platform.machine() + if machine == 'i386': return 'ia32' + if machine == 'x86_64': return 'x64' + if machine.startswith('arm'): return 'arm' + if machine.startswith('mips'): return 'mips' + return machine # Return as-is and hope for the best. + + +def compiler_version(): + proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE) + is_clang = 'clang' in proc.communicate()[0].split('\n')[0] + proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE) + version = proc.communicate()[0].split('.') + version = map(int, version[:2]) + version = tuple(version) + return (version, is_clang) + + +def run_gyp(args): + rc = gyp.main(args) + if rc != 0: + print 'Error running GYP' + sys.exit(rc) + + +if __name__ == '__main__': + args = sys.argv[1:] + + # GYP bug. + # On msvs it will crash if it gets an absolute path. + # On Mac/make it will crash if it doesn't get an absolute path. + if sys.platform == 'win32': + args.append(os.path.join(uv_root, 'uv.gyp')) + common_fn = os.path.join(uv_root, 'common.gypi') + options_fn = os.path.join(uv_root, 'options.gypi') + # we force vs 2010 over 2008 which would otherwise be the default for gyp + if not os.environ.get('GYP_MSVS_VERSION'): + os.environ['GYP_MSVS_VERSION'] = '2010' + else: + args.append(os.path.join(os.path.abspath(uv_root), 'uv.gyp')) + common_fn = os.path.join(os.path.abspath(uv_root), 'common.gypi') + options_fn = os.path.join(os.path.abspath(uv_root), 'options.gypi') + + if os.path.exists(common_fn): + args.extend(['-I', common_fn]) + + if os.path.exists(options_fn): + args.extend(['-I', options_fn]) + + args.append('--depth=' + uv_root) + + # There's a bug with windows which doesn't allow this feature. + if sys.platform != 'win32': + if '-f' not in args: + args.extend('-f make'.split()) + if 'eclipse' not in args and 'ninja' not in args: + args.extend(['-Goutput_dir=' + output_dir]) + args.extend(['--generator-output', output_dir]) + (major, minor), is_clang = compiler_version() + args.append('-Dgcc_version=%d' % (10 * major + minor)) + args.append('-Dclang=%d' % int(is_clang)) + + if not any(a.startswith('-Dhost_arch=') for a in args): + args.append('-Dhost_arch=%s' % host_arch()) + + if not any(a.startswith('-Dtarget_arch=') for a in args): + args.append('-Dtarget_arch=%s' % host_arch()) + + if not any(a.startswith('-Dlibrary=') for a in args): + args.append('-Dlibrary=static_library') + + if not any(a.startswith('-Dcomponent=') for a in args): + args.append('-Dcomponent=static_library') + + gyp_args = list(args) + print gyp_args + run_gyp(gyp_args) diff --git a/include/pthread-fixes.h b/include/pthread-fixes.h new file mode 100644 index 0000000000..230ce3178d --- /dev/null +++ b/include/pthread-fixes.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2013, Sony Mobile Communications AB + * Copyright (c) 2012, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H + +#include + + +/*Android doesn't provide pthread_barrier_t for now.*/ +#ifndef PTHREAD_BARRIER_SERIAL_THREAD + +/* Anything except 0 will do here.*/ +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned count; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); +#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ + +int pthread_yield(void); +#endif /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */ diff --git a/include/stdint-msvc2008.h b/include/stdint-msvc2008.h new file mode 100644 index 0000000000..d02608a597 --- /dev/null +++ b/include/stdint-msvc2008.h @@ -0,0 +1,247 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000000..f936416e3d --- /dev/null +++ b/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UV_TREE_H_ +#define UV_TREE_H_ + +#ifndef UV__UNUSED +# if __GNUC__ +# define UV__UNUSED __attribute__((unused)) +# else +# define UV__UNUSED +# endif +#endif + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + \ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ + __left = __right = &__node; \ + \ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field); \ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \ + struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field); \ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_LEFT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK; \ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field); \ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field); \ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \ + RB_ROTATE_RIGHT(head, parent, tmp, field); \ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old) \ + RB_LEFT(RB_PARENT(old, field), field) = elm; \ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm; \ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* UV_TREE_H_ */ diff --git a/include/uv-bsd.h b/include/uv-bsd.h new file mode 100644 index 0000000000..2d72b3d771 --- /dev/null +++ b/include/uv-bsd.h @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_BSD_H +#define UV_BSD_H + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_HAVE_KQUEUE 1 + +#endif /* UV_BSD_H */ diff --git a/include/uv-darwin.h b/include/uv-darwin.h new file mode 100644 index 0000000000..24bc35b581 --- /dev/null +++ b/include/uv-darwin.h @@ -0,0 +1,63 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_DARWIN_H +#define UV_DARWIN_H + +#if defined(__APPLE__) && defined(__MACH__) +# include +# include +# include +# include +# define UV_PLATFORM_SEM_T semaphore_t +#endif + +#define UV_IO_PRIVATE_PLATFORM_FIELDS \ + int rcount; \ + int wcount; \ + +#define UV_PLATFORM_LOOP_FIELDS \ + uv_thread_t cf_thread; \ + void* _cf_reserved; \ + void* cf_state; \ + uv_mutex_t cf_mutex; \ + uv_sem_t cf_sem; \ + void* cf_signals[2]; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + uv__io_t event_watcher; \ + char* realpath; \ + int realpath_len; \ + int cf_flags; \ + uv_async_t* cf_cb; \ + void* cf_events[2]; \ + void* cf_member[2]; \ + int cf_error; \ + uv_mutex_t cf_mutex; \ + +#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + void* select; \ + +#define UV_HAVE_KQUEUE 1 + +#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS + +#endif /* UV_DARWIN_H */ diff --git a/include/uv-errno.h b/include/uv-errno.h new file mode 100644 index 0000000000..797bcab93b --- /dev/null +++ b/include/uv-errno.h @@ -0,0 +1,373 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_ERRNO_H_ +#define UV_ERRNO_H_ + +#include + +#define UV__EOF (-4095) +#define UV__UNKNOWN (-4094) + +#define UV__EAI_ADDRFAMILY (-3000) +#define UV__EAI_AGAIN (-3001) +#define UV__EAI_BADFLAGS (-3002) +#define UV__EAI_CANCELED (-3003) +#define UV__EAI_FAIL (-3004) +#define UV__EAI_FAMILY (-3005) +#define UV__EAI_MEMORY (-3006) +#define UV__EAI_NODATA (-3007) +#define UV__EAI_NONAME (-3008) +#define UV__EAI_OVERFLOW (-3009) +#define UV__EAI_SERVICE (-3010) +#define UV__EAI_SOCKTYPE (-3011) +#define UV__EAI_SYSTEM (-3012) /* TODO(bnoordhuis) Return system error. */ +#define UV__EAI_BADHINTS (-3013) +#define UV__EAI_PROTOCOL (-3014) + +/* Only map to the system errno on non-Windows platforms. It's apparently + * a fairly common practice for Windows programmers to redefine errno codes. + */ +#if defined(E2BIG) && !defined(_WIN32) +# define UV__E2BIG (-E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES (-EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINFO) && !defined(_WIN32) +# define UV__EADDRINFO EADDRINFO +#else +# define UV__EADDRINFO (-4091) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE (-EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT (-EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN (-EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY (-EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF (-EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY (-EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED (-ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET (-ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED (-ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED (-ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET (-ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ (-EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST (-EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT (-EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH (-EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR (-EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL (-EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO (-EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN (-EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR (-EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP (-ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE (-EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE (-EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG (-ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN (-ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH (-ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE (-ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS (-ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV (-ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT (-ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM (-ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET (-ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC (-ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS (-ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN (-ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR (-ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY (-ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK (-ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP (-ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM (-EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE (-EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO (-EPROTO) +#else +# define UV__EPROTO (-4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE (-EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS (-EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN (-ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE (-ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH (-ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT (-ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV (-EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#endif /* UV_ERRNO_H_ */ diff --git a/include/uv-linux.h b/include/uv-linux.h new file mode 100644 index 0000000000..62ebfe2a02 --- /dev/null +++ b/include/uv-linux.h @@ -0,0 +1,36 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_LINUX_H +#define UV_LINUX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t inotify_read_watcher; \ + void* inotify_watchers; \ + int inotify_fd; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + void* watchers[2]; \ + int wd; \ + +#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS + +#endif /* UV_LINUX_H */ diff --git a/include/uv-sunos.h b/include/uv-sunos.h new file mode 100644 index 0000000000..042166424e --- /dev/null +++ b/include/uv-sunos.h @@ -0,0 +1,44 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_SUNOS_H +#define UV_SUNOS_H + +#include +#include + +/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c, + * add the fs_event fields even when this version of SunOS doesn't support + * file watching. + */ +#define UV_PLATFORM_LOOP_FIELDS \ + uv__io_t fs_event_watcher; \ + int fs_fd; \ + +#if defined(PORT_SOURCE_FILE) + +# define UV_PLATFORM_FS_EVENT_FIELDS \ + file_obj_t fo; \ + int fd; \ + +#endif /* defined(PORT_SOURCE_FILE) */ + +#endif /* UV_SUNOS_H */ diff --git a/include/uv-unix.h b/include/uv-unix.h new file mode 100644 index 0000000000..45006092be --- /dev/null +++ b/include/uv-unix.h @@ -0,0 +1,329 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_UNIX_H +#define UV_UNIX_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#ifdef __ANDROID__ +#include "pthread-fixes.h" +#endif +#include + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined(__sun) +# include "uv-sunos.h" +#elif defined(__APPLE__) +# include "uv-darwin.h" +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#endif + +#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS +# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +struct uv__io_s; +struct uv__async; +struct uv_loop_s; + +typedef void (*uv__io_cb)(struct uv_loop_s* loop, + struct uv__io_s* w, + unsigned int events); +typedef struct uv__io_s uv__io_t; + +struct uv__io_s { + uv__io_cb cb; + void* pending_queue[2]; + void* watcher_queue[2]; + unsigned int pevents; /* Pending event mask i.e. mask at next tick. */ + unsigned int events; /* Current event mask. */ + int fd; + UV_IO_PRIVATE_PLATFORM_FIELDS +}; + +typedef void (*uv__async_cb)(struct uv_loop_s* loop, + struct uv__async* w, + unsigned int nevents); + +struct uv__async { + uv__async_cb cb; + uv__io_t io_watcher; + int wfd; +}; + +struct uv__work { + void (*work)(struct uv__work *w); + void (*done)(struct uv__work *w, int status); + struct uv_loop_s* loop; + void* wq[2]; +}; + +#ifndef UV_PLATFORM_SEM_T +# define UV_PLATFORM_SEM_T sem_t +#endif + +#ifndef UV_PLATFORM_LOOP_FIELDS +# define UV_PLATFORM_LOOP_FIELDS /* empty */ +#endif + +#ifndef UV_PLATFORM_FS_EVENT_FIELDS +# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */ +#endif + +#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS +# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */ +#endif + +/* Note: May be cast to struct iovec. See writev(2). */ +typedef struct { + char* base; + size_t len; +} uv_buf_t; + +typedef int uv_file; +typedef int uv_os_sock_t; + +#define UV_ONCE_INIT PTHREAD_ONCE_INIT + +typedef pthread_once_t uv_once_t; +typedef pthread_t uv_thread_t; +typedef pthread_mutex_t uv_mutex_t; +typedef pthread_rwlock_t uv_rwlock_t; +typedef UV_PLATFORM_SEM_T uv_sem_t; +typedef pthread_cond_t uv_cond_t; +typedef pthread_key_t uv_key_t; + +#if defined(__APPLE__) && defined(__MACH__) + +typedef struct { + unsigned int n; + unsigned int count; + uv_mutex_t mutex; + uv_sem_t turnstile1; + uv_sem_t turnstile2; +} uv_barrier_t; + +#else /* defined(__APPLE__) && defined(__MACH__) */ + +typedef pthread_barrier_t uv_barrier_t; + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +/* Platform-specific definitions for uv_spawn support. */ +typedef gid_t uv_gid_t; +typedef uid_t uv_uid_t; + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC /* empty */ + +typedef struct { + void* handle; + char* errmsg; +} uv_lib_t; + +#define UV_LOOP_PRIVATE_FIELDS \ + unsigned long flags; \ + int backend_fd; \ + void* pending_queue[2]; \ + void* watcher_queue[2]; \ + uv__io_t** watchers; \ + unsigned int nwatchers; \ + unsigned int nfds; \ + void* wq[2]; \ + uv_mutex_t wq_mutex; \ + uv_async_t wq_async; \ + uv_handle_t* closing_handles; \ + void* process_handles[1][2]; \ + void* prepare_handles[2]; \ + void* check_handles[2]; \ + void* idle_handles[2]; \ + void* async_handles[2]; \ + struct uv__async async_watcher; \ + /* RB_HEAD(uv__timers, uv_timer_s) */ \ + struct uv__timers { \ + struct uv_timer_s* rbh_root; \ + } timer_handles; \ + uint64_t time; \ + int signal_pipefd[2]; \ + uv__io_t signal_io_watcher; \ + uv_signal_t child_watcher; \ + int emfile_fd; \ + uint64_t timer_counter; \ + UV_PLATFORM_LOOP_FIELDS \ + +#define UV_REQ_TYPE_PRIVATE /* empty */ + +#define UV_REQ_PRIVATE_FIELDS /* empty */ + +#define UV_PRIVATE_REQ_TYPES /* empty */ + +#define UV_WRITE_PRIVATE_FIELDS \ + void* queue[2]; \ + unsigned int write_index; \ + uv_buf_t* bufs; \ + unsigned int nbufs; \ + int error; \ + uv_buf_t bufsml[4]; \ + +#define UV_CONNECT_PRIVATE_FIELDS \ + void* queue[2]; \ + +#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + void* queue[2]; \ + struct sockaddr_in6 addr; \ + unsigned int nbufs; \ + uv_buf_t* bufs; \ + ssize_t status; \ + uv_udp_send_cb send_cb; \ + uv_buf_t bufsml[4]; \ + +#define UV_HANDLE_PRIVATE_FIELDS \ + int flags; \ + uv_handle_t* next_closing; \ + +#define UV_STREAM_PRIVATE_FIELDS \ + uv_connect_t *connect_req; \ + uv_shutdown_t *shutdown_req; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + uv_connection_cb connection_cb; \ + int delayed_error; \ + int accepted_fd; \ + UV_STREAM_PRIVATE_PLATFORM_FIELDS \ + +#define UV_TCP_PRIVATE_FIELDS /* empty */ + +#define UV_UDP_PRIVATE_FIELDS \ + uv_alloc_cb alloc_cb; \ + uv_udp_recv_cb recv_cb; \ + uv__io_t io_watcher; \ + void* write_queue[2]; \ + void* write_completed_queue[2]; \ + +#define UV_PIPE_PRIVATE_FIELDS \ + const char* pipe_fname; /* strdup'ed */ + +#define UV_POLL_PRIVATE_FIELDS \ + uv__io_t io_watcher; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_cb prepare_cb; \ + void* queue[2]; \ + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_cb check_cb; \ + void* queue[2]; \ + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_cb idle_cb; \ + void* queue[2]; \ + +#define UV_ASYNC_PRIVATE_FIELDS \ + uv_async_cb async_cb; \ + void* queue[2]; \ + int pending; \ + +#define UV_TIMER_PRIVATE_FIELDS \ + /* RB_ENTRY(uv_timer_s) tree_entry; */ \ + struct { \ + struct uv_timer_s* rbe_left; \ + struct uv_timer_s* rbe_right; \ + struct uv_timer_s* rbe_parent; \ + int rbe_color; \ + } tree_entry; \ + uv_timer_cb timer_cb; \ + uint64_t timeout; \ + uint64_t repeat; \ + uint64_t start_id; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ + uv_getaddrinfo_cb cb; \ + struct addrinfo* hints; \ + char* hostname; \ + char* service; \ + struct addrinfo* res; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + void* queue[2]; \ + int status; \ + +#define UV_FS_PRIVATE_FIELDS \ + const char *new_path; \ + uv_file file; \ + int flags; \ + mode_t mode; \ + void* buf; \ + size_t len; \ + off_t off; \ + uv_uid_t uid; \ + uv_gid_t gid; \ + double atime; \ + double mtime; \ + struct uv__work work_req; \ + +#define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; + +#define UV_TTY_PRIVATE_FIELDS \ + struct termios orig_termios; \ + int mode; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + /* RB_ENTRY(uv_signal_s) tree_entry; */ \ + struct { \ + struct uv_signal_s* rbe_left; \ + struct uv_signal_s* rbe_right; \ + struct uv_signal_s* rbe_parent; \ + int rbe_color; \ + } tree_entry; \ + /* Use two counters here so we don have to fiddle with atomics. */ \ + unsigned int caught_signals; \ + unsigned int dispatched_signals; + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + uv_fs_event_cb cb; \ + UV_PLATFORM_FS_EVENT_FIELDS \ + +#endif /* UV_UNIX_H */ diff --git a/include/uv-win.h b/include/uv-win.h new file mode 100644 index 0000000000..e4e1f839f0 --- /dev/null +++ b/include/uv-win.h @@ -0,0 +1,589 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0502 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "tree.h" + +#define MAX_PIPENAME_LEN 256 + +#ifndef S_IFLNK +# define S_IFLNK 0xA000 +#endif + +/* Additional signals supported by uv_signal and or uv_kill. The CRT defines + * the following signals already: + * + * #define SIGINT 2 + * #define SIGILL 4 + * #define SIGABRT_COMPAT 6 + * #define SIGFPE 8 + * #define SIGSEGV 11 + * #define SIGTERM 15 + * #define SIGBREAK 21 + * #define SIGABRT 22 + * + * The additional signals have values that are common on other Unix + * variants (Linux and Darwin) + */ +#define SIGHUP 1 +#define SIGKILL 9 +#define SIGWINCH 28 + +/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */ +/* unix-like platforms. However MinGW doesn't define it, so we do. */ +#ifndef SIGABRT_COMPAT +# define SIGABRT_COMPAT 6 +#endif + +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ + {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ + {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} + +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + + typedef BOOL PASCAL (*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL PASCAL (*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR* LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR* RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); + + typedef PVOID RTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +typedef int (WSAAPI* LPFN_WSARECV) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +typedef int (WSAAPI* LPFN_WSARECVFROM) + (SOCKET socket, + LPWSABUF buffers, + DWORD buffer_count, + LPDWORD bytes, + LPDWORD flags, + struct sockaddr* addr, + LPINT addr_len, + LPWSAOVERLAPPED overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +#ifndef _NTDEF_ + typedef LONG NTSTATUS; + typedef NTSTATUS *PNTSTATUS; +#endif + +#ifndef RTL_CONDITION_VARIABLE_INIT + typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef struct _AFD_POLL_HANDLE_INFO { + HANDLE Handle; + ULONG Events; + NTSTATUS Status; +} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO; + +typedef struct _AFD_POLL_INFO { + LARGE_INTEGER Timeout; + ULONG NumberOfHandles; + ULONG Exclusive; + AFD_POLL_HANDLE_INFO Handles[1]; +} AFD_POLL_INFO, *PAFD_POLL_INFO; + +#define UV_MSAFD_PROVIDER_COUNT 3 + + +/** + * It should be possible to cast uv_buf_t[] to WSABUF[] + * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx + */ +typedef struct uv_buf_t { + ULONG len; + char* base; +} uv_buf_t; + +typedef int uv_file; + +typedef SOCKET uv_os_sock_t; + +typedef HANDLE uv_thread_t; + +typedef HANDLE uv_sem_t; + +typedef CRITICAL_SECTION uv_mutex_t; + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +typedef union { + CONDITION_VARIABLE cond_var; + struct { + unsigned int waiters_count; + CRITICAL_SECTION waiters_count_lock; + HANDLE signal_event; + HANDLE broadcast_event; + } fallback; +} uv_cond_t; + +typedef union { + /* srwlock_ has type SRWLOCK, but not all toolchains define this type in */ + /* windows.h. */ + SRWLOCK srwlock_; + struct { + uv_mutex_t read_mutex_; + uv_mutex_t write_mutex_; + unsigned int num_readers_; + } fallback_; +} uv_rwlock_t; + +typedef struct { + unsigned int n; + unsigned int count; + uv_mutex_t mutex; + uv_sem_t turnstile1; + uv_sem_t turnstile2; +} uv_barrier_t; + +typedef struct { + DWORD tls_index; +} uv_key_t; + +#define UV_ONCE_INIT { 0, NULL } + +typedef struct uv_once_s { + unsigned char ran; + HANDLE event; +} uv_once_t; + +/* Platform-specific definitions for uv_spawn support. */ +typedef unsigned char uv_uid_t; +typedef unsigned char uv_gid_t; + +/* Platform-specific definitions for uv_dlopen support. */ +#define UV_DYNAMIC FAR WINAPI +typedef struct { + HMODULE handle; + char* errmsg; +} uv_lib_t; + +RB_HEAD(uv_timer_tree_s, uv_timer_s); + +#define UV_LOOP_PRIVATE_FIELDS \ + /* The loop's I/O completion port */ \ + HANDLE iocp; \ + /* The current time according to the event loop. in msecs. */ \ + uint64_t time; \ + /* GetTickCount() result when the event loop time was last updated. */ \ + DWORD last_tick_count; \ + /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ + /* is empty, tail_ is NULL. If there is only one item, */ \ + /* tail_->next_req == tail_ */ \ + uv_req_t* pending_reqs_tail; \ + /* Head of a single-linked list of closed handles */ \ + uv_handle_t* endgame_handles; \ + /* The head of the timers tree */ \ + struct uv_timer_tree_s timers; \ + /* Lists of active loop (prepare / check / idle) watchers */ \ + uv_prepare_t* prepare_handles; \ + uv_check_t* check_handles; \ + uv_idle_t* idle_handles; \ + /* This pointer will refer to the prepare/check/idle handle whose */ \ + /* callback is scheduled to be called next. This is needed to allow */ \ + /* safe removal from one of the lists above while that list being */ \ + /* iterated over. */ \ + uv_prepare_t* next_prepare_handle; \ + uv_check_t* next_check_handle; \ + uv_idle_t* next_idle_handle; \ + /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ + SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ + /* Counter to keep track of active tcp streams */ \ + unsigned int active_tcp_streams; \ + /* Counter to keep track of active udp streams */ \ + unsigned int active_udp_streams; \ + /* Counter to started timer */ \ + uint64_t timer_counter; + +#define UV_REQ_TYPE_PRIVATE \ + /* TODO: remove the req suffix */ \ + UV_ACCEPT, \ + UV_FS_EVENT_REQ, \ + UV_POLL_REQ, \ + UV_PROCESS_EXIT, \ + UV_READ, \ + UV_UDP_RECV, \ + UV_WAKEUP, \ + UV_SIGNAL_REQ, + +#define UV_REQ_PRIVATE_FIELDS \ + union { \ + /* Used by I/O operations */ \ + struct { \ + OVERLAPPED overlapped; \ + size_t queued_bytes; \ + }; \ + }; \ + struct uv_req_s* next_req; + +#define UV_WRITE_PRIVATE_FIELDS \ + int ipc_header; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ + HANDLE wait_handle; + +#define UV_CONNECT_PRIVATE_FIELDS \ + /* empty */ + +#define UV_SHUTDOWN_PRIVATE_FIELDS \ + /* empty */ + +#define UV_UDP_SEND_PRIVATE_FIELDS \ + /* empty */ + +#define UV_PRIVATE_REQ_TYPES \ + typedef struct uv_pipe_accept_s { \ + UV_REQ_FIELDS \ + HANDLE pipeHandle; \ + struct uv_pipe_accept_s* next_pending; \ + } uv_pipe_accept_t; \ + \ + typedef struct uv_tcp_accept_s { \ + UV_REQ_FIELDS \ + SOCKET accept_socket; \ + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + struct uv_tcp_accept_s* next_pending; \ + } uv_tcp_accept_t; \ + \ + typedef struct uv_read_s { \ + UV_REQ_FIELDS \ + HANDLE event_handle; \ + HANDLE wait_handle; \ + } uv_read_t; + +#define uv_stream_connection_fields \ + unsigned int write_reqs_pending; \ + uv_shutdown_t* shutdown_req; + +#define uv_stream_server_fields \ + uv_connection_cb connection_cb; + +#define UV_STREAM_PRIVATE_FIELDS \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_read_t read_req; \ + union { \ + struct { uv_stream_connection_fields }; \ + struct { uv_stream_server_fields }; \ + }; + +#define uv_tcp_server_fields \ + uv_tcp_accept_t* accept_reqs; \ + unsigned int processed_accepts; \ + uv_tcp_accept_t* pending_accepts; \ + LPFN_ACCEPTEX func_acceptex; + +#define uv_tcp_connection_fields \ + uv_buf_t read_buffer; \ + LPFN_CONNECTEX func_connectex; + +#define UV_TCP_PRIVATE_FIELDS \ + SOCKET socket; \ + int bind_error; \ + union { \ + struct { uv_tcp_server_fields }; \ + struct { uv_tcp_connection_fields }; \ + }; + +#define UV_UDP_PRIVATE_FIELDS \ + SOCKET socket; \ + unsigned int reqs_pending; \ + int activecnt; \ + uv_req_t recv_req; \ + uv_buf_t recv_buffer; \ + struct sockaddr_storage recv_from; \ + int recv_from_len; \ + uv_udp_recv_cb recv_cb; \ + uv_alloc_cb alloc_cb; \ + LPFN_WSARECV func_wsarecv; \ + LPFN_WSARECVFROM func_wsarecvfrom; + +#define uv_pipe_server_fields \ + int pending_instances; \ + uv_pipe_accept_t* accept_reqs; \ + uv_pipe_accept_t* pending_accepts; + +#define uv_pipe_connection_fields \ + uv_timer_t* eof_timer; \ + uv_write_t ipc_header_write_req; \ + int ipc_pid; \ + uint64_t remaining_ipc_rawdata_bytes; \ + unsigned char reserved[sizeof(void*)]; \ + struct { \ + WSAPROTOCOL_INFOW* socket_info; \ + int tcp_connection; \ + } pending_ipc_info; \ + uv_write_t* non_overlapped_writes_tail; + +#define UV_PIPE_PRIVATE_FIELDS \ + HANDLE handle; \ + WCHAR* name; \ + union { \ + struct { uv_pipe_server_fields }; \ + struct { uv_pipe_connection_fields }; \ + }; + +/* TODO: put the parser states in an union - TTY handles are always */ +/* half-duplex so read-state can safely overlap write-state. */ +#define UV_TTY_PRIVATE_FIELDS \ + HANDLE handle; \ + union { \ + struct { \ + /* Used for readable TTY handles */ \ + HANDLE read_line_handle; \ + uv_buf_t read_line_buffer; \ + HANDLE read_raw_wait; \ + /* Fields used for translating win keystrokes into vt100 characters */ \ + char last_key[8]; \ + unsigned char last_key_offset; \ + unsigned char last_key_len; \ + WCHAR last_utf16_high_surrogate; \ + INPUT_RECORD last_input_record; \ + }; \ + struct { \ + /* Used for writable TTY handles */ \ + /* utf8-to-utf16 conversion state */ \ + unsigned int utf8_codepoint; \ + unsigned char utf8_bytes_left; \ + /* eol conversion state */ \ + unsigned char previous_eol; \ + /* ansi parser state */ \ + unsigned char ansi_parser_state; \ + unsigned char ansi_csi_argc; \ + unsigned short ansi_csi_argv[4]; \ + COORD saved_position; \ + WORD saved_attributes; \ + }; \ + }; + +#define UV_POLL_PRIVATE_FIELDS \ + SOCKET socket; \ + /* Used in fast mode */ \ + SOCKET peer_socket; \ + AFD_POLL_INFO afd_poll_info_1; \ + AFD_POLL_INFO afd_poll_info_2; \ + /* Used in fast and slow mode. */ \ + uv_req_t poll_req_1; \ + uv_req_t poll_req_2; \ + unsigned char submitted_events_1; \ + unsigned char submitted_events_2; \ + unsigned char mask_events_1; \ + unsigned char mask_events_2; \ + unsigned char events; + +#define UV_TIMER_PRIVATE_FIELDS \ + RB_ENTRY(uv_timer_s) tree_entry; \ + uint64_t due; \ + uint64_t repeat; \ + uint64_t start_id; \ + uv_timer_cb timer_cb; + +#define UV_ASYNC_PRIVATE_FIELDS \ + struct uv_req_s async_req; \ + uv_async_cb async_cb; \ + /* char to avoid alignment issues */ \ + char volatile async_sent; + +#define UV_PREPARE_PRIVATE_FIELDS \ + uv_prepare_t* prepare_prev; \ + uv_prepare_t* prepare_next; \ + uv_prepare_cb prepare_cb; + +#define UV_CHECK_PRIVATE_FIELDS \ + uv_check_t* check_prev; \ + uv_check_t* check_next; \ + uv_check_cb check_cb; + +#define UV_IDLE_PRIVATE_FIELDS \ + uv_idle_t* idle_prev; \ + uv_idle_t* idle_next; \ + uv_idle_cb idle_cb; + +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* endgame_next; \ + unsigned int flags; + +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + uv_getaddrinfo_cb getaddrinfo_cb; \ + void* alloc; \ + WCHAR* node; \ + WCHAR* service; \ + struct addrinfoW* hints; \ + struct addrinfoW* res; \ + int retcode; + +#define UV_PROCESS_PRIVATE_FIELDS \ + struct uv_process_exit_s { \ + UV_REQ_FIELDS \ + } exit_req; \ + BYTE* child_stdio_buffer; \ + int exit_signal; \ + HANDLE wait_handle; \ + HANDLE process_handle; \ + volatile char exit_cb_pending; + +#define UV_FS_PRIVATE_FIELDS \ + int flags; \ + DWORD sys_errno_; \ + union { \ + /* TODO: remove me in 0.9. */ \ + WCHAR* pathw; \ + int fd; \ + }; \ + union { \ + struct { \ + int mode; \ + WCHAR* new_pathw; \ + int file_flags; \ + int fd_out; \ + void* buf; \ + size_t length; \ + int64_t offset; \ + }; \ + struct { \ + double atime; \ + double mtime; \ + }; \ + }; + +#define UV_WORK_PRIVATE_FIELDS \ + +#define UV_FS_EVENT_PRIVATE_FIELDS \ + struct uv_fs_event_req_s { \ + UV_REQ_FIELDS \ + } req; \ + HANDLE dir_handle; \ + int req_pending; \ + uv_fs_event_cb cb; \ + WCHAR* filew; \ + WCHAR* short_filew; \ + WCHAR* dirw; \ + char* buffer; + +#define UV_SIGNAL_PRIVATE_FIELDS \ + RB_ENTRY(uv_signal_s) tree_entry; \ + struct uv_req_s signal_req; \ + unsigned long pending_signum; + +int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, + char* utf8Buffer, size_t utf8Size); +int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, + size_t utf16Size); + +#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS diff --git a/include/uv.h b/include/uv.h new file mode 100644 index 0000000000..4eeade74c4 --- /dev/null +++ b/include/uv.h @@ -0,0 +1,2135 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* See http://nikhilm.github.com/uvbook/ for an introduction. */ + +#ifndef UV_H +#define UV_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 + /* Windows - set up dll import/export decorators. */ +# if defined(BUILDING_UV_SHARED) + /* Building shared library. */ +# define UV_EXTERN __declspec(dllexport) +# elif defined(USING_UV_SHARED) + /* Using shared library. */ +# define UV_EXTERN __declspec(dllimport) +# else + /* Building static library. */ +# define UV_EXTERN /* nothing */ +# endif +#elif __GNUC__ >= 4 +# define UV_EXTERN __attribute__((visibility("default"))) +#else +# define UV_EXTERN /* nothing */ +#endif + +#include "uv-errno.h" +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if defined(_WIN32) +# include "uv-win.h" +#else +# include "uv-unix.h" +#endif + +/* Expand this list if necessary. */ +#define UV_ERRNO_MAP(XX) \ + XX(E2BIG, "argument list too long") \ + XX(EACCES, "permission denied") \ + XX(EADDRINUSE, "address already in use") \ + XX(EADDRNOTAVAIL, "address not available") \ + XX(EAFNOSUPPORT, "address family not supported") \ + XX(EAGAIN, "resource temporarily unavailable") \ + XX(EAI_ADDRFAMILY, "address family not supported") \ + XX(EAI_AGAIN, "temporary failure") \ + XX(EAI_BADFLAGS, "bad ai_flags value") \ + XX(EAI_BADHINTS, "invalid value for hints") \ + XX(EAI_CANCELED, "request canceled") \ + XX(EAI_FAIL, "permanent failure") \ + XX(EAI_FAMILY, "ai_family not supported") \ + XX(EAI_MEMORY, "out of memory") \ + XX(EAI_NODATA, "no address") \ + XX(EAI_NONAME, "unknown node or service") \ + XX(EAI_OVERFLOW, "argument buffer overflow") \ + XX(EAI_PROTOCOL, "resolved protocol is unknown") \ + XX(EAI_SERVICE, "service not available for socket type") \ + XX(EAI_SOCKTYPE, "socket type not supported") \ + XX(EAI_SYSTEM, "system error") \ + XX(EALREADY, "connection already in progress") \ + XX(EBADF, "bad file descriptor") \ + XX(EBUSY, "resource busy or locked") \ + XX(ECANCELED, "operation canceled") \ + XX(ECHARSET, "invalid Unicode character") \ + XX(ECONNABORTED, "software caused connection abort") \ + XX(ECONNREFUSED, "connection refused") \ + XX(ECONNRESET, "connection reset by peer") \ + XX(EDESTADDRREQ, "destination address required") \ + XX(EEXIST, "file already exists") \ + XX(EFAULT, "bad address in system call argument") \ + XX(EHOSTUNREACH, "host is unreachable") \ + XX(EINTR, "interrupted system call") \ + XX(EINVAL, "invalid argument") \ + XX(EIO, "i/o error") \ + XX(EISCONN, "socket is already connected") \ + XX(EISDIR, "illegal operation on a directory") \ + XX(ELOOP, "too many symbolic links encountered") \ + XX(EMFILE, "too many open files") \ + XX(EMSGSIZE, "message too long") \ + XX(ENAMETOOLONG, "name too long") \ + XX(ENETDOWN, "network is down") \ + XX(ENETUNREACH, "network is unreachable") \ + XX(ENFILE, "file table overflow") \ + XX(ENOBUFS, "no buffer space available") \ + XX(ENODEV, "no such device") \ + XX(ENOENT, "no such file or directory") \ + XX(ENOMEM, "not enough memory") \ + XX(ENONET, "machine is not on the network") \ + XX(ENOSPC, "no space left on device") \ + XX(ENOSYS, "function not implemented") \ + XX(ENOTCONN, "socket is not connected") \ + XX(ENOTDIR, "not a directory") \ + XX(ENOTEMPTY, "directory not empty") \ + XX(ENOTSOCK, "socket operation on non-socket") \ + XX(ENOTSUP, "operation not supported on socket") \ + XX(EPERM, "operation not permitted") \ + XX(EPIPE, "broken pipe") \ + XX(EPROTO, "protocol error") \ + XX(EPROTONOSUPPORT, "protocol not supported") \ + XX(EPROTOTYPE, "protocol wrong type for socket") \ + XX(EROFS, "read-only file system") \ + XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \ + XX(ESPIPE, "invalid seek") \ + XX(ESRCH, "no such process") \ + XX(ETIMEDOUT, "connection timed out") \ + XX(EXDEV, "cross-device link not permitted") \ + XX(UNKNOWN, "unknown error") \ + XX(EOF, "end of file") \ + +#define UV_HANDLE_TYPE_MAP(XX) \ + XX(ASYNC, async) \ + XX(CHECK, check) \ + XX(FS_EVENT, fs_event) \ + XX(FS_POLL, fs_poll) \ + XX(HANDLE, handle) \ + XX(IDLE, idle) \ + XX(NAMED_PIPE, pipe) \ + XX(POLL, poll) \ + XX(PREPARE, prepare) \ + XX(PROCESS, process) \ + XX(STREAM, stream) \ + XX(TCP, tcp) \ + XX(TIMER, timer) \ + XX(TTY, tty) \ + XX(UDP, udp) \ + XX(SIGNAL, signal) \ + +#define UV_REQ_TYPE_MAP(XX) \ + XX(REQ, req) \ + XX(CONNECT, connect) \ + XX(WRITE, write) \ + XX(SHUTDOWN, shutdown) \ + XX(UDP_SEND, udp_send) \ + XX(FS, fs) \ + XX(WORK, work) \ + XX(GETADDRINFO, getaddrinfo) \ + +typedef enum { +#define XX(code, _) UV_ ## code = UV__ ## code, + UV_ERRNO_MAP(XX) +#undef XX + UV_ERRNO_MAX = UV__EOF - 1 +} uv_errno_t; + +typedef enum { + UV_UNKNOWN_HANDLE = 0, +#define XX(uc, lc) UV_##uc, + UV_HANDLE_TYPE_MAP(XX) +#undef XX + UV_FILE, + UV_HANDLE_TYPE_MAX +} uv_handle_type; + +typedef enum { + UV_UNKNOWN_REQ = 0, +#define XX(uc, lc) UV_##uc, + UV_REQ_TYPE_MAP(XX) +#undef XX + UV_REQ_TYPE_PRIVATE + UV_REQ_TYPE_MAX +} uv_req_type; + + +/* Handle types. */ +typedef struct uv_loop_s uv_loop_t; +typedef struct uv_handle_s uv_handle_t; +typedef struct uv_stream_s uv_stream_t; +typedef struct uv_tcp_s uv_tcp_t; +typedef struct uv_udp_s uv_udp_t; +typedef struct uv_pipe_s uv_pipe_t; +typedef struct uv_tty_s uv_tty_t; +typedef struct uv_poll_s uv_poll_t; +typedef struct uv_timer_s uv_timer_t; +typedef struct uv_prepare_s uv_prepare_t; +typedef struct uv_check_s uv_check_t; +typedef struct uv_idle_s uv_idle_t; +typedef struct uv_async_s uv_async_t; +typedef struct uv_process_s uv_process_t; +typedef struct uv_fs_event_s uv_fs_event_t; +typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; + +/* Request types. */ +typedef struct uv_req_s uv_req_t; +typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; +typedef struct uv_shutdown_s uv_shutdown_t; +typedef struct uv_write_s uv_write_t; +typedef struct uv_connect_s uv_connect_t; +typedef struct uv_udp_send_s uv_udp_send_t; +typedef struct uv_fs_s uv_fs_t; +typedef struct uv_work_s uv_work_t; + +/* None of the above. */ +typedef struct uv_cpu_info_s uv_cpu_info_t; +typedef struct uv_interface_address_s uv_interface_address_t; + + +typedef enum { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE, + UV_RUN_NOWAIT +} uv_run_mode; + + +/* + * Returns the libuv version packed into a single integer. 8 bits are used for + * each component, with the patch number stored in the 8 least significant + * bits. E.g. for libuv 1.2.3 this would return 0x010203. + */ +UV_EXTERN unsigned int uv_version(void); + +/* + * Returns the libuv version number as a string. For non-release versions + * "-pre" is appended, so the version number could be "1.2.3-pre". + */ +UV_EXTERN const char* uv_version_string(void); + + +/* + * This function must be called before any other functions in libuv. + * + * All functions besides uv_run() are non-blocking. + * + * All callbacks in libuv are made asynchronously. That is they are never + * made by the function that takes them as a parameter. + */ +UV_EXTERN uv_loop_t* uv_loop_new(void); +UV_EXTERN void uv_loop_delete(uv_loop_t*); + +/* + * Returns the default loop. + */ +UV_EXTERN uv_loop_t* uv_default_loop(void); + +/* + * This function runs the event loop. It will act differently depending on the + * specified mode: + * - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to + * zero. Always returns zero. + * - UV_RUN_ONCE: Poll for new events once. Note that this function blocks if + * there are no pending events. Returns zero when done (no active handles + * or requests left), or non-zero if more events are expected (meaning you + * should run the event loop again sometime in the future). + * - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no + * pending events. + */ +UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); + +/* + * This function checks whether the reference count, the number of active + * handles or requests left in the event loop, is non-zero. + */ +UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); + +/* + * This function will stop the event loop by forcing uv_run to end + * as soon as possible, but not sooner than the next loop iteration. + * If this function was called before blocking for i/o, the loop won't + * block for i/o on this iteration. + */ +UV_EXTERN void uv_stop(uv_loop_t*); + +/* + * Manually modify the event loop's reference count. Useful if the user wants + * to have a handle or timeout that doesn't keep the loop alive. + */ +UV_EXTERN void uv_ref(uv_handle_t*); +UV_EXTERN void uv_unref(uv_handle_t*); +UV_EXTERN int uv_has_ref(const uv_handle_t*); + +/* + * Update the event loop's concept of "now". Libuv caches the current time + * at the start of the event loop tick in order to reduce the number of + * time-related system calls. + * + * You won't normally need to call this function unless you have callbacks + * that block the event loop for longer periods of time, where "longer" is + * somewhat subjective but probably on the order of a millisecond or more. + */ +UV_EXTERN void uv_update_time(uv_loop_t*); + +/* + * Return the current timestamp in milliseconds. The timestamp is cached at + * the start of the event loop tick, see |uv_update_time()| for details and + * rationale. + * + * The timestamp increases monotonically from some arbitrary point in time. + * Don't make assumptions about the starting point, you will only get + * disappointed. + * + * Use uv_hrtime() if you need sub-millisecond granularity. + */ +UV_EXTERN uint64_t uv_now(uv_loop_t*); + +/* + * Get backend file descriptor. Only kqueue, epoll and event ports are + * supported. + * + * This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to + * poll in one thread and run the event loop's event callbacks in another. + * + * Useful for embedding libuv's event loop in another event loop. + * See test/test-embed.c for an example. + * + * Note that embedding a kqueue fd in another kqueue pollset doesn't work on + * all platforms. It's not an error to add the fd but it never generates + * events. + */ +UV_EXTERN int uv_backend_fd(const uv_loop_t*); + +/* + * Get the poll timeout. The return value is in milliseconds, or -1 for no + * timeout. + */ +UV_EXTERN int uv_backend_timeout(const uv_loop_t*); + + +/* + * Should prepare a buffer that libuv can use to read data into. + * + * `suggested_size` is a hint. Returning a buffer that is smaller is perfectly + * okay as long as `buf.len > 0`. + * + * If you return a buffer with `buf.len == 0`, libuv skips the read and calls + * your read or recv callback with nread=UV_ENOBUFS. + * + * Note that returning a zero-length buffer does not stop the handle, call + * uv_read_stop() or uv_udp_recv_stop() for that. + */ +typedef void (*uv_alloc_cb)(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); + +/* + * `nread` is > 0 if there is data available, 0 if libuv is done reading for + * now, or < 0 on error. + * + * The callee is responsible for closing the stream when an error happens. + * Trying to read from the stream again is undefined. + * + * The callee is responsible for freeing the buffer, libuv does not reuse it. + * The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on + * EOF or error. + */ +typedef void (*uv_read_cb)(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf); + +/* + * Just like the uv_read_cb except that if the pending parameter is true + * then you can use uv_accept() to pull the new handle into the process. + * If no handle is pending then pending will be UV_UNKNOWN_HANDLE. + */ +typedef void (*uv_read2_cb)(uv_pipe_t* pipe, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type pending); + +typedef void (*uv_write_cb)(uv_write_t* req, int status); +typedef void (*uv_connect_cb)(uv_connect_t* req, int status); +typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); +typedef void (*uv_connection_cb)(uv_stream_t* server, int status); +typedef void (*uv_close_cb)(uv_handle_t* handle); +typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events); +typedef void (*uv_timer_cb)(uv_timer_t* handle, int status); +/* TODO: do these really need a status argument? */ +typedef void (*uv_async_cb)(uv_async_t* handle, int status); +typedef void (*uv_prepare_cb)(uv_prepare_t* handle, int status); +typedef void (*uv_check_cb)(uv_check_t* handle, int status); +typedef void (*uv_idle_cb)(uv_idle_t* handle, int status); +typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal); +typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg); +typedef void (*uv_fs_cb)(uv_fs_t* req); +typedef void (*uv_work_cb)(uv_work_t* req); +typedef void (*uv_after_work_cb)(uv_work_t* req, int status); +typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res); + +typedef struct { + long tv_sec; + long tv_nsec; +} uv_timespec_t; + + +typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_flags; + uint64_t st_gen; + uv_timespec_t st_atim; + uv_timespec_t st_mtim; + uv_timespec_t st_ctim; + uv_timespec_t st_birthtim; +} uv_stat_t; + + +/* +* This will be called repeatedly after the uv_fs_event_t is initialized. +* If uv_fs_event_t was initialized with a directory the filename parameter +* will be a relative path to a file contained in the directory. +* The events parameter is an ORed mask of enum uv_fs_event elements. +*/ +typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, + int events, int status); + +typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr); + +typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum); + + +typedef enum { + UV_LEAVE_GROUP = 0, + UV_JOIN_GROUP +} uv_membership; + + +/* + * Most functions return 0 on success or an error code < 0 on failure. + */ +UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN const char* uv_err_name(int err); + + +#define UV_REQ_FIELDS \ + /* public */ \ + void* data; \ + /* read-only */ \ + uv_req_type type; \ + /* private */ \ + void* active_queue[2]; \ + UV_REQ_PRIVATE_FIELDS \ + +/* Abstract base class of all requests. */ +struct uv_req_s { + UV_REQ_FIELDS +}; + + +/* Platform-specific request types */ +UV_PRIVATE_REQ_TYPES + + +/* + * uv_shutdown_t is a subclass of uv_req_t + * + * Shutdown the outgoing (write) side of a duplex stream. It waits for + * pending write requests to complete. The handle should refer to a + * initialized stream. req should be an uninitialized shutdown request + * struct. The cb is called after shutdown is complete. + */ +UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, + uv_shutdown_cb cb); + +struct uv_shutdown_s { + UV_REQ_FIELDS + uv_stream_t* handle; + uv_shutdown_cb cb; + UV_SHUTDOWN_PRIVATE_FIELDS +}; + + +#define UV_HANDLE_FIELDS \ + /* public */ \ + uv_close_cb close_cb; \ + void* data; \ + /* read-only */ \ + uv_loop_t* loop; \ + uv_handle_type type; \ + /* private */ \ + void* handle_queue[2]; \ + UV_HANDLE_PRIVATE_FIELDS \ + +/* The abstract base class of all handles. */ +struct uv_handle_s { + UV_HANDLE_FIELDS +}; + +/* + * Returns size of various handle types, useful for FFI + * bindings to allocate correct memory without copying struct + * definitions + */ +UV_EXTERN size_t uv_handle_size(uv_handle_type type); + +/* + * Returns size of request types, useful for dynamic lookup with FFI + */ +UV_EXTERN size_t uv_req_size(uv_req_type type); + +/* + * Returns non-zero if the handle is active, zero if it's inactive. + * + * What "active" means depends on the type of handle: + * + * - A uv_async_t handle is always active and cannot be deactivated, except + * by closing it with uv_close(). + * + * - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that + * deals with I/O - is active when it is doing something that involves I/O, + * like reading, writing, connecting, accepting new connections, etc. + * + * - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has + * been started with a call to uv_check_start(), uv_idle_start(), etc. + * + * Rule of thumb: if a handle of type uv_foo_t has a uv_foo_start() + * function, then it's active from the moment that function is called. + * Likewise, uv_foo_stop() deactivates the handle again. + * + */ +UV_EXTERN int uv_is_active(const uv_handle_t* handle); + +/* + * Walk the list of open handles. + */ +UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); + + +/* + * Request handle to be closed. close_cb will be called asynchronously after + * this call. This MUST be called on each handle before memory is released. + * + * Note that handles that wrap file descriptors are closed immediately but + * close_cb will still be deferred to the next iteration of the event loop. + * It gives you a chance to free up any resources associated with the handle. + * + * In-progress requests, like uv_connect_t or uv_write_t, are cancelled and + * have their callbacks called asynchronously with status=UV_ECANCELED. + */ +UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); + + +/* + * Constructor for uv_buf_t. + * Due to platform differences the user cannot rely on the ordering of the + * base and len members of the uv_buf_t struct. The user is responsible for + * freeing base after the uv_buf_t is done. Return struct passed by value. + */ +UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); + + +#define UV_STREAM_FIELDS \ + /* number of bytes queued for writing */ \ + size_t write_queue_size; \ + uv_alloc_cb alloc_cb; \ + uv_read_cb read_cb; \ + uv_read2_cb read2_cb; \ + /* private */ \ + UV_STREAM_PRIVATE_FIELDS + +/* + * uv_stream_t is a subclass of uv_handle_t + * + * uv_stream is an abstract class. + * + * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t, and + * soon uv_file_t. + */ +struct uv_stream_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS +}; + +UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); + +/* + * This call is used in conjunction with uv_listen() to accept incoming + * connections. Call uv_accept after receiving a uv_connection_cb to accept + * the connection. Before calling uv_accept use uv_*_init() must be + * called on the client. Non-zero return value indicates an error. + * + * When the uv_connection_cb is called it is guaranteed that uv_accept will + * complete successfully the first time. If you attempt to use it more than + * once, it may fail. It is suggested to only call uv_accept once per + * uv_connection_cb call. + */ +UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); + +/* + * Read data from an incoming stream. The callback will be made several + * times until there is no more data to read or uv_read_stop is called. + * When we've reached EOF nread will be set to UV_EOF. + * + * When nread < 0, the buf parameter might not point to a valid buffer; + * in that case buf.len and buf.base are both set to 0. + * + * Note that nread might also be 0, which does *not* indicate an error or + * eof; it happens when libuv requested a buffer through the alloc callback + * but then decided that it didn't need that buffer. + */ +UV_EXTERN int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); + +UV_EXTERN int uv_read_stop(uv_stream_t*); + +/* + * Extended read methods for receiving handles over a pipe. The pipe must be + * initialized with ipc == 1. + */ +UV_EXTERN int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb, + uv_read2_cb read_cb); + + +/* + * Write data to stream. Buffers are written in order. Example: + * + * uv_buf_t a[] = { + * { .base = "1", .len = 1 }, + * { .base = "2", .len = 1 } + * }; + * + * uv_buf_t b[] = { + * { .base = "3", .len = 1 }, + * { .base = "4", .len = 1 } + * }; + * + * uv_write_t req1; + * uv_write_t req2; + * + * // writes "1234" + * uv_write(&req1, stream, a, 2); + * uv_write(&req2, stream, b, 2); + * + */ +UV_EXTERN int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb); + +/* + * Extended write function for sending handles over a pipe. The pipe must be + * initialized with ipc == 1. + * send_handle must be a TCP socket or pipe, which is a server or a connection + * (listening or connected state). Bound sockets or pipes will be assumed to + * be servers. + */ +UV_EXTERN int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb); + +/* + * Same as `uv_write()`, but won't queue write request if it can't be completed + * immediately. + * Will return either: + * - positive number of bytes written + * - zero - if queued write is needed + * - negative error code + */ +UV_EXTERN int uv_try_write(uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs); + +/* uv_write_t is a subclass of uv_req_t */ +struct uv_write_s { + UV_REQ_FIELDS + uv_write_cb cb; + uv_stream_t* send_handle; + uv_stream_t* handle; + UV_WRITE_PRIVATE_FIELDS +}; + + +/* + * Used to determine whether a stream is readable or writable. + */ +UV_EXTERN int uv_is_readable(const uv_stream_t* handle); +UV_EXTERN int uv_is_writable(const uv_stream_t* handle); + + +/* + * Enable or disable blocking mode for a stream. + * + * When blocking mode is enabled all writes complete synchronously. The + * interface remains unchanged otherwise, e.g. completion or failure of the + * operation will still be reported through a callback which is made + * asychronously. + * + * Relying too much on this API is not recommended. It is likely to change + * significantly in the future. + * + * On windows this currently works only for uv_pipe_t instances. On unix it + * works for tcp, pipe and tty instances. Be aware that changing the blocking + * mode on unix sets or clears the O_NONBLOCK bit. If you are sharing a handle + * with another process, the other process is affected by the change too, + * which can lead to unexpected results. + * + * Also libuv currently makes no ordering guarantee when the blocking mode + * is changed after write requests have already been submitted. Therefore it is + * recommended to set the blocking mode immediately after opening or creating + * the stream. + */ +UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking); + + +/* + * Used to determine whether a stream is closing or closed. + * + * N.B. is only valid between the initialization of the handle + * and the arrival of the close callback, and cannot be used + * to validate the handle. + */ +UV_EXTERN int uv_is_closing(const uv_handle_t* handle); + + +/* + * uv_tcp_t is a subclass of uv_stream_t + * + * Represents a TCP stream or TCP server. + */ +struct uv_tcp_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TCP_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle); + +/* + * Opens an existing file descriptor or SOCKET as a tcp handle. + */ +UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock); + +/* Enable/disable Nagle's algorithm. */ +UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); + +/* + * Enable/disable TCP keep-alive. + * + * `delay` is the initial delay in seconds, ignored when `enable` is zero. + */ +UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, + int enable, + unsigned int delay); + +/* + * Enable/disable simultaneous asynchronous accept requests that are + * queued by the operating system when listening for new tcp connections. + * This setting is used to tune a tcp server for the desired performance. + * Having simultaneous accepts can significantly improve the rate of + * accepting connections (which is why it is enabled by default) but + * may lead to uneven load distribution in multi-process setups. + */ +UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); + +enum uv_tcp_flags { + /* Used with uv_tcp_bind, when an IPv6 address is used */ + UV_TCP_IPV6ONLY = 1 +}; + +/* + * Bind the handle to an address and port. `addr` should point to an + * initialized struct sockaddr_in or struct sockaddr_in6. + * + * When the port is already taken, you can expect to see an UV_EADDRINUSE + * error from either uv_tcp_bind(), uv_listen() or uv_tcp_connect(). + * + * That is, a successful call to uv_tcp_bind() does not guarantee that + * the call to uv_listen() or uv_tcp_connect() will succeed as well. + */ +UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags); +UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, + int* namelen); +UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, + int* namelen); + +/* + * Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle + * and an uninitialized uv_connect_t*. `addr` should point to an initialized + * struct sockaddr_in or struct sockaddr_in6. + * + * The callback is made when the connection has been established or when a + * connection error happened. + */ +UV_EXTERN int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb); + +/* uv_connect_t is a subclass of uv_req_t */ +struct uv_connect_s { + UV_REQ_FIELDS + uv_connect_cb cb; + uv_stream_t* handle; + UV_CONNECT_PRIVATE_FIELDS +}; + + +/* + * UDP support. + */ + +enum uv_udp_flags { + /* Disables dual stack mode. */ + UV_UDP_IPV6ONLY = 1, + /* + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ + UV_UDP_PARTIAL = 2 +}; + +/* + * Called after a uv_udp_send() or uv_udp_send6(). status 0 indicates + * success otherwise error. + */ +typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); + +/* + * Callback that is invoked when a new UDP datagram is received. + * + * handle UDP handle. + * nread Number of bytes that have been received. + * 0 if there is no more data to read. You may + * discard or repurpose the read buffer. + * < 0 if a transmission error was detected. + * buf uv_buf_t with the received data. + * addr struct sockaddr_in or struct sockaddr_in6. + * Valid for the duration of the callback only. + * flags One or more OR'ed UV_UDP_* constants. + * Right now only UV_UDP_PARTIAL is used. + */ +typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags); + +/* uv_udp_t is a subclass of uv_handle_t */ +struct uv_udp_s { + UV_HANDLE_FIELDS + UV_UDP_PRIVATE_FIELDS +}; + +/* uv_udp_send_t is a subclass of uv_req_t */ +struct uv_udp_send_s { + UV_REQ_FIELDS + uv_udp_t* handle; + uv_udp_send_cb cb; + UV_UDP_SEND_PRIVATE_FIELDS +}; + +/* + * Initialize a new UDP handle. The actual socket is created lazily. + * Returns 0 on success. + */ +UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); + +/* + * Opens an existing file descriptor or SOCKET as a udp handle. + * + * Unix only: + * The only requirement of the sock argument is that it follows the + * datagram contract (works in unconnected mode, supports sendmsg()/recvmsg(), + * etc.). In other words, other datagram-type sockets like raw sockets or + * netlink sockets can also be passed to this function. + * + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * UNIX platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + * This behavior is something of an anomaly and may be replaced by an explicit + * opt-in mechanism in future versions of libuv. + */ +UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); + +/* + * Bind to a IPv4 address and port. + * + * Arguments: + * handle UDP handle. Should have been initialized with `uv_udp_init`. + * addr struct sockaddr_in or struct sockaddr_in6 with the address and + * port to bind to. + * flags Unused. + * + * Returns: + * 0 on success, or an error code < 0 on failure. + * + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * UNIX platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + * This behavior is something of an anomaly and may be replaced by an explicit + * opt-in mechanism in future versions of libuv. + */ +UV_EXTERN int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags); + +UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, + int* namelen); + +/* + * Set membership for a multicast address + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * multicast_addr multicast address to set membership for + * interface_addr interface address + * membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, const char* interface_addr, + uv_membership membership); + +/* + * Set IP multicast loop flag. Makes multicast packets loop back to + * local sockets. + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * on 1 for on, 0 for off + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); + +/* + * Set the multicast ttl + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * ttl 1 through 255 + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); + +/* + * Set broadcast on or off + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * on 1 for on, 0 for off + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); + +/* + * Set the time to live + * + * Arguments: + * handle UDP handle. Should have been initialized with + * `uv_udp_init`. + * ttl 1 through 255 + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl); + +/* + * Send data. If the socket has not previously been bound with `uv_udp_bind` + * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address) + * and a random port number. + * + * Arguments: + * req UDP request handle. Need not be initialized. + * handle UDP handle. Should have been initialized with `uv_udp_init`. + * bufs List of buffers to send. + * nbufs Number of buffers in `bufs`. + * addr Address of the remote peer. See `uv_ip4_addr`. + * send_cb Callback to invoke when the data has been sent out. + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb); + +/* + * Receive data. If the socket has not previously been bound with `uv_udp_bind` + * or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address) + * and a random port number. + * + * Arguments: + * handle UDP handle. Should have been initialized with `uv_udp_init`. + * alloc_cb Callback to invoke when temporary storage is needed. + * recv_cb Callback to invoke with received data. + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb); + +/* + * Stop listening for incoming datagrams. + * + * Arguments: + * handle UDP handle. Should have been initialized with `uv_udp_init`. + * + * Returns: + * 0 on success, or an error code < 0 on failure. + */ +UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); + + +/* + * uv_tty_t is a subclass of uv_stream_t + * + * Representing a stream for the console. + */ +struct uv_tty_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + UV_TTY_PRIVATE_FIELDS +}; + +/* + * Initialize a new TTY stream with the given file descriptor. Usually the + * file descriptor will be + * 0 = stdin + * 1 = stdout + * 2 = stderr + * The last argument, readable, specifies if you plan on calling + * uv_read_start with this stream. stdin is readable, stdout is not. + * + * TTY streams which are not readable have blocking writes. + */ +UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); + +/* + * Set mode. 0 for normal, 1 for raw. + */ +UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode); + +/* + * To be called when the program exits. Resets TTY settings to default + * values for the next process to take over. + * + * This function is async signal-safe on UNIX platforms but can fail with error + * code UV_EBUSY if you call it when execution is inside uv_tty_set_mode(). + */ +UV_EXTERN int uv_tty_reset_mode(void); + +/* + * Gets the current Window size. On success zero is returned. + */ +UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); + +/* + * Used to detect what type of stream should be used with a given file + * descriptor. Usually this will be used during initialization to guess the + * type of the stdio streams. + * For isatty() functionality use this function and test for UV_TTY. + */ +UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); + +/* + * uv_pipe_t is a subclass of uv_stream_t + * + * Representing a pipe stream or pipe server. On Windows this is a Named + * Pipe. On Unix this is a UNIX domain socket. + */ +struct uv_pipe_s { + UV_HANDLE_FIELDS + UV_STREAM_FIELDS + int ipc; /* non-zero if this pipe is used for passing handles */ + UV_PIPE_PRIVATE_FIELDS +}; + +/* + * Initialize a pipe. The last argument is a boolean to indicate if + * this pipe will be used for handle passing between processes. + */ +UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc); + +/* + * Opens an existing file descriptor or HANDLE as a pipe. + */ +UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); + +/* + * Bind the pipe to a file path (UNIX) or a name (Windows.) + * + * Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, + * typically between 92 and 108 bytes. + */ +UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); + +/* + * Connect to the UNIX domain socket or the named pipe. + * + * Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, + * typically between 92 and 108 bytes. + */ +UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, + const char* name, uv_connect_cb cb); + +/* + * This setting applies to Windows only. + * Set the number of pending pipe instance handles when the pipe server + * is waiting for connections. + */ +UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); + + +/* + * uv_poll_t is a subclass of uv_handle_t. + * + * The uv_poll watcher is used to watch file descriptors for readability and + * writability, similar to the purpose of poll(2). + * + * The purpose of uv_poll is to enable integrating external libraries that + * rely on the event loop to signal it about the socket status changes, like + * c-ares or libssh2. Using uv_poll_t for any other other purpose is not + * recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is + * much faster and more scalable than what can be achieved with uv_poll_t, + * especially on Windows. + * + * It is possible that uv_poll occasionally signals that a file descriptor is + * readable or writable even when it isn't. The user should therefore always + * be prepared to handle EAGAIN or equivalent when it attempts to read from or + * write to the fd. + * + * It is not okay to have multiple active uv_poll watchers for the same socket. + * This can cause libuv to busyloop or otherwise malfunction. + * + * The user should not close a file descriptor while it is being polled by an + * active uv_poll watcher. This can cause the poll watcher to report an error, + * but it might also start polling another socket. However the fd can be safely + * closed immediately after a call to uv_poll_stop() or uv_close(). + * + * On windows only sockets can be polled with uv_poll. On unix any file + * descriptor that would be accepted by poll(2) can be used with uv_poll. + */ +struct uv_poll_s { + UV_HANDLE_FIELDS + uv_poll_cb poll_cb; + UV_POLL_PRIVATE_FIELDS +}; + +enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2 +}; + +/* Initialize the poll watcher using a file descriptor. */ +UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); + +/* Initialize the poll watcher using a socket descriptor. On unix this is */ +/* identical to uv_poll_init. On windows it takes a SOCKET handle. */ +UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket); + +/* + * Starts polling the file descriptor. `events` is a bitmask consisting made up + * of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback + * will be called with `status` set to 0, and the detected events set en the + * `events` field. + * + * If an error happens while polling status, `status` < 0 and corresponds + * with one of the UV_E* error codes. The user should not close the socket + * while uv_poll is active. If the user does that anyway, the callback *may* + * be called reporting an error status, but this is not guaranteed. + * + * Calling uv_poll_start on an uv_poll watcher that is already active is fine. + * Doing so will update the events mask that is being watched for. + */ +UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb); + +/* Stops polling the file descriptor. */ +UV_EXTERN int uv_poll_stop(uv_poll_t* handle); + + +/* + * uv_prepare_t is a subclass of uv_handle_t. + * + * Every active prepare handle gets its callback called exactly once per loop + * iteration, just before the system blocks to wait for completed i/o. + */ +struct uv_prepare_s { + UV_HANDLE_FIELDS + UV_PREPARE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare); + +UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb); + +UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare); + + +/* + * uv_check_t is a subclass of uv_handle_t. + * + * Every active check handle gets its callback called exactly once per loop + * iteration, just after the system returns from blocking. + */ +struct uv_check_s { + UV_HANDLE_FIELDS + UV_CHECK_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check); + +UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb); + +UV_EXTERN int uv_check_stop(uv_check_t* check); + + +/* + * uv_idle_t is a subclass of uv_handle_t. + * + * Every active idle handle gets its callback called repeatedly until it is + * stopped. This happens after all other types of callbacks are processed. + * When there are multiple "idle" handles active, their callbacks are called + * in turn. + */ +struct uv_idle_s { + UV_HANDLE_FIELDS + UV_IDLE_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle); + +UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb); + +UV_EXTERN int uv_idle_stop(uv_idle_t* idle); + + +/* + * uv_async_t is a subclass of uv_handle_t. + * + * uv_async_send wakes up the event loop and calls the async handle's callback. + * There is no guarantee that every uv_async_send call leads to exactly one + * invocation of the callback; the only guarantee is that the callback function + * is called at least once after the call to async_send. Unlike all other + * libuv functions, uv_async_send can be called from another thread. + */ +struct uv_async_s { + UV_HANDLE_FIELDS + UV_ASYNC_PRIVATE_FIELDS +}; + +/* + * Initialize the uv_async_t handle. A NULL callback is allowed. + * + * Note that uv_async_init(), unlike other libuv functions, immediately + * starts the handle. To stop the handle again, close it with uv_close(). + */ +UV_EXTERN int uv_async_init(uv_loop_t*, uv_async_t* async, + uv_async_cb async_cb); + +/* + * This can be called from other threads to wake up a libuv thread. + * + * libuv is single threaded at the moment. + */ +UV_EXTERN int uv_async_send(uv_async_t* async); + + +/* + * uv_timer_t is a subclass of uv_handle_t. + * + * Used to get woken up at a specified time in the future. + */ +struct uv_timer_s { + UV_HANDLE_FIELDS + UV_TIMER_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle); + +/* + * Start the timer. `timeout` and `repeat` are in milliseconds. + * + * If timeout is zero, the callback fires on the next tick of the event loop. + * + * If repeat is non-zero, the callback fires first after timeout milliseconds + * and then repeatedly after repeat milliseconds. + */ +UV_EXTERN int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat); + +UV_EXTERN int uv_timer_stop(uv_timer_t* handle); + +/* + * Stop the timer, and if it is repeating restart it using the repeat value + * as the timeout. If the timer has never been started before it returns + * UV_EINVAL. + */ +UV_EXTERN int uv_timer_again(uv_timer_t* handle); + +/* + * Set the repeat value in milliseconds. Note that if the repeat value is set + * from a timer callback it does not immediately take effect. If the timer was + * non-repeating before, it will have been stopped. If it was repeating, then + * the old repeat value will have been used to schedule the next timeout. + */ +UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat); + +UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); + + +/* + * uv_getaddrinfo_t is a subclass of uv_req_t + * + * Request object for uv_getaddrinfo. + */ +struct uv_getaddrinfo_s { + UV_REQ_FIELDS + /* read-only */ + uv_loop_t* loop; + UV_GETADDRINFO_PRIVATE_FIELDS +}; + + +/* + * Asynchronous getaddrinfo(3). + * + * Either node or service may be NULL but not both. + * + * hints is a pointer to a struct addrinfo with additional address type + * constraints, or NULL. Consult `man -s 3 getaddrinfo` for details. + * + * Returns 0 on success or an error code < 0 on failure. + * + * If successful, your callback gets called sometime in the future with the + * lookup result, which is either: + * + * a) err == 0, the res argument points to a valid struct addrinfo, or + * b) err < 0, the res argument is NULL. See the UV_EAI_* constants. + * + * Call uv_freeaddrinfo() to free the addrinfo structure. + */ +UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints); + +/* + * Free the struct addrinfo. Passing NULL is allowed and is a no-op. + */ +UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai); + + +/* uv_spawn() options */ +typedef enum { + UV_IGNORE = 0x00, + UV_CREATE_PIPE = 0x01, + UV_INHERIT_FD = 0x02, + UV_INHERIT_STREAM = 0x04, + + /* When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE + * determine the direction of flow, from the child process' perspective. Both + * flags may be specified to create a duplex data stream. + */ + UV_READABLE_PIPE = 0x10, + UV_WRITABLE_PIPE = 0x20 +} uv_stdio_flags; + +typedef struct uv_stdio_container_s { + uv_stdio_flags flags; + + union { + uv_stream_t* stream; + int fd; + } data; +} uv_stdio_container_t; + +typedef struct uv_process_options_s { + uv_exit_cb exit_cb; /* Called after the process exits. */ + const char* file; /* Path to program to execute. */ + /* + * Command line arguments. args[0] should be the path to the program. On + * Windows this uses CreateProcess which concatenates the arguments into a + * string this can cause some strange errors. See the note at + * windows_verbatim_arguments. + */ + char** args; + /* + * This will be set as the environ variable in the subprocess. If this is + * NULL then the parents environ will be used. + */ + char** env; + /* + * If non-null this represents a directory the subprocess should execute + * in. Stands for current working directory. + */ + const char* cwd; + /* + * Various flags that control how uv_spawn() behaves. See the definition of + * `enum uv_process_flags` below. + */ + unsigned int flags; + /* + * The `stdio` field points to an array of uv_stdio_container_t structs that + * describe the file descriptors that will be made available to the child + * process. The convention is that stdio[0] points to stdin, fd 1 is used for + * stdout, and fd 2 is stderr. + * + * Note that on windows file descriptors greater than 2 are available to the + * child process only if the child processes uses the MSVCRT runtime. + */ + int stdio_count; + uv_stdio_container_t* stdio; + /* + * Libuv can change the child process' user/group id. This happens only when + * the appropriate bits are set in the flags fields. This is not supported on + * windows; uv_spawn() will fail and set the error to UV_ENOTSUP. + */ + uv_uid_t uid; + uv_gid_t gid; +} uv_process_options_t; + +/* + * These are the flags that can be used for the uv_process_options.flags field. + */ +enum uv_process_flags { + /* + * Set the child process' user id. The user id is supplied in the `uid` field + * of the options struct. This does not work on windows; setting this flag + * will cause uv_spawn() to fail. + */ + UV_PROCESS_SETUID = (1 << 0), + /* + * Set the child process' group id. The user id is supplied in the `gid` + * field of the options struct. This does not work on windows; setting this + * flag will cause uv_spawn() to fail. + */ + UV_PROCESS_SETGID = (1 << 1), + /* + * Do not wrap any arguments in quotes, or perform any other escaping, when + * converting the argument list into a command line string. This option is + * only meaningful on Windows systems. On unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), + /* + * Spawn the child process in a detached state - this will make it a process + * group leader, and will effectively enable the child to keep running after + * the parent exits. Note that the child process will still keep the + * parent's event loop alive unless the parent process calls uv_unref() on + * the child's process handle. + */ + UV_PROCESS_DETACHED = (1 << 3), + /* + * Hide the subprocess console window that would normally be created. This + * option is only meaningful on Windows systems. On unix it is silently + * ignored. + */ + UV_PROCESS_WINDOWS_HIDE = (1 << 4) +}; + +/* + * uv_process_t is a subclass of uv_handle_t + */ +struct uv_process_s { + UV_HANDLE_FIELDS + uv_exit_cb exit_cb; + int pid; + UV_PROCESS_PRIVATE_FIELDS +}; + +/* + * Initializes the uv_process_t and starts the process. If the process is + * successfully spawned, then this function will return 0. Otherwise, the + * negative error code corresponding to the reason it couldn't spawn is + * returned. + * + * Possible reasons for failing to spawn would include (but not be limited to) + * the file to execute not existing, not having permissions to use the setuid or + * setgid specified, or not having enough memory to allocate for the new + * process. + */ +UV_EXTERN int uv_spawn(uv_loop_t* loop, + uv_process_t* handle, + const uv_process_options_t* options); + + +/* + * Kills the process with the specified signal. The user must still + * call uv_close on the process. + */ +UV_EXTERN int uv_process_kill(uv_process_t*, int signum); + + +/* Kills the process with the specified signal. */ +UV_EXTERN int uv_kill(int pid, int signum); + + +/* + * uv_work_t is a subclass of uv_req_t + */ +struct uv_work_s { + UV_REQ_FIELDS + uv_loop_t* loop; + uv_work_cb work_cb; + uv_after_work_cb after_work_cb; + UV_WORK_PRIVATE_FIELDS +}; + +/* Queues a work request to execute asynchronously on the thread pool. */ +UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req, + uv_work_cb work_cb, uv_after_work_cb after_work_cb); + +/* Cancel a pending request. Fails if the request is executing or has finished + * executing. + * + * Returns 0 on success, or an error code < 0 on failure. + * + * Only cancellation of uv_fs_t, uv_getaddrinfo_t and uv_work_t requests is + * currently supported. + * + * Cancelled requests have their callbacks invoked some time in the future. + * It's _not_ safe to free the memory associated with the request until your + * callback is called. + * + * Here is how cancellation is reported to your callback: + * + * - A uv_fs_t request has its req->result field set to UV_ECANCELED. + * + * - A uv_work_t or uv_getaddrinfo_t request has its callback invoked with + * status == UV_ECANCELED. + * + * This function is currently only implemented on UNIX platforms. On Windows, + * it always returns UV_ENOSYS. + */ +UV_EXTERN int uv_cancel(uv_req_t* req); + + +struct uv_cpu_info_s { + char* model; + int speed; + struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; + } cpu_times; +}; + +struct uv_interface_address_s { + char* name; + char phys_addr[6]; + int is_internal; + union { + struct sockaddr_in address4; + struct sockaddr_in6 address6; + } address; + union { + struct sockaddr_in netmask4; + struct sockaddr_in6 netmask6; + } netmask; +}; + +UV_EXTERN char** uv_setup_args(int argc, char** argv); +UV_EXTERN int uv_get_process_title(char* buffer, size_t size); +UV_EXTERN int uv_set_process_title(const char* title); +UV_EXTERN int uv_resident_set_memory(size_t* rss); +UV_EXTERN int uv_uptime(double* uptime); + +/* + * This allocates cpu_infos array, and sets count. The array + * is freed using uv_free_cpu_info(). + */ +UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); +UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); + +/* + * This allocates addresses array, and sets count. The array + * is freed using uv_free_interface_addresses(). + */ +UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, + int* count); +UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count); + +/* + * File System Methods. + * + * The uv_fs_* functions execute a blocking system call asynchronously (in a + * thread pool) and call the specified callback in the specified loop after + * completion. If the user gives NULL as the callback the blocking system + * call will be called synchronously. req should be a pointer to an + * uninitialized uv_fs_t object. + * + * uv_fs_req_cleanup() must be called after completion of the uv_fs_ + * function to free any internal memory allocations associated with the + * request. + */ + +typedef enum { + UV_FS_UNKNOWN = -1, + UV_FS_CUSTOM, + UV_FS_OPEN, + UV_FS_CLOSE, + UV_FS_READ, + UV_FS_WRITE, + UV_FS_SENDFILE, + UV_FS_STAT, + UV_FS_LSTAT, + UV_FS_FSTAT, + UV_FS_FTRUNCATE, + UV_FS_UTIME, + UV_FS_FUTIME, + UV_FS_CHMOD, + UV_FS_FCHMOD, + UV_FS_FSYNC, + UV_FS_FDATASYNC, + UV_FS_UNLINK, + UV_FS_RMDIR, + UV_FS_MKDIR, + UV_FS_RENAME, + UV_FS_READDIR, + UV_FS_LINK, + UV_FS_SYMLINK, + UV_FS_READLINK, + UV_FS_CHOWN, + UV_FS_FCHOWN +} uv_fs_type; + +/* uv_fs_t is a subclass of uv_req_t */ +struct uv_fs_s { + UV_REQ_FIELDS + uv_fs_type fs_type; + uv_loop_t* loop; + uv_fs_cb cb; + ssize_t result; + void* ptr; + const char* path; + uv_stat_t statbuf; /* Stores the result of uv_fs_stat and uv_fs_fstat. */ + UV_FS_PRIVATE_FIELDS +}; + +UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req); + +UV_EXTERN int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, + int flags, int mode, uv_fs_cb cb); + +UV_EXTERN int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, + void* buf, size_t length, int64_t offset, uv_fs_cb cb); + +UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, + const void* buf, size_t length, int64_t offset, uv_fs_cb cb); + +UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, + int mode, uv_fs_cb cb); + +UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, + const char* path, int flags, uv_fs_cb cb); + +UV_EXTERN int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb); + +UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, + int64_t offset, uv_fs_cb cb); + +UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, + uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb); + +UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, + int mode, uv_fs_cb cb); + +UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, + double atime, double mtime, uv_fs_cb cb); + +UV_EXTERN int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, + double atime, double mtime, uv_fs_cb cb); + +UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb); + +/* + * This flag can be used with uv_fs_symlink on Windows + * to specify whether path argument points to a directory. + */ +#define UV_FS_SYMLINK_DIR 0x0001 + +/* + * This flag can be used with uv_fs_symlink on Windows + * to specify whether the symlink is to be created using junction points. + */ +#define UV_FS_SYMLINK_JUNCTION 0x0002 + +UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, int flags, uv_fs_cb cb); + +UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb); + +UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, + int mode, uv_fs_cb cb); + +UV_EXTERN int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); + +UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, + uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); + + +enum uv_fs_event { + UV_RENAME = 1, + UV_CHANGE = 2 +}; + + +struct uv_fs_event_s { + UV_HANDLE_FIELDS + char* filename; + UV_FS_EVENT_PRIVATE_FIELDS +}; + + +/* + * uv_fs_stat() based polling file watcher. + */ +struct uv_fs_poll_s { + UV_HANDLE_FIELDS + /* Private, don't touch. */ + void* poll_ctx; +}; + +UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle); + +/* + * Check the file at `path` for changes every `interval` milliseconds. + * + * Your callback is invoked with `status < 0` if `path` does not exist + * or is inaccessible. The watcher is *not* stopped but your callback is + * not called again until something changes (e.g. when the file is created + * or the error reason changes). + * + * When `status == 0`, your callback receives pointers to the old and new + * `uv_stat_t` structs. They are valid for the duration of the callback + * only! + * + * For maximum portability, use multi-second intervals. Sub-second intervals + * will not detect all changes on many file systems. + */ +UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb poll_cb, + const char* path, + unsigned int interval); + +UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); + + +/* + * UNIX signal handling on a per-event loop basis. The implementation is not + * ultra efficient so don't go creating a million event loops with a million + * signal watchers. + * + * Note to Linux users: SIGRT0 and SIGRT1 (signals 32 and 33) are used by the + * NPTL pthreads library to manage threads. Installing watchers for those + * signals will lead to unpredictable behavior and is strongly discouraged. + * Future versions of libuv may simply reject them. + * + * Some signal support is available on Windows: + * + * SIGINT is normally delivered when the user presses CTRL+C. However, like + * on Unix, it is not generated when terminal raw mode is enabled. + * + * SIGBREAK is delivered when the user pressed CTRL+BREAK. + * + * SIGHUP is generated when the user closes the console window. On SIGHUP the + * program is given approximately 10 seconds to perform cleanup. After that + * Windows will unconditionally terminate it. + * + * SIGWINCH is raised whenever libuv detects that the console has been + * resized. SIGWINCH is emulated by libuv when the program uses an uv_tty_t + * handle to write to the console. SIGWINCH may not always be delivered in a + * timely manner; libuv will only detect size changes when the cursor is + * being moved. When a readable uv_tty_handle is used in raw mode, resizing + * the console buffer will also trigger a SIGWINCH signal. + * + * Watchers for other signals can be successfully created, but these signals + * are never generated. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV, + * SIGTERM and SIGKILL. + * + * Note that calls to raise() or abort() to programmatically raise a signal are + * not detected by libuv; these will not trigger a signal watcher. + */ +struct uv_signal_s { + UV_HANDLE_FIELDS + uv_signal_cb signal_cb; + int signum; + UV_SIGNAL_PRIVATE_FIELDS +}; + +UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); + +UV_EXTERN int uv_signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum); + +UV_EXTERN int uv_signal_stop(uv_signal_t* handle); + + +/* + * Gets load average. + * See: http://en.wikipedia.org/wiki/Load_(computing) + * Returns [0,0,0] on Windows. + */ +UV_EXTERN void uv_loadavg(double avg[3]); + + +/* + * Flags to be passed to uv_fs_event_start. + */ +enum uv_fs_event_flags { + /* + * By default, if the fs event watcher is given a directory name, we will + * watch for all events in that directory. This flags overrides this behavior + * and makes fs_event report only changes to the directory entry itself. This + * flag does not affect individual files watched. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_WATCH_ENTRY = 1, + + /* + * By default uv_fs_event will try to use a kernel interface such as inotify + * or kqueue to detect events. This may not work on remote filesystems such + * as NFS mounts. This flag makes fs_event fall back to calling stat() on a + * regular interval. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_STAT = 2, + + /* + * By default, event watcher, when watching directory, is not registering + * (is ignoring) changes in it's subdirectories. + * This flag will override this behaviour on platforms that support it. + */ + UV_FS_EVENT_RECURSIVE = 4 +}; + + +UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle); + +UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags); + +UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle); + + +/* Utility */ + +/* Convert string ip addresses to binary structures */ +UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr); +UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr); + +/* Convert binary addresses to strings */ +UV_EXTERN int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size); +UV_EXTERN int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size); + +/* Cross-platform IPv6-capable implementation of the 'standard' inet_ntop */ +/* and inet_pton functions. On success they return 0. If an error */ +/* the target of the `dst` pointer is unmodified. */ +UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); +UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); + +/* Gets the executable path */ +UV_EXTERN int uv_exepath(char* buffer, size_t* size); + +/* Gets the current working directory */ +UV_EXTERN int uv_cwd(char* buffer, size_t size); + +/* Changes the current working directory */ +UV_EXTERN int uv_chdir(const char* dir); + +/* Gets memory info in bytes */ +UV_EXTERN uint64_t uv_get_free_memory(void); +UV_EXTERN uint64_t uv_get_total_memory(void); + +/* + * Returns the current high-resolution real time. This is expressed in + * nanoseconds. It is relative to an arbitrary time in the past. It is not + * related to the time of day and therefore not subject to clock drift. The + * primary use is for measuring performance between intervals. + * + * Note not every platform can support nanosecond resolution; however, this + * value will always be in nanoseconds. + */ +UV_EXTERN extern uint64_t uv_hrtime(void); + + +/* + * Disables inheritance for file descriptors / handles that this process + * inherited from its parent. The effect is that child processes spawned by + * this process don't accidentally inherit these handles. + * + * It is recommended to call this function as early in your program as possible, + * before the inherited file descriptors can be closed or duplicated. + * + * Note that this function works on a best-effort basis: there is no guarantee + * that libuv can discover all file descriptors that were inherited. In general + * it does a better job on Windows than it does on unix. + */ +UV_EXTERN void uv_disable_stdio_inheritance(void); + +/* + * Opens a shared library. The filename is in utf-8. Returns 0 on success and + * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message. + */ +UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); + +/* + * Close the shared library. + */ +UV_EXTERN void uv_dlclose(uv_lib_t* lib); + +/* + * Retrieves a data pointer from a dynamic library. It is legal for a symbol to + * map to NULL. Returns 0 on success and -1 if the symbol was not found. + */ +UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); + +/* + * Returns the last uv_dlopen() or uv_dlsym() error message. + */ +UV_EXTERN const char* uv_dlerror(uv_lib_t* lib); + +/* + * The mutex functions return 0 on success or an error code < 0 + * (unless the return type is void, of course). + */ +UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); +UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle); + +/* + * Same goes for the read/write lock functions. + */ +UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); + +/* + * Same goes for the semaphore functions. + */ +UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); +UV_EXTERN void uv_sem_destroy(uv_sem_t* sem); +UV_EXTERN void uv_sem_post(uv_sem_t* sem); +UV_EXTERN void uv_sem_wait(uv_sem_t* sem); +UV_EXTERN int uv_sem_trywait(uv_sem_t* sem); + +/* + * Same goes for the condition variable functions. + */ +UV_EXTERN int uv_cond_init(uv_cond_t* cond); +UV_EXTERN void uv_cond_destroy(uv_cond_t* cond); +UV_EXTERN void uv_cond_signal(uv_cond_t* cond); +UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond); +/* Waits on a condition variable without a timeout. + * + * Note: + * 1. callers should be prepared to deal with spurious wakeups. + */ +UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex); +/* Waits on a condition variable with a timeout in nano seconds. + * Returns 0 for success or UV_ETIMEDOUT on timeout, It aborts when other + * errors happen. + * + * Note: + * 1. callers should be prepared to deal with spurious wakeups. + * 2. the granularity of timeout on Windows is never less than one millisecond. + * 3. uv_cond_timedwait takes a relative timeout, not an absolute time. + */ +UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, + uint64_t timeout); + +UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count); +UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier); +UV_EXTERN void uv_barrier_wait(uv_barrier_t* barrier); + +/* Runs a function once and only once. Concurrent calls to uv_once() with the + * same guard will block all callers except one (it's unspecified which one). + * The guard should be initialized statically with the UV_ONCE_INIT macro. + */ +UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); + +/* Thread-local storage. These functions largely follow the semantics of + * pthread_key_create(), pthread_key_delete(), pthread_getspecific() and + * pthread_setspecific(). + * + * Note that the total thread-local storage size may be limited. + * That is, it may not be possible to create many TLS keys. + */ +UV_EXTERN int uv_key_create(uv_key_t* key); +UV_EXTERN void uv_key_delete(uv_key_t* key); +UV_EXTERN void* uv_key_get(uv_key_t* key); +UV_EXTERN void uv_key_set(uv_key_t* key, void* value); + +UV_EXTERN int uv_thread_create(uv_thread_t *tid, + void (*entry)(void *arg), void *arg); +UV_EXTERN unsigned long uv_thread_self(void); +UV_EXTERN int uv_thread_join(uv_thread_t *tid); + +/* The presence of these unions force similar struct layout. */ +#define XX(_, name) uv_ ## name ## _t name; +union uv_any_handle { + UV_HANDLE_TYPE_MAP(XX) +}; + +union uv_any_req { + UV_REQ_TYPE_MAP(XX) +}; +#undef XX + + +struct uv_loop_s { + /* User data - use this for whatever. */ + void* data; + /* Loop reference counting */ + unsigned int active_handles; + void* handle_queue[2]; + void* active_reqs[2]; + /* Internal flag to signal loop stop */ + unsigned int stop_flag; + UV_LOOP_PRIVATE_FIELDS +}; + + +/* Don't export the private CPP symbols. */ +#undef UV_HANDLE_TYPE_PRIVATE +#undef UV_REQ_TYPE_PRIVATE +#undef UV_REQ_PRIVATE_FIELDS +#undef UV_STREAM_PRIVATE_FIELDS +#undef UV_TCP_PRIVATE_FIELDS +#undef UV_PREPARE_PRIVATE_FIELDS +#undef UV_CHECK_PRIVATE_FIELDS +#undef UV_IDLE_PRIVATE_FIELDS +#undef UV_ASYNC_PRIVATE_FIELDS +#undef UV_TIMER_PRIVATE_FIELDS +#undef UV_GETADDRINFO_PRIVATE_FIELDS +#undef UV_FS_REQ_PRIVATE_FIELDS +#undef UV_WORK_PRIVATE_FIELDS +#undef UV_FS_EVENT_PRIVATE_FIELDS +#undef UV_SIGNAL_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_FIELDS +#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/libuv.pc.in b/libuv.pc.in new file mode 100644 index 0000000000..86c1a126cd --- /dev/null +++ b/libuv.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Version: @PACKAGE_VERSION@ +Description: multi-platform support library with a focus on asynchronous I/O. + +Libs: -L${libdir} -luv +Cflags: -I${includedir} diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000000..bde78f43f9 --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,2 @@ +# Ignore libtoolize-generated files. +*.m4 diff --git a/m4/dtrace.m4 b/m4/dtrace.m4 new file mode 100644 index 0000000000..4060af3181 --- /dev/null +++ b/m4/dtrace.m4 @@ -0,0 +1,58 @@ +dnl Copyright (C) 2009 Sun Microsystems +dnl This file is free software; Sun Microsystems +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl --------------------------------------------------------------------------- +dnl Macro: PANDORA_ENABLE_DTRACE +dnl --------------------------------------------------------------------------- +AC_DEFUN([PANDORA_ENABLE_DTRACE],[ + AC_ARG_ENABLE([dtrace], + [AS_HELP_STRING([--disable-dtrace], + [enable DTrace USDT probes. @<:@default=yes@:>@])], + [ac_cv_enable_dtrace="$enableval"], + [ac_cv_enable_dtrace="yes"]) + + AS_IF([test "$ac_cv_enable_dtrace" = "yes"],[ + AC_CHECK_PROGS([DTRACE], [dtrace]) + AS_IF([test "x$ac_cv_prog_DTRACE" = "xdtrace"],[ + + AC_CACHE_CHECK([if dtrace works],[ac_cv_dtrace_works],[ + cat >conftest.d <<_ACEOF +provider Example { + probe increment(int); +}; +_ACEOF + $DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero + AS_IF([test $? -eq 0],[ac_cv_dtrace_works=yes], + [ac_cv_dtrace_works=no]) + rm -f conftest.h conftest.d + ]) + AS_IF([test "x$ac_cv_dtrace_works" = "xyes"],[ + AC_DEFINE([HAVE_DTRACE], [1], [Enables DTRACE Support]) + ]) + AC_CACHE_CHECK([if dtrace should instrument object files], + [ac_cv_dtrace_needs_objects],[ + dnl DTrace on MacOSX does not use -G option + cat >conftest.d <<_ACEOF +provider Example { + probe increment(int); +}; +_ACEOF + $DTRACE -G -o conftest.d.o -s conftest.d 2>/dev/zero + AS_IF([test $? -eq 0],[ac_cv_dtrace_needs_objects=yes], + [ac_cv_dtrace_needs_objects=no]) + rm -f conftest.d.o conftest.d + ]) + AC_SUBST(DTRACEFLAGS) dnl TODO: test for -G on OSX + ac_cv_have_dtrace=yes + ])]) + +AM_CONDITIONAL([HAVE_DTRACE], [test "x$ac_cv_dtrace_works" = "xyes"]) +AM_CONDITIONAL([DTRACE_NEEDS_OBJECTS], + [test "x$ac_cv_dtrace_needs_objects" = "xyes"]) + +]) +dnl --------------------------------------------------------------------------- +dnl End Macro: PANDORA_ENABLE_DTRACE +dnl --------------------------------------------------------------------------- diff --git a/samples/.gitignore b/samples/.gitignore new file mode 100644 index 0000000000..f868091ba3 --- /dev/null +++ b/samples/.gitignore @@ -0,0 +1,22 @@ +# Copyright StrongLoop, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +*.mk +*.Makefile diff --git a/samples/socks5-proxy/.gitignore b/samples/socks5-proxy/.gitignore new file mode 100644 index 0000000000..c177f37451 --- /dev/null +++ b/samples/socks5-proxy/.gitignore @@ -0,0 +1,21 @@ +# Copyright StrongLoop, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +/build/ diff --git a/samples/socks5-proxy/LICENSE b/samples/socks5-proxy/LICENSE new file mode 100644 index 0000000000..63c1447fc5 --- /dev/null +++ b/samples/socks5-proxy/LICENSE @@ -0,0 +1,53 @@ +Files: * +======== + +Copyright StrongLoop, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + + +Files: getopt.c +=============== + +Copyright (c) 1987, 1993, 1994 +The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/samples/socks5-proxy/Makefile b/samples/socks5-proxy/Makefile new file mode 100644 index 0000000000..268dc55b1a --- /dev/null +++ b/samples/socks5-proxy/Makefile @@ -0,0 +1,46 @@ +# Copyright StrongLoop, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +BUILDTYPE ?= Debug +BUILDDIR ?= build +GYP ?= gyp +V ?= + +SOURCES := client.c defs.h getopt.c main.c s5.c s5.h server.c util.c + +.PHONY: all clean + +all: $(BUILDDIR)/$(BUILDTYPE)/s5-proxy + +clean: + $(RM) $(BUILDDIR) + +$(BUILDDIR)/$(BUILDTYPE)/s5-proxy: $(BUILDDIR)/Makefile $(SOURCES) + $(MAKE) -C $(BUILDDIR) V=$(V) + +$(BUILDDIR)/Makefile: ../../common.gypi build.gyp + $(GYP) \ + -Dlibrary=static_library \ + -Goutput_dir=. \ + -I../../common.gypi \ + -f make \ + --depth=. \ + --generator-output=$(BUILDDIR) \ + build.gyp diff --git a/samples/socks5-proxy/build.gyp b/samples/socks5-proxy/build.gyp new file mode 100644 index 0000000000..771a1e146d --- /dev/null +++ b/samples/socks5-proxy/build.gyp @@ -0,0 +1,46 @@ +# Copyright StrongLoop, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +{ + 'targets': [ + { + 'dependencies': ['../../uv.gyp:libuv'], + 'target_name': 's5-proxy', + 'type': 'executable', + 'sources': [ + 'client.c', + 'defs.h', + 'main.c', + 's5.c', + 's5.h', + 'server.c', + 'util.c', + ], + 'conditions': [ + ['OS=="win"', { + 'defines': ['HAVE_UNISTD_H=0'], + 'sources': ['getopt.c'] + }, { + 'defines': ['HAVE_UNISTD_H=1'] + }] + ] + } + ] +} diff --git a/samples/socks5-proxy/client.c b/samples/socks5-proxy/client.c new file mode 100644 index 0000000000..ae9913a1c6 --- /dev/null +++ b/samples/socks5-proxy/client.c @@ -0,0 +1,737 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "defs.h" +#include +#include +#include + +/* A connection is modeled as an abstraction on top of two simple state + * machines, one for reading and one for writing. Either state machine + * is, when active, in one of three states: busy, done or stop; the fourth + * and final state, dead, is an end state and only relevant when shutting + * down the connection. A short overview: + * + * busy done stop + * ----------|---------------------------|--------------------|------| + * readable | waiting for incoming data | have incoming data | idle | + * writable | busy writing out data | completed write | idle | + * + * We could remove the done state from the writable state machine. For our + * purposes, it's functionally equivalent to the stop state. + * + * When the connection with upstream has been established, the client_ctx + * moves into a state where incoming data from the client is sent upstream + * and vice versa, incoming data from upstream is sent to the client. In + * other words, we're just piping data back and forth. See conn_cycle() + * for details. + * + * An interesting deviation from libuv's I/O model is that reads are discrete + * rather than continuous events. In layman's terms, when a read operation + * completes, the connection stops reading until further notice. + * + * The rationale for this approach is that we have to wait until the data + * has been sent out again before we can reuse the read buffer. + * + * It also pleasingly unifies with the request model that libuv uses for + * writes and everything else; libuv may switch to a request model for + * reads in the future. + */ +enum conn_state { + c_busy, /* Busy; waiting for incoming data or for a write to complete. */ + c_done, /* Done; read incoming data or write finished. */ + c_stop, /* Stopped. */ + c_dead +}; + +/* Session states. */ +enum sess_state { + s_handshake, /* Wait for client handshake. */ + s_handshake_auth, /* Wait for client authentication data. */ + s_req_start, /* Start waiting for request data. */ + s_req_parse, /* Wait for request data. */ + s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */ + s_req_connect, /* Wait for uv_tcp_connect() to complete. */ + s_proxy_start, /* Connected. Start piping data. */ + s_proxy, /* Connected. Pipe data back and forth. */ + s_kill, /* Tear down session. */ + s_almost_dead_0, /* Waiting for finalizers to complete. */ + s_almost_dead_1, /* Waiting for finalizers to complete. */ + s_almost_dead_2, /* Waiting for finalizers to complete. */ + s_almost_dead_3, /* Waiting for finalizers to complete. */ + s_almost_dead_4, /* Waiting for finalizers to complete. */ + s_dead /* Dead. Safe to free now. */ +}; + +static void do_next(client_ctx *cx); +static int do_handshake(client_ctx *cx); +static int do_handshake_auth(client_ctx *cx); +static int do_req_start(client_ctx *cx); +static int do_req_parse(client_ctx *cx); +static int do_req_lookup(client_ctx *cx); +static int do_req_connect_start(client_ctx *cx); +static int do_req_connect(client_ctx *cx); +static int do_proxy_start(client_ctx *cx); +static int do_proxy(client_ctx *cx); +static int do_kill(client_ctx *cx); +static int do_almost_dead(client_ctx *cx); +static int conn_cycle(const char *who, conn *a, conn *b); +static void conn_timer_reset(conn *c); +static void conn_timer_expire(uv_timer_t *handle, int status); +static void conn_getaddrinfo(conn *c, const char *hostname); +static void conn_getaddrinfo_done(uv_getaddrinfo_t *req, + int status, + struct addrinfo *ai); +static int conn_connect(conn *c); +static void conn_connect_done(uv_connect_t *req, int status); +static void conn_read(conn *c); +static void conn_read_done(uv_stream_t *handle, + ssize_t nread, + const uv_buf_t *buf); +static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf); +static void conn_write(conn *c, const void *data, unsigned int len); +static void conn_write_done(uv_write_t *req, int status); +static void conn_close(conn *c); +static void conn_close_done(uv_handle_t *handle); + +/* |incoming| has been initialized by server.c when this is called. */ +void client_finish_init(server_ctx *sx, client_ctx *cx) { + conn *incoming; + conn *outgoing; + + cx->sx = sx; + cx->state = s_handshake; + s5_init(&cx->parser); + + incoming = &cx->incoming; + incoming->client = cx; + incoming->result = 0; + incoming->rdstate = c_stop; + incoming->wrstate = c_stop; + incoming->idle_timeout = sx->idle_timeout; + CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle)); + + outgoing = &cx->outgoing; + outgoing->client = cx; + outgoing->result = 0; + outgoing->rdstate = c_stop; + outgoing->wrstate = c_stop; + outgoing->idle_timeout = sx->idle_timeout; + CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp)); + CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle)); + + /* Wait for the initial packet. */ + conn_read(incoming); +} + +/* This is the core state machine that drives the client <-> upstream proxy. + * We move through the initial handshake and authentication steps first and + * end up (if all goes well) in the proxy state where we're just proxying + * data between the client and upstream. + */ +static void do_next(client_ctx *cx) { + int new_state; + + ASSERT(cx->state != s_dead); + switch (cx->state) { + case s_handshake: + new_state = do_handshake(cx); + break; + case s_handshake_auth: + new_state = do_handshake_auth(cx); + break; + case s_req_start: + new_state = do_req_start(cx); + break; + case s_req_parse: + new_state = do_req_parse(cx); + break; + case s_req_lookup: + new_state = do_req_lookup(cx); + break; + case s_req_connect: + new_state = do_req_connect(cx); + break; + case s_proxy_start: + new_state = do_proxy_start(cx); + break; + case s_proxy: + new_state = do_proxy(cx); + break; + case s_kill: + new_state = do_kill(cx); + break; + case s_almost_dead_0: + case s_almost_dead_1: + case s_almost_dead_2: + case s_almost_dead_3: + case s_almost_dead_4: + new_state = do_almost_dead(cx); + break; + default: + UNREACHABLE(); + } + cx->state = new_state; + + if (cx->state == s_dead) { + if (DEBUG_CHECKS) { + memset(cx, -1, sizeof(*cx)); + } + free(cx); + } +} + +static int do_handshake(client_ctx *cx) { + unsigned int methods; + conn *incoming; + s5_ctx *parser; + uint8_t *data; + size_t size; + int err; + + parser = &cx->parser; + incoming = &cx->incoming; + ASSERT(incoming->rdstate == c_done); + ASSERT(incoming->wrstate == c_stop); + incoming->rdstate = c_stop; + + if (incoming->result < 0) { + pr_err("read error: %s", uv_strerror(incoming->result)); + return do_kill(cx); + } + + data = (uint8_t *) incoming->t.buf; + size = (size_t) incoming->result; + err = s5_parse(parser, &data, &size); + if (err == s5_ok) { + conn_read(incoming); + return s_handshake; /* Need more data. */ + } + + if (size != 0) { + /* Could allow a round-trip saving shortcut here if the requested auth + * method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.) + * Requires client support however. + */ + pr_err("junk in handshake"); + return do_kill(cx); + } + + if (err != s5_auth_select) { + pr_err("handshake error: %s", s5_strerror(err)); + return do_kill(cx); + } + + methods = s5_auth_methods(parser); + if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) { + s5_select_auth(parser, S5_AUTH_NONE); + conn_write(incoming, "\5\0", 2); /* No auth required. */ + return s_req_start; + } + + if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) { + /* TODO(bnoordhuis) Implement username/password auth. */ + } + + conn_write(incoming, "\5\377", 2); /* No acceptable auth. */ + return s_kill; +} + +/* TODO(bnoordhuis) Implement username/password auth. */ +static int do_handshake_auth(client_ctx *cx) { + UNREACHABLE(); + return do_kill(cx); +} + +static int do_req_start(client_ctx *cx) { + conn *incoming; + + incoming = &cx->incoming; + ASSERT(incoming->rdstate == c_stop); + ASSERT(incoming->wrstate == c_done); + incoming->wrstate = c_stop; + + if (incoming->result < 0) { + pr_err("write error: %s", uv_strerror(incoming->result)); + return do_kill(cx); + } + + conn_read(incoming); + return s_req_parse; +} + +static int do_req_parse(client_ctx *cx) { + conn *incoming; + conn *outgoing; + s5_ctx *parser; + uint8_t *data; + size_t size; + int err; + + parser = &cx->parser; + incoming = &cx->incoming; + outgoing = &cx->outgoing; + ASSERT(incoming->rdstate == c_done); + ASSERT(incoming->wrstate == c_stop); + ASSERT(outgoing->rdstate == c_stop); + ASSERT(outgoing->wrstate == c_stop); + incoming->rdstate = c_stop; + + if (incoming->result < 0) { + pr_err("read error: %s", uv_strerror(incoming->result)); + return do_kill(cx); + } + + data = (uint8_t *) incoming->t.buf; + size = (size_t) incoming->result; + err = s5_parse(parser, &data, &size); + if (err == s5_ok) { + conn_read(incoming); + return s_req_parse; /* Need more data. */ + } + + if (size != 0) { + pr_err("junk in request %u", (unsigned) size); + return do_kill(cx); + } + + if (err != s5_exec_cmd) { + pr_err("request error: %s", s5_strerror(err)); + return do_kill(cx); + } + + if (parser->cmd == s5_cmd_tcp_bind) { + /* Not supported but relatively straightforward to implement. */ + pr_warn("BIND requests are not supported."); + return do_kill(cx); + } + + if (parser->cmd == s5_cmd_udp_assoc) { + /* Not supported. Might be hard to implement because libuv has no + * functionality for detecting the MTU size which the RFC mandates. + */ + pr_warn("UDP ASSOC requests are not supported."); + return do_kill(cx); + } + ASSERT(parser->cmd == s5_cmd_tcp_connect); + + if (parser->atyp == s5_atyp_host) { + conn_getaddrinfo(outgoing, (const char *) parser->daddr); + return s_req_lookup; + } + + if (parser->atyp == s5_atyp_ipv4) { + memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4)); + outgoing->t.addr4.sin_family = AF_INET; + outgoing->t.addr4.sin_port = htons(parser->dport); + memcpy(&outgoing->t.addr4.sin_addr, + parser->daddr, + sizeof(outgoing->t.addr4.sin_addr)); + } else if (parser->atyp == s5_atyp_ipv6) { + memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6)); + outgoing->t.addr6.sin6_family = AF_INET6; + outgoing->t.addr6.sin6_port = htons(parser->dport); + memcpy(&outgoing->t.addr6.sin6_addr, + parser->daddr, + sizeof(outgoing->t.addr6.sin6_addr)); + } else { + UNREACHABLE(); + } + + return do_req_connect_start(cx); +} + +static int do_req_lookup(client_ctx *cx) { + s5_ctx *parser; + conn *incoming; + conn *outgoing; + + parser = &cx->parser; + incoming = &cx->incoming; + outgoing = &cx->outgoing; + ASSERT(incoming->rdstate == c_stop); + ASSERT(incoming->wrstate == c_stop); + ASSERT(outgoing->rdstate == c_stop); + ASSERT(outgoing->wrstate == c_stop); + + if (outgoing->result < 0) { + /* TODO(bnoordhuis) Escape control characters in parser->daddr. */ + pr_err("lookup error for \"%s\": %s", + parser->daddr, + uv_strerror(outgoing->result)); + /* Send back a 'Host unreachable' reply. */ + conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10); + return s_kill; + } + + /* Don't make assumptions about the offset of sin_port/sin6_port. */ + switch (outgoing->t.addr.sa_family) { + case AF_INET: + outgoing->t.addr4.sin_port = htons(parser->dport); + break; + case AF_INET6: + outgoing->t.addr6.sin6_port = htons(parser->dport); + break; + default: + UNREACHABLE(); + } + + return do_req_connect_start(cx); +} + +/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */ +static int do_req_connect_start(client_ctx *cx) { + conn *incoming; + conn *outgoing; + int err; + + incoming = &cx->incoming; + outgoing = &cx->outgoing; + ASSERT(incoming->rdstate == c_stop); + ASSERT(incoming->wrstate == c_stop); + ASSERT(outgoing->rdstate == c_stop); + ASSERT(outgoing->wrstate == c_stop); + + if (!can_access(cx->sx, cx, &outgoing->t.addr)) { + pr_warn("connection not allowed by ruleset"); + /* Send a 'Connection not allowed by ruleset' reply. */ + conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10); + return s_kill; + } + + err = conn_connect(outgoing); + if (err != 0) { + pr_err("connect error: %s\n", uv_strerror(err)); + return do_kill(cx); + } + + return s_req_connect; +} + +static int do_req_connect(client_ctx *cx) { + const struct sockaddr_in6 *in6; + const struct sockaddr_in *in; + char addr_storage[sizeof(*in6)]; + conn *incoming; + conn *outgoing; + uint8_t *buf; + int addrlen; + + incoming = &cx->incoming; + outgoing = &cx->outgoing; + ASSERT(incoming->rdstate == c_stop); + ASSERT(incoming->wrstate == c_stop); + ASSERT(outgoing->rdstate == c_stop); + ASSERT(outgoing->wrstate == c_stop); + + /* Build and send the reply. Not very pretty but gets the job done. */ + buf = (uint8_t *) incoming->t.buf; + if (outgoing->result == 0) { + /* The RFC mandates that the SOCKS server must include the local port + * and address in the reply. So that's what we do. + */ + addrlen = sizeof(addr_storage); + CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp, + (struct sockaddr *) addr_storage, + &addrlen)); + buf[0] = 5; /* Version. */ + buf[1] = 0; /* Success. */ + buf[2] = 0; /* Reserved. */ + if (addrlen == sizeof(*in)) { + buf[3] = 1; /* IPv4. */ + in = (const struct sockaddr_in *) &addr_storage; + memcpy(buf + 4, &in->sin_addr, 4); + memcpy(buf + 8, &in->sin_port, 2); + conn_write(incoming, buf, 10); + } else if (addrlen == sizeof(*in6)) { + buf[3] = 4; /* IPv6. */ + in6 = (const struct sockaddr_in6 *) &addr_storage; + memcpy(buf + 4, &in6->sin6_addr, 16); + memcpy(buf + 20, &in6->sin6_port, 2); + conn_write(incoming, buf, 22); + } else { + UNREACHABLE(); + } + return s_proxy_start; + } else { + pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result)); + /* Send a 'Connection refused' reply. */ + conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10); + return s_kill; + } + + UNREACHABLE(); + return s_kill; +} + +static int do_proxy_start(client_ctx *cx) { + conn *incoming; + conn *outgoing; + + incoming = &cx->incoming; + outgoing = &cx->outgoing; + ASSERT(incoming->rdstate == c_stop); + ASSERT(incoming->wrstate == c_done); + ASSERT(outgoing->rdstate == c_stop); + ASSERT(outgoing->wrstate == c_stop); + incoming->wrstate = c_stop; + + if (incoming->result < 0) { + pr_err("write error: %s", uv_strerror(incoming->result)); + return do_kill(cx); + } + + conn_read(incoming); + conn_read(outgoing); + return s_proxy; +} + +/* Proxy incoming data back and forth. */ +static int do_proxy(client_ctx *cx) { + if (conn_cycle("client", &cx->incoming, &cx->outgoing)) { + return do_kill(cx); + } + + if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) { + return do_kill(cx); + } + + return s_proxy; +} + +static int do_kill(client_ctx *cx) { + int new_state; + + if (cx->state >= s_almost_dead_0) { + return cx->state; + } + + /* Try to cancel the request. The callback still runs but if the + * cancellation succeeded, it gets called with status=UV_ECANCELED. + */ + new_state = s_almost_dead_1; + if (cx->state == s_req_lookup) { + new_state = s_almost_dead_0; + uv_cancel(&cx->outgoing.t.req); + } + + conn_close(&cx->incoming); + conn_close(&cx->outgoing); + return new_state; +} + +static int do_almost_dead(client_ctx *cx) { + ASSERT(cx->state >= s_almost_dead_0); + return cx->state + 1; /* Another finalizer completed. */ +} + +static int conn_cycle(const char *who, conn *a, conn *b) { + if (a->result < 0) { + if (a->result != UV_EOF) { + pr_err("%s error: %s", who, uv_strerror(a->result)); + } + return -1; + } + + if (b->result < 0) { + return -1; + } + + if (a->wrstate == c_done) { + a->wrstate = c_stop; + } + + /* The logic is as follows: read when we don't write and write when we don't + * read. That gives us back-pressure handling for free because if the peer + * sends data faster than we consume it, TCP congestion control kicks in. + */ + if (a->wrstate == c_stop) { + if (b->rdstate == c_stop) { + conn_read(b); + } else if (b->rdstate == c_done) { + conn_write(a, b->t.buf, b->result); + b->rdstate = c_stop; /* Triggers the call to conn_read() above. */ + } + } + + return 0; +} + +static void conn_timer_reset(conn *c) { + CHECK(0 == uv_timer_start(&c->timer_handle, + conn_timer_expire, + c->idle_timeout, + 0)); +} + +static void conn_timer_expire(uv_timer_t *handle, int status) { + conn *c; + + CHECK(0 == status); + c = CONTAINER_OF(handle, conn, timer_handle); + c->result = UV_ETIMEDOUT; + do_next(c->client); +} + +static void conn_getaddrinfo(conn *c, const char *hostname) { + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + CHECK(0 == uv_getaddrinfo(c->client->sx->loop, + &c->t.addrinfo_req, + conn_getaddrinfo_done, + hostname, + NULL, + &hints)); + conn_timer_reset(c); +} + +static void conn_getaddrinfo_done(uv_getaddrinfo_t *req, + int status, + struct addrinfo *ai) { + conn *c; + + c = CONTAINER_OF(req, conn, t.addrinfo_req); + c->result = status; + + if (status == 0) { + /* FIXME(bnoordhuis) Should try all addresses. */ + if (ai->ai_family == AF_INET) { + c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr; + } else if (ai->ai_family == AF_INET6) { + c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr; + } else { + UNREACHABLE(); + } + } + + uv_freeaddrinfo(ai); + do_next(c->client); +} + +/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */ +static int conn_connect(conn *c) { + ASSERT(c->t.addr.sa_family == AF_INET || + c->t.addr.sa_family == AF_INET6); + conn_timer_reset(c); + return uv_tcp_connect(&c->t.connect_req, + &c->handle.tcp, + &c->t.addr, + conn_connect_done); +} + +static void conn_connect_done(uv_connect_t *req, int status) { + conn *c; + + if (status == UV_ECANCELED) { + return; /* Handle has been closed. */ + } + + c = CONTAINER_OF(req, conn, t.connect_req); + c->result = status; + do_next(c->client); +} + +static void conn_read(conn *c) { + ASSERT(c->rdstate == c_stop); + CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done)); + c->rdstate = c_busy; + conn_timer_reset(c); +} + +static void conn_read_done(uv_stream_t *handle, + ssize_t nread, + const uv_buf_t *buf) { + conn *c; + + c = CONTAINER_OF(handle, conn, handle); + ASSERT(c->t.buf == buf->base); + ASSERT(c->rdstate == c_busy); + c->rdstate = c_done; + c->result = nread; + + uv_read_stop(&c->handle.stream); + do_next(c->client); +} + +static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) { + conn *c; + + c = CONTAINER_OF(handle, conn, handle); + ASSERT(c->rdstate == c_busy); + buf->base = c->t.buf; + buf->len = sizeof(c->t.buf); +} + +static void conn_write(conn *c, const void *data, unsigned int len) { + uv_buf_t buf; + + ASSERT(c->wrstate == c_stop || c->wrstate == c_done); + c->wrstate = c_busy; + + /* It's okay to cast away constness here, uv_write() won't modify the + * memory. + */ + buf.base = (char *) data; + buf.len = len; + + CHECK(0 == uv_write(&c->write_req, + &c->handle.stream, + &buf, + 1, + conn_write_done)); + conn_timer_reset(c); +} + +static void conn_write_done(uv_write_t *req, int status) { + conn *c; + + if (status == UV_ECANCELED) { + return; /* Handle has been closed. */ + } + + c = CONTAINER_OF(req, conn, write_req); + ASSERT(c->wrstate == c_busy); + c->wrstate = c_done; + c->result = status; + do_next(c->client); +} + +static void conn_close(conn *c) { + ASSERT(c->rdstate != c_dead); + ASSERT(c->wrstate != c_dead); + c->rdstate = c_dead; + c->wrstate = c_dead; + c->timer_handle.data = c; + c->handle.handle.data = c; + uv_close(&c->handle.handle, conn_close_done); + uv_close((uv_handle_t *) &c->timer_handle, conn_close_done); +} + +static void conn_close_done(uv_handle_t *handle) { + conn *c; + + c = handle->data; + do_next(c->client); +} diff --git a/samples/socks5-proxy/defs.h b/samples/socks5-proxy/defs.h new file mode 100644 index 0000000000..99ee8160c8 --- /dev/null +++ b/samples/socks5-proxy/defs.h @@ -0,0 +1,139 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef DEFS_H_ +#define DEFS_H_ + +#include "s5.h" +#include "uv.h" + +#include +#include /* sockaddr_in, sockaddr_in6 */ +#include /* size_t, ssize_t */ +#include +#include /* sockaddr */ + +struct client_ctx; + +typedef struct { + const char *bind_host; + unsigned short bind_port; + unsigned int idle_timeout; +} server_config; + +typedef struct { + unsigned int idle_timeout; /* Connection idle timeout in ms. */ + uv_tcp_t tcp_handle; + uv_loop_t *loop; +} server_ctx; + +typedef struct { + unsigned char rdstate; + unsigned char wrstate; + unsigned int idle_timeout; + struct client_ctx *client; /* Backlink to owning client context. */ + ssize_t result; + union { + uv_handle_t handle; + uv_stream_t stream; + uv_tcp_t tcp; + uv_udp_t udp; + } handle; + uv_timer_t timer_handle; /* For detecting timeouts. */ + uv_write_t write_req; + /* We only need one of these at a time so make them share memory. */ + union { + uv_getaddrinfo_t addrinfo_req; + uv_connect_t connect_req; + uv_req_t req; + struct sockaddr_in6 addr6; + struct sockaddr_in addr4; + struct sockaddr addr; + char buf[2048]; /* Scratch space. Used to read data into. */ + } t; +} conn; + +typedef struct client_ctx { + unsigned int state; + server_ctx *sx; /* Backlink to owning server context. */ + s5_ctx parser; /* The SOCKS protocol parser. */ + conn incoming; /* Connection with the SOCKS client. */ + conn outgoing; /* Connection with upstream. */ +} client_ctx; + +/* server.c */ +int server_run(const server_config *cf, uv_loop_t *loop); +int can_auth_none(const server_ctx *sx, const client_ctx *cx); +int can_auth_passwd(const server_ctx *sx, const client_ctx *cx); +int can_access(const server_ctx *sx, + const client_ctx *cx, + const struct sockaddr *addr); + +/* client.c */ +void client_finish_init(server_ctx *sx, client_ctx *cx); + +/* util.c */ +#if defined(__GNUC__) +# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b))) +#else +# define ATTRIBUTE_FORMAT_PRINTF(a, b) +#endif +void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); +void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); +void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); +void *xmalloc(size_t size); + +/* main.c */ +const char *_getprogname(void); + +/* getopt.c */ +#if !HAVE_UNISTD_H +extern char *optarg; +int getopt(int argc, char **argv, const char *options); +#endif + +/* ASSERT() is for debug checks, CHECK() for run-time sanity checks. + * DEBUG_CHECKS is for expensive debug checks that we only want to + * enable in debug builds but still want type-checked by the compiler + * in release builds. + */ +#if defined(NDEBUG) +# define ASSERT(exp) +# define CHECK(exp) do { if (!(exp)) abort(); } while (0) +# define DEBUG_CHECKS (0) +#else +# define ASSERT(exp) assert(exp) +# define CHECK(exp) assert(exp) +# define DEBUG_CHECKS (1) +#endif + +#define UNREACHABLE() CHECK(!"Unreachable code reached.") + +/* This macro looks complicated but it's not: it calculates the address + * of the embedding struct through the address of the embedded struct. + * In other words, if struct A embeds struct B, then we can obtain + * the address of A by taking the address of B and subtracting the + * field offset of B in A. + */ +#define CONTAINER_OF(ptr, type, field) \ + ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field))) + +#endif /* DEFS_H_ */ diff --git a/samples/socks5-proxy/getopt.c b/samples/socks5-proxy/getopt.c new file mode 100644 index 0000000000..8481b2264f --- /dev/null +++ b/samples/socks5-proxy/getopt.c @@ -0,0 +1,131 @@ +/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +extern const char *_getprogname(void); + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const nargv[]; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || *place == 0) { /* update scanning pointer */ + optreset = 0; + place = nargv[optind]; + if (optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + optopt = *place++; + if (optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++optind; + place = EMSG; + return (-1); + } + if (optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == NULL) + return (-1); + optopt = '-'; + } + } else + optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { + if (*place == 0) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", _getprogname(), + optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + optarg = NULL; + if (*place == 0) + ++optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + optarg = place; + else if (nargc > ++optind) + optarg = nargv[optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + _getprogname(), optopt); + return (BADCH); + } + place = EMSG; + ++optind; + } + return (optopt); /* return option letter */ +} diff --git a/samples/socks5-proxy/main.c b/samples/socks5-proxy/main.c new file mode 100644 index 0000000000..04020cbd3a --- /dev/null +++ b/samples/socks5-proxy/main.c @@ -0,0 +1,99 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "defs.h" +#include +#include +#include + +#if HAVE_UNISTD_H +#include /* getopt */ +#endif + +#define DEFAULT_BIND_HOST "127.0.0.1" +#define DEFAULT_BIND_PORT 1080 +#define DEFAULT_IDLE_TIMEOUT (60 * 1000) + +static void parse_opts(server_config *cf, int argc, char **argv); +static void usage(void); + +static const char *progname = __FILE__; /* Reset in main(). */ + +int main(int argc, char **argv) { + server_config config; + int err; + + progname = argv[0]; + memset(&config, 0, sizeof(config)); + config.bind_host = DEFAULT_BIND_HOST; + config.bind_port = DEFAULT_BIND_PORT; + config.idle_timeout = DEFAULT_IDLE_TIMEOUT; + parse_opts(&config, argc, argv); + + err = server_run(&config, uv_default_loop()); + if (err) { + exit(1); + } + + return 0; +} + +const char *_getprogname(void) { + return progname; +} + +static void parse_opts(server_config *cf, int argc, char **argv) { + int opt; + + while (-1 != (opt = getopt(argc, argv, "H:hp:"))) { + switch (opt) { + case 'H': + cf->bind_host = optarg; + break; + + case 'p': + if (1 != sscanf(optarg, "%hu", &cf->bind_port)) { + pr_err("bad port number: %s", optarg); + usage(); + } + break; + + default: + usage(); + } + } +} + +static void usage(void) { + printf("Usage:\n" + "\n" + " %s [-b
[-h] [-p ]\n" + "\n" + "Options:\n" + "\n" + " -b Bind to this address or hostname.\n" + " Default: \"127.0.0.1\"\n" + " -h Show this help message.\n" + " -p Bind to this port number. Default: 1080\n" + "", + progname); + exit(1); +} diff --git a/samples/socks5-proxy/s5.c b/samples/socks5-proxy/s5.c new file mode 100644 index 0000000000..4f08e34524 --- /dev/null +++ b/samples/socks5-proxy/s5.c @@ -0,0 +1,271 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "s5.h" +#include +#include +#include /* abort() */ +#include /* memset() */ + +enum { + s5_version, + s5_nmethods, + s5_methods, + s5_auth_pw_version, + s5_auth_pw_userlen, + s5_auth_pw_username, + s5_auth_pw_passlen, + s5_auth_pw_password, + s5_req_version, + s5_req_cmd, + s5_req_reserved, + s5_req_atyp, + s5_req_atyp_host, + s5_req_daddr, + s5_req_dport0, + s5_req_dport1, + s5_dead +}; + +void s5_init(s5_ctx *cx) { + memset(cx, 0, sizeof(*cx)); + cx->state = s5_version; +} + +s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) { + s5_err err; + uint8_t *p; + uint8_t c; + size_t i; + size_t n; + + p = *data; + n = *size; + i = 0; + + while (i < n) { + c = p[i]; + i += 1; + switch (cx->state) { + case s5_version: + if (c != 5) { + err = s5_bad_version; + goto out; + } + cx->state = s5_nmethods; + break; + + case s5_nmethods: + cx->arg0 = 0; + cx->arg1 = c; /* Number of bytes to read. */ + cx->state = s5_methods; + break; + + case s5_methods: + if (cx->arg0 < cx->arg1) { + switch (c) { + case 0: + cx->methods |= S5_AUTH_NONE; + break; + case 1: + cx->methods |= S5_AUTH_GSSAPI; + break; + case 2: + cx->methods |= S5_AUTH_PASSWD; + break; + /* Ignore everything we don't understand. */ + } + cx->arg0 += 1; + } + if (cx->arg0 == cx->arg1) { + err = s5_auth_select; + goto out; + } + break; + + case s5_auth_pw_version: + if (c != 1) { + err = s5_bad_version; + goto out; + } + cx->state = s5_auth_pw_userlen; + break; + + case s5_auth_pw_userlen: + cx->arg0 = 0; + cx->userlen = c; + cx->state = s5_auth_pw_username; + break; + + case s5_auth_pw_username: + if (cx->arg0 < cx->userlen) { + cx->username[cx->arg0] = c; + cx->arg0 += 1; + } + if (cx->arg0 == cx->userlen) { + cx->username[cx->userlen] = '\0'; + cx->state = s5_auth_pw_passlen; + } + break; + + case s5_auth_pw_passlen: + cx->arg0 = 0; + cx->passlen = c; + cx->state = s5_auth_pw_password; + break; + + case s5_auth_pw_password: + if (cx->arg0 < cx->passlen) { + cx->password[cx->arg0] = c; + cx->arg0 += 1; + } + if (cx->arg0 == cx->passlen) { + cx->password[cx->passlen] = '\0'; + cx->state = s5_req_version; + err = s5_auth_verify; + goto out; + } + break; + + case s5_req_version: + if (c != 5) { + err = s5_bad_version; + goto out; + } + cx->state = s5_req_cmd; + break; + + case s5_req_cmd: + switch (c) { + case 1: /* TCP connect */ + cx->cmd = s5_cmd_tcp_connect; + break; + case 3: /* UDP associate */ + cx->cmd = s5_cmd_udp_assoc; + break; + default: + err = s5_bad_cmd; + goto out; + } + cx->state = s5_req_reserved; + break; + + case s5_req_reserved: + cx->state = s5_req_atyp; + break; + + case s5_req_atyp: + cx->arg0 = 0; + switch (c) { + case 1: /* IPv4, four octets. */ + cx->state = s5_req_daddr; + cx->atyp = s5_atyp_ipv4; + cx->arg1 = 4; + break; + case 3: /* Hostname. First byte is length. */ + cx->state = s5_req_atyp_host; + cx->atyp = s5_atyp_host; + cx->arg1 = 0; + break; + case 4: /* IPv6, sixteen octets. */ + cx->state = s5_req_daddr; + cx->atyp = s5_atyp_ipv6; + cx->arg1 = 16; + break; + default: + err = s5_bad_atyp; + goto out; + } + break; + + case s5_req_atyp_host: + cx->arg1 = c; + cx->state = s5_req_daddr; + break; + + case s5_req_daddr: + if (cx->arg0 < cx->arg1) { + cx->daddr[cx->arg0] = c; + cx->arg0 += 1; + } + if (cx->arg0 == cx->arg1) { + cx->daddr[cx->arg1] = '\0'; + cx->state = s5_req_dport0; + } + break; + + case s5_req_dport0: + cx->dport = c << 8; + cx->state = s5_req_dport1; + break; + + case s5_req_dport1: + cx->dport |= c; + cx->state = s5_dead; + err = s5_exec_cmd; + goto out; + + case s5_dead: + break; + + default: + abort(); + } + } + err = s5_ok; + +out: + *data = p + i; + *size = n - i; + return err; +} + +unsigned int s5_auth_methods(const s5_ctx *cx) { + return cx->methods; +} + +int s5_select_auth(s5_ctx *cx, s5_auth_method method) { + int err; + + err = 0; + switch (method) { + case S5_AUTH_NONE: + cx->state = s5_req_version; + break; + case S5_AUTH_PASSWD: + cx->state = s5_auth_pw_version; + break; + default: + err = -EINVAL; + } + + return err; +} + +const char *s5_strerror(s5_err err) { +#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg; + switch (err) { + S5_ERR_MAP(S5_ERR_GEN) + default: ; /* Silence s5_max_errors -Wswitch warning. */ + } +#undef S5_ERR_GEN + return "Unknown error."; +} diff --git a/samples/socks5-proxy/s5.h b/samples/socks5-proxy/s5.h new file mode 100644 index 0000000000..715f322287 --- /dev/null +++ b/samples/socks5-proxy/s5.h @@ -0,0 +1,94 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef S5_H_ +#define S5_H_ + +#include +#include + +#define S5_ERR_MAP(V) \ + V(-1, bad_version, "Bad protocol version.") \ + V(-2, bad_cmd, "Bad protocol command.") \ + V(-3, bad_atyp, "Bad address type.") \ + V(0, ok, "No error.") \ + V(1, auth_select, "Select authentication method.") \ + V(2, auth_verify, "Verify authentication.") \ + V(3, exec_cmd, "Execute command.") \ + +typedef enum { +#define S5_ERR_GEN(code, name, _) s5_ ## name = code, + S5_ERR_MAP(S5_ERR_GEN) +#undef S5_ERR_GEN + s5_max_errors +} s5_err; + +typedef enum { + S5_AUTH_NONE = 1 << 0, + S5_AUTH_GSSAPI = 1 << 1, + S5_AUTH_PASSWD = 1 << 2 +} s5_auth_method; + +typedef enum { + s5_auth_allow, + s5_auth_deny +} s5_auth_result; + +typedef enum { + s5_atyp_ipv4, + s5_atyp_ipv6, + s5_atyp_host +} s5_atyp; + +typedef enum { + s5_cmd_tcp_connect, + s5_cmd_tcp_bind, + s5_cmd_udp_assoc +} s5_cmd; + +typedef struct { + uint32_t arg0; /* Scratch space for the state machine. */ + uint32_t arg1; /* Scratch space for the state machine. */ + uint8_t state; + uint8_t methods; + uint8_t cmd; + uint8_t atyp; + uint8_t userlen; + uint8_t passlen; + uint16_t dport; + uint8_t username[257]; + uint8_t password[257]; + uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */ +} s5_ctx; + +void s5_init(s5_ctx *ctx); + +s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size); + +/* Only call after s5_parse() has returned s5_want_auth_method. */ +unsigned int s5_auth_methods(const s5_ctx *cx); + +/* Call after s5_parse() has returned s5_want_auth_method. */ +int s5_select_auth(s5_ctx *cx, s5_auth_method method); + +const char *s5_strerror(s5_err err); + +#endif /* S5_H_ */ diff --git a/samples/socks5-proxy/server.c b/samples/socks5-proxy/server.c new file mode 100644 index 0000000000..3f1ba42c9e --- /dev/null +++ b/samples/socks5-proxy/server.c @@ -0,0 +1,241 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "defs.h" +#include /* INET6_ADDRSTRLEN */ +#include +#include + +#ifndef INET6_ADDRSTRLEN +# define INET6_ADDRSTRLEN 63 +#endif + +typedef struct { + uv_getaddrinfo_t getaddrinfo_req; + server_config config; + server_ctx *servers; + uv_loop_t *loop; +} server_state; + +static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai); +static void on_connection(uv_stream_t *server, int status); + +int server_run(const server_config *cf, uv_loop_t *loop) { + struct addrinfo hints; + server_state state; + int err; + + memset(&state, 0, sizeof(state)); + state.servers = NULL; + state.config = *cf; + state.loop = loop; + + /* Resolve the address of the interface that we should bind to. + * The getaddrinfo callback starts the server and everything else. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + err = uv_getaddrinfo(loop, + &state.getaddrinfo_req, + do_bind, + cf->bind_host, + NULL, + &hints); + if (err != 0) { + pr_err("getaddrinfo: %s", uv_strerror(err)); + return err; + } + + /* Start the event loop. Control continues in do_bind(). */ + if (uv_run(loop, UV_RUN_DEFAULT)) { + abort(); + } + + /* Please Valgrind. */ + uv_loop_delete(loop); + free(state.servers); + return 0; +} + +/* Bind a server to each address that getaddrinfo() reported. */ +static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) { + char addrbuf[INET6_ADDRSTRLEN + 1]; + unsigned int ipv4_naddrs; + unsigned int ipv6_naddrs; + server_state *state; + server_config *cf; + struct addrinfo *ai; + const void *addrv; + const char *what; + uv_loop_t *loop; + server_ctx *sx; + unsigned int n; + int err; + union { + struct sockaddr addr; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + } s; + + state = CONTAINER_OF(req, server_state, getaddrinfo_req); + loop = state->loop; + cf = &state->config; + + if (status < 0) { + pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status)); + uv_freeaddrinfo(addrs); + return; + } + + ipv4_naddrs = 0; + ipv6_naddrs = 0; + for (ai = addrs; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family == AF_INET) { + ipv4_naddrs += 1; + } else if (ai->ai_family == AF_INET6) { + ipv6_naddrs += 1; + } + } + + if (ipv4_naddrs == 0 && ipv6_naddrs == 0) { + pr_err("%s has no IPv4/6 addresses", cf->bind_host); + uv_freeaddrinfo(addrs); + return; + } + + state->servers = + xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0])); + + n = 0; + for (ai = addrs; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { + continue; + } + + if (ai->ai_family == AF_INET) { + s.addr4 = *(const struct sockaddr_in *) ai->ai_addr; + s.addr4.sin_port = htons(cf->bind_port); + addrv = &s.addr4.sin_addr; + } else if (ai->ai_family == AF_INET6) { + s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr; + s.addr6.sin6_port = htons(cf->bind_port); + addrv = &s.addr6.sin6_addr; + } else { + UNREACHABLE(); + } + + if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) { + UNREACHABLE(); + } + + sx = state->servers + n; + sx->loop = loop; + sx->idle_timeout = state->config.idle_timeout; + CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle)); + + what = "uv_tcp_bind"; + err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0); + if (err == 0) { + what = "uv_listen"; + err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection); + } + + if (err != 0) { + pr_err("%s(\"%s:%hu\"): %s", + what, + addrbuf, + cf->bind_port, + uv_strerror(err)); + while (n > 0) { + n -= 1; + uv_close((uv_handle_t *) (state->servers + n), NULL); + } + break; + } + + pr_info("listening on %s:%hu", addrbuf, cf->bind_port); + n += 1; + } + + uv_freeaddrinfo(addrs); +} + +static void on_connection(uv_stream_t *server, int status) { + server_ctx *sx; + client_ctx *cx; + + CHECK(status == 0); + sx = CONTAINER_OF(server, server_ctx, tcp_handle); + cx = xmalloc(sizeof(*cx)); + CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp)); + CHECK(0 == uv_accept(server, &cx->incoming.handle.stream)); + client_finish_init(sx, cx); +} + +int can_auth_none(const server_ctx *sx, const client_ctx *cx) { + return 1; +} + +int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) { + return 0; +} + +int can_access(const server_ctx *sx, + const client_ctx *cx, + const struct sockaddr *addr) { + const struct sockaddr_in6 *addr6; + const struct sockaddr_in *addr4; + const uint32_t *p; + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + + /* TODO(bnoordhuis) Implement proper access checks. For now, just reject + * traffic to localhost. + */ + if (addr->sa_family == AF_INET) { + addr4 = (const struct sockaddr_in *) addr; + d = ntohl(addr4->sin_addr.s_addr); + return (d >> 24) != 0x7F; + } + + if (addr->sa_family == AF_INET6) { + addr6 = (const struct sockaddr_in6 *) addr; + p = (const uint32_t *) &addr6->sin6_addr.s6_addr; + a = ntohl(p[0]); + b = ntohl(p[1]); + c = ntohl(p[2]); + d = ntohl(p[3]); + if (a == 0 && b == 0 && c == 0 && d == 1) { + return 0; /* "::1" style address. */ + } + if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) { + return 0; /* "::ffff:127.x.x.x" style address. */ + } + return 1; + } + + return 0; +} diff --git a/samples/socks5-proxy/util.c b/samples/socks5-proxy/util.c new file mode 100644 index 0000000000..af34f05593 --- /dev/null +++ b/samples/socks5-proxy/util.c @@ -0,0 +1,72 @@ +/* Copyright StrongLoop, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "defs.h" +#include +#include +#include + +static void pr_do(FILE *stream, + const char *label, + const char *fmt, + va_list ap); + +void *xmalloc(size_t size) { + void *ptr; + + ptr = malloc(size); + if (ptr == NULL) { + pr_err("out of memory, need %lu bytes", (unsigned long) size); + exit(1); + } + + return ptr; +} + +void pr_info(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + pr_do(stdout, "info", fmt, ap); + va_end(ap); +} + +void pr_warn(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + pr_do(stderr, "warn", fmt, ap); + va_end(ap); +} + +void pr_err(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + pr_do(stderr, "error", fmt, ap); + va_end(ap); +} + +static void pr_do(FILE *stream, + const char *label, + const char *fmt, + va_list ap) { + char fmtbuf[1024]; + vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap); + fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf); +} diff --git a/src/fs-poll.c b/src/fs-poll.c new file mode 100644 index 0000000000..7fdaaeb17a --- /dev/null +++ b/src/fs-poll.c @@ -0,0 +1,223 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include + +struct poll_ctx { + uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */ + int busy_polling; + unsigned int interval; + uint64_t start_time; + uv_loop_t* loop; + uv_fs_poll_cb poll_cb; + uv_timer_t timer_handle; + uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ + uv_stat_t statbuf; + char path[1]; /* variable length */ +}; + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); +static void poll_cb(uv_fs_t* req); +static void timer_cb(uv_timer_t* timer, int status); +static void timer_close_cb(uv_handle_t* handle); + +static uv_stat_t zero_statbuf; + + +int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); + return 0; +} + + +int uv_fs_poll_start(uv_fs_poll_t* handle, + uv_fs_poll_cb cb, + const char* path, + unsigned int interval) { + struct poll_ctx* ctx; + uv_loop_t* loop; + size_t len; + + if (uv__is_active(handle)) + return 0; + + loop = handle->loop; + len = strlen(path); + ctx = calloc(1, sizeof(*ctx) + len); + + if (ctx == NULL) + return UV_ENOMEM; + + ctx->loop = loop; + ctx->poll_cb = cb; + ctx->interval = interval ? interval : 1; + ctx->start_time = uv_now(loop); + ctx->parent_handle = handle; + memcpy(ctx->path, path, len + 1); + + if (uv_timer_init(loop, &ctx->timer_handle)) + abort(); + + ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&ctx->timer_handle); + + if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb)) + abort(); + + handle->poll_ctx = ctx; + uv__handle_start(handle); + + return 0; +} + + +int uv_fs_poll_stop(uv_fs_poll_t* handle) { + struct poll_ctx* ctx; + + if (!uv__is_active(handle)) + return 0; + + ctx = handle->poll_ctx; + assert(ctx != NULL); + assert(ctx->parent_handle != NULL); + ctx->parent_handle = NULL; + handle->poll_ctx = NULL; + + /* Close the timer if it's active. If it's inactive, there's a stat request + * in progress and poll_cb will take care of the cleanup. + */ + if (uv__is_active(&ctx->timer_handle)) + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + + uv__handle_stop(handle); + + return 0; +} + + +void uv__fs_poll_close(uv_fs_poll_t* handle) { + uv_fs_poll_stop(handle); +} + + +static void timer_cb(uv_timer_t* timer, int status) { + struct poll_ctx* ctx; + + ctx = container_of(timer, struct poll_ctx, timer_handle); + assert(ctx->parent_handle != NULL); + assert(ctx->parent_handle->poll_ctx == ctx); + ctx->start_time = uv_now(ctx->loop); + + if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb)) + abort(); +} + + +static void poll_cb(uv_fs_t* req) { + uv_stat_t* statbuf; + struct poll_ctx* ctx; + uint64_t interval; + + ctx = container_of(req, struct poll_ctx, fs_req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + uv_fs_req_cleanup(req); + return; + } + + if (req->result != 0) { + if (ctx->busy_polling != req->result) { + ctx->poll_cb(ctx->parent_handle, + req->result, + &ctx->statbuf, + &zero_statbuf); + ctx->busy_polling = req->result; + } + goto out; + } + + statbuf = &req->statbuf; + + if (ctx->busy_polling != 0) + if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf)) + ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf); + + ctx->statbuf = *statbuf; + ctx->busy_polling = 1; + +out: + uv_fs_req_cleanup(req); + + if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */ + uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); + return; + } + + /* Reschedule timer, subtract the delay from doing the stat(). */ + interval = ctx->interval; + interval -= (uv_now(ctx->loop) - ctx->start_time) % interval; + + if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0)) + abort(); +} + + +static void timer_close_cb(uv_handle_t* handle) { + free(container_of(handle, struct poll_ctx, timer_handle)); +} + + +static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { + return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec + && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec + && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec + && a->st_ctim.tv_sec == b->st_ctim.tv_sec + && a->st_mtim.tv_sec == b->st_mtim.tv_sec + && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec + && a->st_size == b->st_size + && a->st_mode == b->st_mode + && a->st_uid == b->st_uid + && a->st_gid == b->st_gid + && a->st_ino == b->st_ino + && a->st_dev == b->st_dev + && a->st_flags == b->st_flags + && a->st_gen == b->st_gen; +} + + +#if defined(_WIN32) + +#include "win/internal.h" +#include "win/handle-inl.h" + +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); +} + +#endif /* _WIN32 */ diff --git a/src/inet.c b/src/inet.c new file mode 100644 index 0000000000..a30c0d1512 --- /dev/null +++ b/src/inet.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "uv-common.h" + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size); +static int inet_ntop6(const unsigned char *src, char *dst, size_t size); +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); + + +int uv_inet_ntop(int af, const void* src, char* dst, size_t size) { + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int l; + +#ifndef _WIN32 + l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); +#else + l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); +#endif + if (l <= 0 || (size_t) l >= size) { + return UV_ENOSPC; + } + strncpy(dst, tmp, size); + dst[size - 1] = '\0'; + return 0; +} + + +static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < (int) sizeof(struct in6_addr); i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (int) ARRAY_SIZE(words); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)); + if (err) + return err; + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + return UV_ENOSPC; + } + strcpy(dst, tmp); + return 0; +} + + +int uv_inet_pton(int af, const char* src, void* dst) { + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + return UV_EAFNOSUPPORT; + } + /* NOTREACHED */ +} + + +static int inet_pton4(const char *src, unsigned char *dst) { + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[sizeof(struct in_addr)], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int nw = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return UV_EINVAL; + if (nw > 255) + return UV_EINVAL; + *tp = nw; + if (!saw_digit) { + if (++octets > 4) + return UV_EINVAL; + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return UV_EINVAL; + *++tp = 0; + saw_digit = 0; + } else + return UV_EINVAL; + } + if (octets < 4) + return UV_EINVAL; + memcpy(dst, tmp, sizeof(struct in_addr)); + return 0; +} + + +static int inet_pton6(const char *src, unsigned char *dst) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + unsigned int val; + + memset((tp = tmp), '\0', sizeof tmp); + endp = tp + sizeof tmp; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return UV_EINVAL; + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return UV_EINVAL; + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return UV_EINVAL; + colonp = tp; + continue; + } else if (*src == '\0') { + return UV_EINVAL; + } + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) { + int err = inet_pton4(curtok, tp); + if (err == 0) { + tp += sizeof(struct in_addr); + seen_xdigits = 0; + break; /*%< '\\0' was seen by inet_pton4(). */ + } + } + return UV_EINVAL; + } + if (seen_xdigits) { + if (tp + sizeof(uint16_t) > endp) + return UV_EINVAL; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return UV_EINVAL; + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return UV_EINVAL; + memcpy(dst, tmp, sizeof tmp); + return 0; +} diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000000..fe02b454ea --- /dev/null +++ b/src/queue.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QUEUE_H_ +#define QUEUE_H_ + +typedef void *QUEUE[2]; + +/* Private macros. */ +#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) +#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) +#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) +#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) + +/* Public macros. */ +#define QUEUE_DATA(ptr, type, field) \ + ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field))) + +#define QUEUE_FOREACH(q, h) \ + for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) + +#define QUEUE_EMPTY(q) \ + ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) + +#define QUEUE_HEAD(q) \ + (QUEUE_NEXT(q)) + +#define QUEUE_INIT(q) \ + do { \ + QUEUE_NEXT(q) = (q); \ + QUEUE_PREV(q) = (q); \ + } \ + while (0) + +#define QUEUE_ADD(h, n) \ + do { \ + QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ + QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV(h) = QUEUE_PREV(n); \ + QUEUE_PREV_NEXT(h) = (h); \ + } \ + while (0) + +#define QUEUE_SPLIT(h, q, n) \ + do { \ + QUEUE_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(n) = (n); \ + QUEUE_NEXT(n) = (q); \ + QUEUE_PREV(h) = QUEUE_PREV(q); \ + QUEUE_PREV_NEXT(h) = (h); \ + QUEUE_PREV(q) = (n); \ + } \ + while (0) + +#define QUEUE_INSERT_HEAD(h, q) \ + do { \ + QUEUE_NEXT(q) = QUEUE_NEXT(h); \ + QUEUE_PREV(q) = (h); \ + QUEUE_NEXT_PREV(q) = (q); \ + QUEUE_NEXT(h) = (q); \ + } \ + while (0) + +#define QUEUE_INSERT_TAIL(h, q) \ + do { \ + QUEUE_NEXT(q) = (h); \ + QUEUE_PREV(q) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(q) = (q); \ + QUEUE_PREV(h) = (q); \ + } \ + while (0) + +#define QUEUE_REMOVE(q) \ + do { \ + QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ + QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ + } \ + while (0) + +#endif /* QUEUE_H_ */ diff --git a/src/unix/aix.c b/src/unix/aix.c new file mode 100644 index 0000000000..2521681305 --- /dev/null +++ b/src/unix/aix.c @@ -0,0 +1,399 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +uint64_t uv__hrtime(uv_clocktype_t type) { + uint64_t G = 1000000000; + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (uint64_t) t.tb_high * G + t.tb_low; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + */ +int uv_exepath(char* buffer, size_t* size) { + ssize_t res; + char pp[64], cwdl[PATH_MAX]; + struct psinfo ps; + int fd; + + if (buffer == NULL) + return (-1); + + if (size == NULL) + return (-1); + + (void) snprintf(pp, sizeof(pp), "/proc/%lu/cwd", (unsigned long) getpid()); + + res = readlink(pp, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return res; + + cwdl[res] = '\0'; + + (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + fd = open(pp, O_RDONLY); + if (fd < 0) + return fd; + + res = read(fd, &ps, sizeof(ps)); + uv__close(fd); + if (res < 0) + return res; + + (void) snprintf(buffer, *size, "%s%s", cwdl, ps.pr_fname); + *size = strlen(buffer); + return 0; +} + + +uint64_t uv_get_free_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_free * 4096; +} + + +uint64_t uv_get_total_memory(void) { + perfstat_memory_total_t mem_total; + int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); + if (result == -1) { + return 0; + } + return mem_total.real_total * 4096; +} + + +void uv_loadavg(double avg[3]) { + perfstat_cpu_total_t ps_total; + int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + avg[0] = 0.; avg[1] = 0.; avg[2] = 0.; + return; + } + avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS); + avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS); + avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (size > 0) { + buffer[0] = '\0'; + } + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + char pp[64]; + psinfo_t psinfo; + int err; + int fd; + + (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + + fd = open(pp, O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + struct utmp *utmp_buf; + size_t entries = 0; + time_t boot_time; + + utmpname(UTMP_FILE); + + setutent(); + + while ((utmp_buf = getutent()) != NULL) { + if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS) + ++entries; + if (utmp_buf->ut_type == BOOT_TIME) + boot_time = utmp_buf->ut_time; + } + + endutent(); + + if (boot_time == 0) + return -ENOSYS; + + *uptime = time(NULL) - boot_time; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + perfstat_cpu_total_t ps_total; + perfstat_cpu_t* ps_cpus; + perfstat_id_t cpu_id; + int result, ncpus, idx = 0; + + result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); + if (result == -1) { + return -ENOSYS; + } + + ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); + if (result == -1) { + return -ENOSYS; + } + + ps_cpus = (perfstat_cpu_t*) malloc(ncpus * sizeof(perfstat_cpu_t)); + if (!ps_cpus) { + return -ENOMEM; + } + + strcpy(cpu_id.name, FIRST_CPU); + result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); + if (result == -1) { + free(ps_cpus); + return -ENOSYS; + } + + *cpu_infos = (uv_cpu_info_t*) malloc(ncpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + free(ps_cpus); + return -ENOMEM; + } + + *count = ncpus; + + cpu_info = *cpu_infos; + while (idx < ncpus) { + cpu_info->speed = (int)(ps_total.processorHZ / 1000000); + cpu_info->model = strdup(ps_total.description); + cpu_info->cpu_times.user = ps_cpus[idx].user; + cpu_info->cpu_times.sys = ps_cpus[idx].sys; + cpu_info->cpu_times.idle = ps_cpus[idx].idle; + cpu_info->cpu_times.irq = ps_cpus[idx].wait; + cpu_info->cpu_times.nice = 0; + cpu_info++; + idx++; + } + + free(ps_cpus); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; ++i) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return -ENOSYS; + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + ifc.ifc_req = (struct ifreq*)malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = (uv_interface_address_t*) + malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = strdup(p->ifr_name); + + if (p->ifr_addr.sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + } + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + + address++; + } + +#undef ADDR_SIZE + + uv__close(sockfd); + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; ++i) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/async.c b/src/unix/async.c new file mode 100644 index 0000000000..3c23e1d7fd --- /dev/null +++ b/src/unix/async.c @@ -0,0 +1,290 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* This file contains both the uv__async internal infrastructure and the + * user-facing uv_async_t functions. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents); +static int uv__async_make_pending(int* pending); +static int uv__async_eventfd(void); + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + int err; + + err = uv__async_start(loop, &loop->async_watcher, uv__async_event); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); + handle->async_cb = async_cb; + handle->pending = 0; + + QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); + uv__handle_start(handle); + + return 0; +} + + +int uv_async_send(uv_async_t* handle) { + if (uv__async_make_pending(&handle->pending) == 0) + uv__async_send(&handle->loop->async_watcher); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents) { + QUEUE* q; + uv_async_t* h; + + QUEUE_FOREACH(q, &loop->async_handles) { + h = QUEUE_DATA(q, uv_async_t, queue); + + if (h->pending == 0) + continue; + h->pending = 0; + + if (h->async_cb == NULL) + continue; + h->async_cb(h, 0); + } +} + + +static int uv__async_make_pending(int* pending) { + /* Do a cheap read first. */ + if (ACCESS_ONCE(int, *pending) != 0) + return 1; + + /* Micro-optimization: use atomic memory operations to detect if we've been + * preempted by another thread and don't have to make an expensive syscall. + * This speeds up the heavily contended case by about 1-2% and has little + * if any impact on the non-contended case. + * + * Use XCHG instead of the CMPXCHG that __sync_val_compare_and_swap() emits + * on x86, it's about 4x faster. It probably makes zero difference in the + * grand scheme of things but I'm OCD enough not to let this one pass. + */ +#if defined(__i386__) || defined(__x86_64__) + { + unsigned int val = 1; + __asm__ __volatile__ ("xchgl %0, %1" + : "+r" (val) + : "m" (*pending)); + return val != 0; + } +#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0) + return __sync_val_compare_and_swap(pending, 0, 1) != 0; +#else + ACCESS_ONCE(int, *pending) = 1; + return 0; +#endif +} + + +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + struct uv__async* wa; + char buf[1024]; + unsigned n; + ssize_t r; + + n = 0; + for (;;) { + r = read(w->fd, buf, sizeof(buf)); + + if (r > 0) + n += r; + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + wa = container_of(w, struct uv__async, io_watcher); + +#if defined(__linux__) + if (wa->wfd == -1) { + uint64_t val; + assert(n == sizeof(val)); + memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */ + wa->cb(loop, wa, val); + return; + } +#endif + + wa->cb(loop, wa, n); +} + + +void uv__async_send(struct uv__async* wa) { + const void* buf; + ssize_t len; + int fd; + int r; + + buf = ""; + len = 1; + fd = wa->wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = wa->io_watcher.fd; /* eventfd */ + } +#endif + + do + r = write(fd, buf, len); + while (r == -1 && errno == EINTR); + + if (r == len) + return; + + if (r == -1) + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + + abort(); +} + + +void uv__async_init(struct uv__async* wa) { + wa->io_watcher.fd = -1; + wa->wfd = -1; +} + + +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { + int pipefd[2]; + int err; + + if (wa->io_watcher.fd != -1) + return 0; + + err = uv__async_eventfd(); + if (err >= 0) { + pipefd[0] = err; + pipefd[1] = -1; + } + else if (err == -ENOSYS) + err = uv__make_pipe(pipefd, UV__F_NONBLOCK); + + if (err < 0) + return err; + + uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &wa->io_watcher, UV__POLLIN); + wa->wfd = pipefd[1]; + wa->cb = cb; + + return 0; +} + + +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { + if (wa->io_watcher.fd == -1) + return; + + uv__io_stop(loop, &wa->io_watcher, UV__POLLIN); + uv__close(wa->io_watcher.fd); + wa->io_watcher.fd = -1; + + if (wa->wfd != -1) { + uv__close(wa->wfd); + wa->wfd = -1; + } +} + + +static int uv__async_eventfd() { +#if defined(__linux__) + static int no_eventfd2; + static int no_eventfd; + int fd; + + if (no_eventfd2) + goto skip_eventfd2; + + fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + no_eventfd2 = 1; + +skip_eventfd2: + + if (no_eventfd) + goto skip_eventfd; + + fd = uv__eventfd(0); + if (fd != -1) { + uv__cloexec(fd, 1); + uv__nonblock(fd, 1); + return fd; + } + + if (errno != ENOSYS) + return -errno; + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return -ENOSYS; +} diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h new file mode 100644 index 0000000000..7e4e64beda --- /dev/null +++ b/src/unix/atomic-ops.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_ATOMIC_OPS_H_ +#define UV_ATOMIC_OPS_H_ + +#include "internal.h" /* UV_UNUSED */ + +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); +UV_UNUSED(static void cpu_relax(void)); + +/* Prefer hand-rolled assembly over the gcc builtins because the latter also + * issue full memory barriers. + */ +UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { +#if defined(__i386__) || defined(__x86_64__) + int out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile int*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { +#if defined(__i386__) || defined(__x86_64__) + long out; + __asm__ __volatile__ ("lock; cmpxchg %2, %1;" + : "=a" (out), "+m" (*(volatile long*) ptr) + : "r" (newval), "0" (oldval) + : "memory"); + return out; +#else + return __sync_val_compare_and_swap(ptr, oldval, newval); +#endif +} + +UV_UNUSED(static void cpu_relax(void)) { +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ +#endif +} + +#endif /* UV_ATOMIC_OPS_H_ */ diff --git a/src/unix/core.c b/src/unix/core.c new file mode 100644 index 0000000000..df2a5f8042 --- /dev/null +++ b/src/unix/core.c @@ -0,0 +1,787 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include /* NULL */ +#include /* printf */ +#include +#include /* strerror */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* INT_MAX, PATH_MAX */ +#include /* writev */ + +#ifdef __linux__ +# include +#endif + +#ifdef __sun +# include +# include +#endif + +#ifdef __APPLE__ +# include /* _NSGetExecutablePath */ +# include +# include +#endif + +#ifdef __FreeBSD__ +# include +# include +# include +# include +#endif + +static void uv__run_pending(uv_loop_t* loop); + +/* Verify that uv_buf_t is ABI-compatible with struct iovec. */ +STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) == + sizeof(((struct iovec*) 0)->iov_base)); +STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) == + sizeof(((struct iovec*) 0)->iov_len)); +STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); +STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); + + +uint64_t uv_hrtime(void) { + return uv__hrtime(UV_CLOCK_PRECISE); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + handle->flags |= UV_CLOSING; + handle->close_cb = close_cb; + + switch (handle->type) { + case UV_NAMED_PIPE: + uv__pipe_close((uv_pipe_t*)handle); + break; + + case UV_TTY: + uv__stream_close((uv_stream_t*)handle); + break; + + case UV_TCP: + uv__tcp_close((uv_tcp_t*)handle); + break; + + case UV_UDP: + uv__udp_close((uv_udp_t*)handle); + break; + + case UV_PREPARE: + uv__prepare_close((uv_prepare_t*)handle); + break; + + case UV_CHECK: + uv__check_close((uv_check_t*)handle); + break; + + case UV_IDLE: + uv__idle_close((uv_idle_t*)handle); + break; + + case UV_ASYNC: + uv__async_close((uv_async_t*)handle); + break; + + case UV_TIMER: + uv__timer_close((uv_timer_t*)handle); + break; + + case UV_PROCESS: + uv__process_close((uv_process_t*)handle); + break; + + case UV_FS_EVENT: + uv__fs_event_close((uv_fs_event_t*)handle); + break; + + case UV_POLL: + uv__poll_close((uv_poll_t*)handle); + break; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*)handle); + break; + + case UV_SIGNAL: + uv__signal_close((uv_signal_t*) handle); + /* Signal handles may not be closed immediately. The signal code will */ + /* itself close uv__make_close_pending whenever appropriate. */ + return; + + default: + assert(0); + } + + uv__make_close_pending(handle); +} + + +void uv__make_close_pending(uv_handle_t* handle) { + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->next_closing = handle->loop->closing_handles; + handle->loop->closing_handles = handle; +} + + +static void uv__finish_close(uv_handle_t* handle) { + /* Note: while the handle is in the UV_CLOSING state now, it's still possible + * for it to be active in the sense that uv__is_active() returns true. + * A good example is when the user calls uv_shutdown(), immediately followed + * by uv_close(). The handle is considered active at this point because the + * completion of the shutdown req is still pending. + */ + assert(handle->flags & UV_CLOSING); + assert(!(handle->flags & UV_CLOSED)); + handle->flags |= UV_CLOSED; + + switch (handle->type) { + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + case UV_ASYNC: + case UV_TIMER: + case UV_PROCESS: + case UV_FS_EVENT: + case UV_FS_POLL: + case UV_POLL: + case UV_SIGNAL: + break; + + case UV_NAMED_PIPE: + case UV_TCP: + case UV_TTY: + uv__stream_destroy((uv_stream_t*)handle); + break; + + case UV_UDP: + uv__udp_finish_close((uv_udp_t*)handle); + break; + + default: + assert(0); + break; + } + + uv__handle_unref(handle); + QUEUE_REMOVE(&handle->handle_queue); + + if (handle->close_cb) { + handle->close_cb(handle); + } +} + + +static void uv__run_closing_handles(uv_loop_t* loop) { + uv_handle_t* p; + uv_handle_t* q; + + p = loop->closing_handles; + loop->closing_handles = NULL; + + while (p) { + q = p->next_closing; + uv__finish_close(p); + p = q; + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return uv__is_closing(handle); +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return loop->backend_fd; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) + return 0; + + if (!QUEUE_EMPTY(&loop->idle_handles)) + return 0; + + if (loop->closing_handles) + return 0; + + return uv__next_timeout(loop); +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + loop->closing_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t* loop, uv_run_mode mode) { + int timeout; + int r; + + r = uv__loop_alive(loop); + if (!r) + uv__update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + UV_TICK_START(loop, mode); + + uv__update_time(loop); + uv__run_timers(loop); + uv__run_idle(loop); + uv__run_prepare(loop); + uv__run_pending(loop); + + timeout = 0; + if ((mode & UV_RUN_NOWAIT) == 0) + timeout = uv_backend_timeout(loop); + + uv__io_poll(loop, timeout); + uv__run_check(loop); + uv__run_closing_handles(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progess: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv__update_time(loop); + uv__run_timers(loop); + } + + r = uv__loop_alive(loop); + UV_TICK_STOP(loop, mode); + + if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + break; + } + + /* The if statement lets gcc compile it to a conditional store. Avoids + * dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} + + +void uv_update_time(uv_loop_t* loop) { + uv__update_time(loop); +} + + +int uv_is_active(const uv_handle_t* handle) { + return uv__is_active(handle); +} + + +/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ +int uv__socket(int domain, int type, int protocol) { + int sockfd; + int err; + +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) + sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); + if (sockfd != -1) + return sockfd; + + if (errno != EINVAL) + return -errno; +#endif + + sockfd = socket(domain, type, protocol); + if (sockfd == -1) + return -errno; + + err = uv__nonblock(sockfd, 1); + if (err == 0) + err = uv__cloexec(sockfd, 1); + + if (err) { + uv__close(sockfd); + return err; + } + +#if defined(SO_NOSIGPIPE) + { + int on = 1; + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); + } +#endif + + return sockfd; +} + + +int uv__accept(int sockfd) { + int peerfd; + int err; + + assert(sockfd >= 0); + + while (1) { +#if defined(__linux__) + static int no_accept4; + + if (no_accept4) + goto skip; + + peerfd = uv__accept4(sockfd, + NULL, + NULL, + UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); + if (peerfd != -1) + return peerfd; + + if (errno == EINTR) + continue; + + if (errno != ENOSYS) + return -errno; + + no_accept4 = 1; +skip: +#endif + + peerfd = accept(sockfd, NULL, NULL); + if (peerfd == -1) { + if (errno == EINTR) + continue; + return -errno; + } + + err = uv__cloexec(peerfd, 1); + if (err == 0) + err = uv__nonblock(peerfd, 1); + + if (err) { + uv__close(peerfd); + return err; + } + + return peerfd; + } +} + + +int uv__close(int fd) { + int saved_errno; + int rc; + + assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + + saved_errno = errno; + rc = close(fd); + if (rc == -1) { + rc = -errno; + if (rc == -EINTR) + rc = -EINPROGRESS; /* For platform/libc consistency. */ + errno = saved_errno; + } + + return rc; +} + + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) + +int uv__nonblock(int fd, int set) { + int r; + + do + r = ioctl(fd, FIONBIO, &set); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec(int fd, int set) { + int r; + + do + r = ioctl(fd, set ? FIOCLEX : FIONCLEX); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + +#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) */ + +int uv__nonblock(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFL); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & O_NONBLOCK) == !!set) + return 0; + + if (set) + flags = r | O_NONBLOCK; + else + flags = r & ~O_NONBLOCK; + + do + r = fcntl(fd, F_SETFL, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + + +int uv__cloexec(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFD); + while (r == -1 && errno == EINTR); + + if (r == -1) + return -errno; + + /* Bail out now if already set/clear. */ + if (!!(r & FD_CLOEXEC) == !!set) + return 0; + + if (set) + flags = r | FD_CLOEXEC; + else + flags = r & ~FD_CLOEXEC; + + do + r = fcntl(fd, F_SETFD, flags); + while (r == -1 && errno == EINTR); + + if (r) + return -errno; + + return 0; +} + +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */ + + +/* This function is not execve-safe, there is a race window + * between the call to dup() and fcntl(FD_CLOEXEC). + */ +int uv__dup(int fd) { + int err; + + fd = dup(fd); + + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { + struct cmsghdr* cmsg; + ssize_t rc; + int* pfd; + int* end; +#if defined(__linux__) + static int no_msg_cmsg_cloexec; + if (no_msg_cmsg_cloexec == 0) { + rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ + if (rc != -1) + return rc; + if (errno != EINVAL) + return -errno; + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return -errno; + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return -errno; + if (msg->msg_controllen == 0) + return rc; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) + if (cmsg->cmsg_type == SCM_RIGHTS) + for (pfd = (int*) CMSG_DATA(cmsg), + end = (int*) ((char*) cmsg + cmsg->cmsg_len); + pfd < end; + pfd += 1) + uv__cloexec(*pfd, 1); + return rc; +} + + +int uv_cwd(char* buffer, size_t size) { + if (buffer == NULL) + return -EINVAL; + + if (size == 0) + return -EINVAL; + + if (getcwd(buffer, size) == NULL) + return -errno; + + return 0; +} + + +int uv_chdir(const char* dir) { + if (chdir(dir)) + return -errno; + + return 0; +} + + +void uv_disable_stdio_inheritance(void) { + int fd; + + /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the + * first 16 file descriptors. After that, bail out after the first error. + */ + for (fd = 0; ; fd++) + if (uv__cloexec(fd, 1) && fd > 15) + break; +} + + +static void uv__run_pending(uv_loop_t* loop) { + QUEUE* q; + uv__io_t* w; + + while (!QUEUE_EMPTY(&loop->pending_queue)) { + q = QUEUE_HEAD(&loop->pending_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, pending_queue); + w->cb(loop, w, UV__POLLOUT); + } +} + + +static unsigned int next_power_of_two(unsigned int val) { + val -= 1; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val += 1; + return val; +} + +static void maybe_resize(uv_loop_t* loop, unsigned int len) { + uv__io_t** watchers; + void* fake_watcher_list; + void* fake_watcher_count; + unsigned int nwatchers; + unsigned int i; + + if (len <= loop->nwatchers) + return; + + /* Preserve fake watcher list and count at the end of the watchers */ + if (loop->watchers != NULL) { + fake_watcher_list = loop->watchers[loop->nwatchers]; + fake_watcher_count = loop->watchers[loop->nwatchers + 1]; + } else { + fake_watcher_list = NULL; + fake_watcher_count = NULL; + } + + nwatchers = next_power_of_two(len + 2) - 2; + watchers = realloc(loop->watchers, + (nwatchers + 2) * sizeof(loop->watchers[0])); + + if (watchers == NULL) + abort(); + for (i = loop->nwatchers; i < nwatchers; i++) + watchers[i] = NULL; + watchers[nwatchers] = fake_watcher_list; + watchers[nwatchers + 1] = fake_watcher_count; + + loop->watchers = watchers; + loop->nwatchers = nwatchers; +} + + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { + assert(cb != NULL); + assert(fd >= -1); + QUEUE_INIT(&w->pending_queue); + QUEUE_INIT(&w->watcher_queue); + w->cb = cb; + w->fd = fd; + w->events = 0; + w->pevents = 0; + +#if defined(UV_HAVE_KQUEUE) + w->rcount = 0; + w->wcount = 0; +#endif /* defined(UV_HAVE_KQUEUE) */ +} + + +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 != events); + assert(w->fd >= 0); + assert(w->fd < INT_MAX); + + w->pevents |= events; + maybe_resize(loop, w->fd + 1); + +#if !defined(__sun) + /* The event ports backend needs to rearm all file descriptors on each and + * every tick of the event loop but the other backends allow us to + * short-circuit here if the event mask is unchanged. + */ + if (w->events == w->pevents) { + if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + } + return; + } +#endif + + if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + + if (loop->watchers[w->fd] == NULL) { + loop->watchers[w->fd] = w; + loop->nfds++; + } +} + + +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 != events); + + if (w->fd == -1) + return; + + assert(w->fd >= 0); + + /* Happens when uv__io_stop() is called on a handle that was never started. */ + if ((unsigned) w->fd >= loop->nwatchers) + return; + + w->pevents &= ~events; + + if (w->pevents == 0) { + QUEUE_REMOVE(&w->watcher_queue); + QUEUE_INIT(&w->watcher_queue); + + if (loop->watchers[w->fd] != NULL) { + assert(loop->watchers[w->fd] == w); + assert(loop->nfds > 0); + loop->watchers[w->fd] = NULL; + loop->nfds--; + w->events = 0; + } + } + else if (QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); +} + + +void uv__io_close(uv_loop_t* loop, uv__io_t* w) { + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + QUEUE_REMOVE(&w->pending_queue); + + /* Remove stale events for this file descriptor */ + uv__platform_invalidate_fd(loop, w->fd); +} + + +void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { + if (QUEUE_EMPTY(&w->pending_queue)) + QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); +} + + +int uv__io_active(const uv__io_t* w, unsigned int events) { + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 != events); + return 0 != (w->pevents & events); +} diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c new file mode 100644 index 0000000000..8cd358bcf0 --- /dev/null +++ b/src/unix/darwin-proctitle.c @@ -0,0 +1,203 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#if !TARGET_OS_IPHONE +# include +# include +#endif + + +static int uv__pthread_setname_np(const char* name) { + int (*dynamic_pthread_setname_np)(const char* name); + char namebuf[64]; /* MAXTHREADNAMESIZE */ + int err; + + /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ + dynamic_pthread_setname_np = dlsym(RTLD_DEFAULT, "pthread_setname_np"); + if (dynamic_pthread_setname_np == NULL) + return -ENOSYS; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + err = dynamic_pthread_setname_np(namebuf); + if (err) + return -err; + + return 0; +} + + +int uv__set_process_title(const char* title) { +#if TARGET_OS_IPHONE + return uv__pthread_setname_np(title); +#else + CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); + CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); + void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); + void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); + CFTypeRef (*pLSGetCurrentApplicationASN)(void); + OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); + void* application_services_handle; + void* core_foundation_handle; + CFBundleRef launch_services_bundle; + CFStringRef* display_name_key; + CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); + CFBundleRef (*pCFBundleGetMainBundle)(void); + CFBundleRef hi_services_bundle; + OSStatus (*pSetApplicationIsDaemon)(int); + CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); + void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, + void*); + CFTypeRef asn; + int err; + + err = -ENOENT; + application_services_handle = dlopen("/System/Library/Frameworks/" + "ApplicationServices.framework/" + "Versions/A/ApplicationServices", + RTLD_LAZY | RTLD_LOCAL); + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + + if (application_services_handle == NULL || core_foundation_handle == NULL) + goto out; + + pCFStringCreateWithCString = + dlsym(core_foundation_handle, "CFStringCreateWithCString"); + pCFBundleGetBundleWithIdentifier = + dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier"); + pCFBundleGetDataPointerForName = + dlsym(core_foundation_handle, "CFBundleGetDataPointerForName"); + pCFBundleGetFunctionPointerForName = + dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName"); + + if (pCFStringCreateWithCString == NULL || + pCFBundleGetBundleWithIdentifier == NULL || + pCFBundleGetDataPointerForName == NULL || + pCFBundleGetFunctionPointerForName == NULL) { + goto out; + } + +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) + + launch_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); + + if (launch_services_bundle == NULL) + goto out; + + pLSGetCurrentApplicationASN = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSGetCurrentApplicationASN")); + + if (pLSGetCurrentApplicationASN == NULL) + goto out; + + pLSSetApplicationInformationItem = + pCFBundleGetFunctionPointerForName(launch_services_bundle, + S("_LSSetApplicationInformationItem")); + + if (pLSSetApplicationInformationItem == NULL) + goto out; + + display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle, + S("_kLSDisplayNameKey")); + + if (display_name_key == NULL || *display_name_key == NULL) + goto out; + + pCFBundleGetInfoDictionary = dlsym(core_foundation_handle, + "CFBundleGetInfoDictionary"); + pCFBundleGetMainBundle = dlsym(core_foundation_handle, + "CFBundleGetMainBundle"); + if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) + goto out; + + /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ + hi_services_bundle = + pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); + err = -ENOENT; + if (hi_services_bundle == NULL) + goto out; + + pSetApplicationIsDaemon = pCFBundleGetFunctionPointerForName( + hi_services_bundle, + S("SetApplicationIsDaemon")); + pLSApplicationCheckIn = pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSApplicationCheckIn")); + pLSSetApplicationLaunchServicesServerConnectionStatus = + pCFBundleGetFunctionPointerForName( + launch_services_bundle, + S("_LSSetApplicationLaunchServicesServerConnectionStatus")); + if (pSetApplicationIsDaemon == NULL || + pLSApplicationCheckIn == NULL || + pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) { + goto out; + } + + if (pSetApplicationIsDaemon(1) != noErr) + goto out; + + pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); + + /* Check into process manager?! */ + pLSApplicationCheckIn(-2, + pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); + + asn = pLSGetCurrentApplicationASN(); + + err = -EINVAL; + if (pLSSetApplicationInformationItem(-2, /* Magic value. */ + asn, + *display_name_key, + S(title), + NULL) != noErr) { + goto out; + } + + uv__pthread_setname_np(title); /* Don't care if it fails. */ + err = 0; + +out: + if (core_foundation_handle != NULL) + dlclose(core_foundation_handle); + + if (application_services_handle != NULL) + dlclose(application_services_handle); + + return err; +#endif /* !TARGET_OS_IPHONE */ +} diff --git a/src/unix/darwin.c b/src/unix/darwin.c new file mode 100644 index 0000000000..bc282e7912 --- /dev/null +++ b/src/unix/darwin.c @@ -0,0 +1,324 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include /* _NSGetExecutablePath */ +#include +#include +#include /* sysconf */ + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + loop->cf_state = NULL; + + if (uv__kqueue_init(loop)) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__fsevents_loop_delete(loop); +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + mach_timebase_info_data_t info; + + if (mach_timebase_info(&info) != KERN_SUCCESS) + abort(); + + return mach_absolute_time() * info.numer / info.denom; +} + + +int uv_exepath(char* buffer, size_t* size) { + uint32_t usize; + int result; + char* path; + char* fullpath; + + if (buffer == NULL || size == NULL) + return -EINVAL; + + usize = *size; + result = _NSGetExecutablePath(buffer, &usize); + if (result) return result; + + path = malloc(2 * PATH_MAX); + fullpath = realpath(buffer, path); + if (fullpath == NULL) { + SAVE_ERRNO(free(path)); + return -errno; + } + + strncpy(buffer, fullpath, *size); + free(fullpath); + *size = strlen(buffer); + return 0; +} + + +uint64_t uv_get_free_memory(void) { + vm_statistics_data_t info; + mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t); + + if (host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t)&info, &count) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_MEMSIZE}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_resident_set_memory(size_t* rss) { + mach_msg_type_number_t count; + task_basic_info_data_t info; + kern_return_t err; + + count = TASK_BASIC_INFO_COUNT; + err = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t) &info, + &count); + (void) &err; + /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than + * KERN_SUCCESS implies a libuv bug. + */ + assert(err == KERN_SUCCESS); + *rss = info.resident_size; + + return 0; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + *uptime = now - info.tv_sec; + + return 0; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks); + char model[512]; + uint64_t cpuspeed; + size_t size; + unsigned int i; + natural_t numcpus; + mach_msg_type_number_t msg_type; + processor_cpu_load_info_data_t *info; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) + return -errno; + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, + (processor_info_array_t*)&info, + &msg_type) != KERN_SUCCESS) { + return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + } + + *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; /* FIXME(bnoordhuis) Deallocate info? */ + + *count = numcpus; + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier; + cpu_info->cpu_times.irq = 0; + + cpu_info->model = strdup(model); + cpu_info->speed = cpuspeed/1000000; + } + vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Mac OS X getifaddrs returns information related to Mac Addresses for + * various devices, such as firewire, etc. These are not relevant here. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/dl.c b/src/unix/dl.c new file mode 100644 index 0000000000..cbffe4aa26 --- /dev/null +++ b/src/unix/dl.c @@ -0,0 +1,83 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +static int uv__dlerror(uv_lib_t* lib); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + dlerror(); /* Reset error status. */ + lib->errmsg = NULL; + lib->handle = dlopen(filename, RTLD_LAZY); + return lib->handle ? 0 : uv__dlerror(lib); +} + + +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + free(lib->errmsg); + lib->errmsg = NULL; + } + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + dlclose(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + dlerror(); /* Reset error status. */ + *ptr = dlsym(lib->handle, name); + return uv__dlerror(lib); +} + + +const char* uv_dlerror(uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static int uv__dlerror(uv_lib_t* lib) { + const char* errmsg; + + if (lib->errmsg) + free(lib->errmsg); + + errmsg = dlerror(); + + if (errmsg) { + lib->errmsg = strdup(errmsg); + return -1; + } + else { + lib->errmsg = NULL; + return 0; + } +} diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c new file mode 100644 index 0000000000..dcae244bb1 --- /dev/null +++ b/src/unix/freebsd.c @@ -0,0 +1,425 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* VM_LOADAVG */ +#include +#include +#include /* sysconf */ +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#ifndef CPUSTATES +# define CPUSTATES 5U +#endif +#ifndef CP_USER +# define CP_USER 0 +# define CP_NICE 1 +# define CP_SYS 2 +# define CP_IDLE 3 +# define CP_INTR 4 +#endif + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + size_t cb; + + if (buffer == NULL || size == NULL) + return -EINVAL; + +#ifdef __DragonFly__ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ARGS; + mib[3] = getpid(); +#else + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; +#endif + + cb = *size; + if (sysctl(mib, 4, buffer, &cb, NULL, 0)) + return -errno; + *size = strlen(buffer); + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + int freecount; + size_t size = sizeof(freecount); + + if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) + return -errno; + + return (uint64_t) freecount * sysconf(_SC_PAGESIZE); + +} + + +uint64_t uv_get_total_memory(void) { + unsigned long info; + int which[] = {CTL_HW, HW_PHYSMEM}; + + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + int oid[4]; + + if (process_title) free(process_title); + process_title = strdup(title); + + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = getpid(); + + sysctl(oid, + ARRAY_SIZE(oid), + NULL, + NULL, + process_title, + strlen(process_title) + 1); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (process_title) { + strncpy(buffer, process_title, size); + } else { + if (size > 0) { + buffer[0] = '\0'; + } + } + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc *kinfo = NULL; + pid_t pid; + int nprocs; + size_t page_size = getpagesize(); + + pid = getpid(); + + kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) goto error; + + kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); + if (kinfo == NULL) goto error; + +#ifdef __DragonFly__ + *rss = kinfo->kp_vm_rssize * page_size; +#else + *rss = kinfo->ki_rssize * page_size; +#endif + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, + cur = 0; + uv_cpu_info_t* cpu_info; + const char* maxcpus_key; + const char* cptimes_key; + char model[512]; + long* cp_times; + int numcpus; + size_t size; + int i; + +#if defined(__DragonFly__) + /* This is not quite correct but DragonFlyBSD doesn't seem to have anything + * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, + * not per CPU). At least this stops uv_cpu_info() from failing completely. + */ + maxcpus_key = "hw.ncpu"; + cptimes_key = "kern.cp_time"; +#else + maxcpus_key = "kern.smp.maxcpus"; + cptimes_key = "kern.cp_times"; +#endif + + size = sizeof(model); + if (sysctlbyname("hw.model", &model, &size, NULL, 0)) + return -errno; + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { + SAVE_ERRNO(free(*cpu_infos)); + return -errno; + } + + /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of + * ncpu. + */ + size = sizeof(maxcpus); + if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { + SAVE_ERRNO(free(*cpu_infos)); + return -errno; + } + + size = maxcpus * CPUSTATES * sizeof(long); + + cp_times = malloc(size); + if (cp_times == NULL) { + free(*cpu_infos); + return -ENOMEM; + } + + if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { + SAVE_ERRNO(free(cp_times)); + SAVE_ERRNO(free(*cpu_infos)); + return -errno; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + + cpu_info->model = strdup(model); + cpu_info->speed = cpuspeed; + + cur+=CPUSTATES; + } + + free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == AF_LINK)) { + continue; + } + + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On FreeBSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/fs.c b/src/unix/fs.c new file mode 100644 index 0000000000..1aa6539cb4 --- /dev/null +++ b/src/unix/fs.c @@ -0,0 +1,971 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Caveat emptor: this file deviates from the libuv convention of returning + * negated errno codes. Most uv_fs_*() functions map directly to the system + * call of the same name. For more complex wrappers, it's easier to just + * return -1 with errno set. The dispatcher in uv__fs_work() takes care of + * getting the errno to the right place (req->result or as the return value.) + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) || defined(__sun) +# include +#elif defined(__APPLE__) || defined(__FreeBSD__) +# include +# include +#endif + +#define INIT(type) \ + do { \ + uv__req_init((loop), (req), UV_FS); \ + (req)->fs_type = UV_FS_ ## type; \ + (req)->result = 0; \ + (req)->ptr = NULL; \ + (req)->loop = loop; \ + (req)->path = NULL; \ + (req)->new_path = NULL; \ + (req)->cb = (cb); \ + } \ + while (0) + +#define PATH \ + do { \ + (req)->path = strdup(path); \ + if ((req)->path == NULL) \ + return -ENOMEM; \ + } \ + while (0) + +#define PATH2 \ + do { \ + size_t path_len; \ + size_t new_path_len; \ + path_len = strlen((path)) + 1; \ + new_path_len = strlen((new_path)) + 1; \ + (req)->path = malloc(path_len + new_path_len); \ + if ((req)->path == NULL) \ + return -ENOMEM; \ + (req)->new_path = (req)->path + path_len; \ + memcpy((void*) (req)->path, (path), path_len); \ + memcpy((void*) (req)->new_path, (new_path), new_path_len); \ + } \ + while (0) + +#define POST \ + do { \ + if ((cb) != NULL) { \ + uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ + return 0; \ + } \ + else { \ + uv__fs_work(&(req)->work_req); \ + uv__fs_done(&(req)->work_req, 0); \ + return (req)->result; \ + } \ + } \ + while (0) + + +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) && defined(F_FULLFSYNC) + return fcntl(req->file, F_FULLFSYNC); +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_futime(uv_fs_t* req) { +#if defined(__linux__) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + static int no_utimesat; + struct timespec ts[2]; + struct timeval tv[2]; + char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; + int r; + + if (no_utimesat) + goto skip; + + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + + r = uv__utimesat(req->file, NULL, ts, 0); + if (r == 0) + return r; + + if (errno != ENOSYS) + return r; + + no_utimesat = 1; + +skip: + + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; + snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); + + r = utimes(path, tv); + if (r == 0) + return r; + + switch (errno) { + case ENOENT: + if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) + break; + /* Fall through. */ + + case EACCES: + case ENOTDIR: + errno = ENOSYS; + break; + } + + return r; + +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__sun) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; +# if defined(__sun) + return futimesat(req->file, NULL, tv); +# else + return futimes(req->file, tv); +# endif +#else + errno = ENOSYS; + return -1; +#endif +} + + +static ssize_t uv__fs_read(uv_fs_t* req) { + if (req->off < 0) + return read(req->file, req->buf, req->len); + else + return pread(req->file, req->buf, req->len, req->off); +} + + +static int uv__fs_readdir_filter(const struct dirent* dent) { + return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; +} + + +/* This should have been called uv__fs_scandir(). */ +static ssize_t uv__fs_readdir(uv_fs_t* req) { + struct dirent **dents; + int saved_errno; + size_t off; + size_t len; + char *buf; + int i; + int n; + + dents = NULL; + n = scandir(req->path, &dents, uv__fs_readdir_filter, alphasort); + + if (n == 0) + goto out; /* osx still needs to deallocate some memory */ + else if (n == -1) + return n; + + len = 0; + + for (i = 0; i < n; i++) + len += strlen(dents[i]->d_name) + 1; + + buf = malloc(len); + + if (buf == NULL) { + errno = ENOMEM; + n = -1; + goto out; + } + + off = 0; + + for (i = 0; i < n; i++) { + len = strlen(dents[i]->d_name) + 1; + memcpy(buf + off, dents[i]->d_name, len); + off += len; + } + + req->ptr = buf; + +out: + saved_errno = errno; + if (dents != NULL) { + for (i = 0; i < n; i++) + free(dents[i]); + free(dents); + } + errno = saved_errno; + + return n; +} + + +static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = pathconf(req->path, _PC_PATH_MAX); + + if (len == -1) { +#if defined(PATH_MAX) + len = PATH_MAX; +#else + len = 4096; +#endif + } + + buf = malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + len = readlink(req->path, buf, len); + + if (len == -1) { + free(buf); + return -1; + } + + buf[len] = '\0'; + req->ptr = buf; + + return 0; +} + + +static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { + struct pollfd pfd; + int use_pread; + off_t offset; + ssize_t nsent; + ssize_t nread; + ssize_t nwritten; + size_t buflen; + size_t len; + ssize_t n; + int in_fd; + int out_fd; + char buf[8192]; + + len = req->len; + in_fd = req->flags; + out_fd = req->file; + offset = req->off; + use_pread = 1; + + /* Here are the rules regarding errors: + * + * 1. Read errors are reported only if nsent==0, otherwise we return nsent. + * The user needs to know that some data has already been sent, to stop + * them from sending it twice. + * + * 2. Write errors are always reported. Write errors are bad because they + * mean data loss: we've read data but now we can't write it out. + * + * We try to use pread() and fall back to regular read() if the source fd + * doesn't support positional reads, for example when it's a pipe fd. + * + * If we get EAGAIN when writing to the target fd, we poll() on it until + * it becomes writable again. + * + * FIXME: If we get a write error when use_pread==1, it should be safe to + * return the number of sent bytes instead of an error because pread() + * is, in theory, idempotent. However, special files in /dev or /proc + * may support pread() but not necessarily return the same data on + * successive reads. + * + * FIXME: There is no way now to signal that we managed to send *some* data + * before a write error. + */ + for (nsent = 0; (size_t) nsent < len; ) { + buflen = len - nsent; + + if (buflen > sizeof(buf)) + buflen = sizeof(buf); + + do + if (use_pread) + nread = pread(in_fd, buf, buflen, offset); + else + nread = read(in_fd, buf, buflen); + while (nread == -1 && errno == EINTR); + + if (nread == 0) + goto out; + + if (nread == -1) { + if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) { + use_pread = 0; + continue; + } + + if (nsent == 0) + nsent = -1; + + goto out; + } + + for (nwritten = 0; nwritten < nread; ) { + do + n = write(out_fd, buf + nwritten, nread - nwritten); + while (n == -1 && errno == EINTR); + + if (n != -1) { + nwritten += n; + continue; + } + + if (errno != EAGAIN && errno != EWOULDBLOCK) { + nsent = -1; + goto out; + } + + pfd.fd = out_fd; + pfd.events = POLLOUT; + pfd.revents = 0; + + do + n = poll(&pfd, 1, -1); + while (n == -1 && errno == EINTR); + + if (n == -1 || (pfd.revents & ~POLLOUT) != 0) { + errno = EIO; + nsent = -1; + goto out; + } + } + + offset += nread; + nsent += nread; + } + +out: + if (nsent != -1) + req->off = offset; + + return nsent; +} + + +static ssize_t uv__fs_sendfile(uv_fs_t* req) { + int in_fd; + int out_fd; + + in_fd = req->flags; + out_fd = req->file; + +#if defined(__linux__) || defined(__sun) + { + off_t off; + ssize_t r; + + off = req->off; + r = sendfile(out_fd, in_fd, &off, req->len); + + /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but + * it still writes out data. Fortunately, we can detect it by checking if + * the offset has been updated. + */ + if (r != -1 || off > req->off) { + r = off - req->off; + req->off = off; + return r; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#elif defined(__FreeBSD__) || defined(__APPLE__) + { + off_t len; + ssize_t r; + + /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in + * non-blocking mode and not all data could be written. If a non-zero + * number of bytes have been sent, we don't consider it an error. + */ + +#if defined(__FreeBSD__) + len = 0; + r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0); +#else + /* The darwin sendfile takes len as an input for the length to send, + * so make sure to initialize it with the caller's value. */ + len = req->len; + r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); +#endif + + if (r != -1 || len != 0) { + req->off += len; + return (ssize_t) len; + } + + if (errno == EINVAL || + errno == EIO || + errno == ENOTSOCK || + errno == EXDEV) { + errno = 0; + return uv__fs_sendfile_emul(req); + } + + return -1; + } +#else + /* Squelch compiler warnings. */ + (void) &in_fd; + (void) &out_fd; + + return uv__fs_sendfile_emul(req); +#endif +} + + +static ssize_t uv__fs_utime(uv_fs_t* req) { + struct utimbuf buf; + buf.actime = req->atime; + buf.modtime = req->mtime; + return utime(req->path, &buf); /* TODO use utimes() where available */ +} + + +static ssize_t uv__fs_write(uv_fs_t* req) { + ssize_t r; + + /* Serialize writes on OS X, concurrent write() and pwrite() calls result in + * data loss. We can't use a per-file descriptor lock, the descriptor may be + * a dup(). + */ +#if defined(__APPLE__) + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&lock); +#endif + + if (req->off < 0) + r = write(req->file, req->buf, req->len); + else + r = pwrite(req->file, req->buf, req->len, req->off); + +#if defined(__APPLE__) + pthread_mutex_unlock(&lock); +#endif + + return r; +} + +static void uv__to_stat(struct stat* src, uv_stat_t* dst) { + dst->st_dev = src->st_dev; + dst->st_mode = src->st_mode; + dst->st_nlink = src->st_nlink; + dst->st_uid = src->st_uid; + dst->st_gid = src->st_gid; + dst->st_rdev = src->st_rdev; + dst->st_ino = src->st_ino; + dst->st_size = src->st_size; + dst->st_blksize = src->st_blksize; + dst->st_blocks = src->st_blocks; + +#if defined(__APPLE__) + dst->st_atim.tv_sec = src->st_atimespec.tv_sec; + dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec; + dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +#elif defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) + dst->st_atim.tv_sec = src->st_atim.tv_sec; + dst->st_atim.tv_nsec = src->st_atim.tv_nsec; + dst->st_mtim.tv_sec = src->st_mtim.tv_sec; + dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; + dst->st_ctim.tv_sec = src->st_ctim.tv_sec; + dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; +# if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec; + dst->st_flags = src->st_flags; + dst->st_gen = src->st_gen; +# else + dst->st_birthtim.tv_sec = src->st_ctim.tv_sec; + dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec; + dst->st_flags = 0; + dst->st_gen = 0; +# endif +#else + dst->st_atim.tv_sec = src->st_atime; + dst->st_atim.tv_nsec = 0; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = 0; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = 0; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = 0; + dst->st_flags = 0; + dst->st_gen = 0; +#endif +} + + +static int uv__fs_stat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + ret = stat(path, &pbuf); + uv__to_stat(&pbuf, buf); + return ret; +} + + +static int uv__fs_lstat(const char *path, uv_stat_t *buf) { + struct stat pbuf; + int ret; + ret = lstat(path, &pbuf); + uv__to_stat(&pbuf, buf); + return ret; +} + + +static int uv__fs_fstat(int fd, uv_stat_t *buf) { + struct stat pbuf; + int ret; + ret = fstat(fd, &pbuf); + uv__to_stat(&pbuf, buf); + return ret; +} + + +static void uv__fs_work(struct uv__work* w) { + int retry_on_eintr; + uv_fs_t* req; + ssize_t r; + + req = container_of(w, uv_fs_t, work_req); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + + do { + errno = 0; + +#define X(type, action) \ + case UV_FS_ ## type: \ + r = action; \ + break; + + switch (req->fs_type) { + X(CHMOD, chmod(req->path, req->mode)); + X(CHOWN, chown(req->path, req->uid, req->gid)); + X(CLOSE, close(req->file)); + X(FCHMOD, fchmod(req->file, req->mode)); + X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(FDATASYNC, uv__fs_fdatasync(req)); + X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); + X(FSYNC, fsync(req->file)); + X(FTRUNCATE, ftruncate(req->file, req->off)); + X(FUTIME, uv__fs_futime(req)); + X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); + X(LINK, link(req->path, req->new_path)); + X(MKDIR, mkdir(req->path, req->mode)); + X(OPEN, open(req->path, req->flags, req->mode)); + X(READ, uv__fs_read(req)); + X(READDIR, uv__fs_readdir(req)); + X(READLINK, uv__fs_readlink(req)); + X(RENAME, rename(req->path, req->new_path)); + X(RMDIR, rmdir(req->path)); + X(SENDFILE, uv__fs_sendfile(req)); + X(STAT, uv__fs_stat(req->path, &req->statbuf)); + X(SYMLINK, symlink(req->path, req->new_path)); + X(UNLINK, unlink(req->path)); + X(UTIME, uv__fs_utime(req)); + X(WRITE, uv__fs_write(req)); + default: abort(); + } + +#undef X + } + while (r == -1 && errno == EINTR && retry_on_eintr); + + if (r == -1) + req->result = -errno; + else + req->result = r; + + if (r == 0 && (req->fs_type == UV_FS_STAT || + req->fs_type == UV_FS_FSTAT || + req->fs_type == UV_FS_LSTAT)) { + req->ptr = &req->statbuf; + } +} + + +static void uv__fs_done(struct uv__work* w, int status) { + uv_fs_t* req; + + req = container_of(w, uv_fs_t, work_req); + uv__req_unregister(req->loop, req); + + if (status == -ECANCELED) { + assert(req->result == 0); + req->result = -ECANCELED; + } + + if (req->cb != NULL) + req->cb(req); +} + + +int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(CHMOD); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(CHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(CLOSE); + req->file = file; + POST; +} + + +int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb) { + INIT(FCHMOD); + req->file = file; + req->mode = mode; + POST; +} + + +int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(FCHOWN); + req->file = file; + req->uid = uid; + req->gid = gid; + POST; +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FDATASYNC); + req->file = file; + POST; +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSTAT); + req->file = file; + POST; +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { + INIT(FSYNC); + req->file = file; + POST; +} + + +int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t off, + uv_fs_cb cb) { + INIT(FTRUNCATE); + req->file = file; + req->off = off; + POST; +} + + +int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(FUTIME); + req->file = file; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(LSTAT); + PATH; + POST; +} + + +int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(LINK); + PATH2; + POST; +} + + +int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb) { + INIT(MKDIR); + PATH; + req->mode = mode; + POST; +} + + +int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb) { + INIT(OPEN); + PATH; + req->flags = flags; + req->mode = mode; + POST; +} + + +int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, + uv_file file, + void* buf, + size_t len, + int64_t off, + uv_fs_cb cb) { + INIT(READ); + req->file = file; + req->buf = buf; + req->len = len; + req->off = off; + POST; +} + + +int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(READDIR); + PATH; + req->flags = flags; + POST; +} + + +int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + INIT(READLINK); + PATH; + POST; +} + + +int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb) { + INIT(RENAME); + PATH2; + POST; +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(RMDIR); + PATH; + POST; +} + + +int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t off, + size_t len, + uv_fs_cb cb) { + INIT(SENDFILE); + req->flags = in_fd; /* hack */ + req->file = out_fd; + req->off = off; + req->len = len; + POST; +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(STAT); + PATH; + POST; +} + + +int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(SYMLINK); + PATH2; + req->flags = flags; + POST; +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + INIT(UNLINK); + PATH; + POST; +} + + +int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb) { + INIT(UTIME); + PATH; + req->atime = atime; + req->mtime = mtime; + POST; +} + + +int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const void* buf, + size_t len, + int64_t off, + uv_fs_cb cb) { + INIT(WRITE); + req->file = file; + req->buf = (void*) buf; + req->len = len; + req->off = off; + POST; +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + free((void*) req->path); + req->path = NULL; + req->new_path = NULL; + + if (req->ptr != &req->statbuf) + free(req->ptr); + req->ptr = NULL; +} diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c new file mode 100644 index 0000000000..7faa1562a6 --- /dev/null +++ b/src/unix/fsevents.c @@ -0,0 +1,899 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#if TARGET_OS_IPHONE + +/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */ + +int uv__fsevents_init(uv_fs_event_t* handle) { + return 0; +} + + +int uv__fsevents_close(uv_fs_event_t* handle) { + return 0; +} + + +void uv__fsevents_loop_delete(uv_loop_t* loop) { +} + +#else /* TARGET_OS_IPHONE */ + +#include +#include +#include +#include + +#include +#include + +/* These are macros to avoid "initializer element is not constant" errors + * with old versions of gcc. + */ +#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \ + kFSEventStreamEventFlagItemModified | \ + kFSEventStreamEventFlagItemInodeMetaMod | \ + kFSEventStreamEventFlagItemChangeOwner | \ + kFSEventStreamEventFlagItemXattrMod) + +#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \ + kFSEventStreamEventFlagItemRemoved | \ + kFSEventStreamEventFlagItemRenamed) + +#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \ + kFSEventStreamEventFlagKernelDropped | \ + kFSEventStreamEventFlagEventIdsWrapped | \ + kFSEventStreamEventFlagHistoryDone | \ + kFSEventStreamEventFlagMount | \ + kFSEventStreamEventFlagUnmount | \ + kFSEventStreamEventFlagRootChanged) + +typedef struct uv__fsevents_event_s uv__fsevents_event_t; +typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; +typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; + +struct uv__cf_loop_signal_s { + QUEUE member; + uv_fs_event_t* handle; +}; + +struct uv__fsevents_event_s { + QUEUE member; + int events; + char path[1]; +}; + +struct uv__cf_loop_state_s { + CFRunLoopRef loop; + CFRunLoopSourceRef signal_source; + int fsevent_need_reschedule; + FSEventStreamRef fsevent_stream; + uv_sem_t fsevent_sem; + uv_mutex_t fsevent_mutex; + void* fsevent_handles[2]; + unsigned int fsevent_handle_count; +}; + +/* Forward declarations */ +static void uv__cf_loop_cb(void* arg); +static void* uv__cf_loop_runner(void* arg); +static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); + +/* Lazy-loaded by uv__fsevents_global_init(). */ +static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, + const void**, + CFIndex, + const CFArrayCallBacks*); +static void (*pCFRelease)(CFTypeRef); +static void (*pCFRunLoopAddSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static CFRunLoopRef (*pCFRunLoopGetCurrent)(void); +static void (*pCFRunLoopRemoveSource)(CFRunLoopRef, + CFRunLoopSourceRef, + CFStringRef); +static void (*pCFRunLoopRun)(void); +static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef, + CFIndex, + CFRunLoopSourceContext*); +static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); +static void (*pCFRunLoopStop)(CFRunLoopRef); +static void (*pCFRunLoopWakeUp)(CFRunLoopRef); +static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)( + CFAllocatorRef, + const char*); +static CFStringEncoding (*pCFStringGetSystemEncoding)(void); +static CFStringRef (*pkCFRunLoopDefaultMode); +static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, + FSEventStreamCallback, + FSEventStreamContext*, + CFArrayRef, + FSEventStreamEventId, + CFTimeInterval, + FSEventStreamCreateFlags); +static void (*pFSEventStreamFlushSync)(FSEventStreamRef); +static void (*pFSEventStreamInvalidate)(FSEventStreamRef); +static void (*pFSEventStreamRelease)(FSEventStreamRef); +static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, + CFRunLoopRef, + CFStringRef); +static Boolean (*pFSEventStreamStart)(FSEventStreamRef); +static void (*pFSEventStreamStop)(FSEventStreamRef); + +#define UV__FSEVENTS_PROCESS(handle, block) \ + do { \ + QUEUE events; \ + QUEUE* q; \ + uv__fsevents_event_t* event; \ + int err; \ + uv_mutex_lock(&(handle)->cf_mutex); \ + /* Split-off all events and empty original queue */ \ + QUEUE_INIT(&events); \ + if (!QUEUE_EMPTY(&(handle)->cf_events)) { \ + q = QUEUE_HEAD(&(handle)->cf_events); \ + QUEUE_SPLIT(&(handle)->cf_events, q, &events); \ + } \ + /* Get error (if any) and zero original one */ \ + err = (handle)->cf_error; \ + (handle)->cf_error = 0; \ + uv_mutex_unlock(&(handle)->cf_mutex); \ + /* Loop through events, deallocating each after processing */ \ + while (!QUEUE_EMPTY(&events)) { \ + q = QUEUE_HEAD(&events); \ + event = QUEUE_DATA(q, uv__fsevents_event_t, member); \ + QUEUE_REMOVE(q); \ + /* NOTE: Checking uv__is_active() is required here, because handle \ + * callback may close handle and invoking it after it will lead to \ + * incorrect behaviour */ \ + if (!uv__is_closing((handle)) && uv__is_active((handle))) \ + block \ + /* Free allocated data */ \ + free(event); \ + } \ + if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \ + (handle)->cb((handle), NULL, 0, err); \ + } while (0) + + +/* Runs in UV loop's thread, when there're events to report to handle */ +static void uv__fsevents_cb(uv_async_t* cb, int status) { + uv_fs_event_t* handle; + + handle = cb->data; + + UV__FSEVENTS_PROCESS(handle, { + handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0); + }); +} + + +/* Runs in CF thread, pushed event into handle's event list */ +static void uv__fsevents_push_event(uv_fs_event_t* handle, + QUEUE* events, + int err) { + assert(events != NULL || err != 0); + uv_mutex_lock(&handle->cf_mutex); + + /* Concatenate two queues */ + if (events != NULL) + QUEUE_ADD(&handle->cf_events, events); + + /* Propagate error */ + if (err != 0) + handle->cf_error = err; + uv_mutex_unlock(&handle->cf_mutex); + + uv_async_send(handle->cf_cb); +} + + +/* Runs in CF thread, when there're events in FSEventStream */ +static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, + void* info, + size_t numEvents, + void* eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { + size_t i; + int len; + char** paths; + char* path; + char* pos; + uv_fs_event_t* handle; + QUEUE* q; + uv_loop_t* loop; + uv__cf_loop_state_t* state; + uv__fsevents_event_t* event; + QUEUE head; + + loop = info; + state = loop->cf_state; + assert(state != NULL); + paths = eventPaths; + + /* For each handle */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); + QUEUE_INIT(&head); + + /* Process and filter out events */ + for (i = 0; i < numEvents; i++) { + /* Ignore system events */ + if (eventFlags[i] & kFSEventsSystem) + continue; + + path = paths[i]; + len = strlen(path); + + /* Filter out paths that are outside handle's request */ + if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + continue; + + if (handle->realpath_len > 1 || *handle->realpath != '/') { + path += handle->realpath_len; + len -= handle->realpath_len; + + /* Skip forward slash */ + if (*path != '\0') { + path++; + len--; + } + } + +#ifdef MAC_OS_X_VERSION_10_7 + /* Ignore events with path equal to directory itself */ + if (len == 0) + continue; +#endif /* MAC_OS_X_VERSION_10_7 */ + + /* Do not emit events from subdirectories (without option set) */ + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + pos = strchr(path + 1, '/'); + if (pos != NULL) + continue; + } + +#ifndef MAC_OS_X_VERSION_10_7 + path = ""; + len = 0; +#endif /* MAC_OS_X_VERSION_10_7 */ + + event = malloc(sizeof(*event) + len); + if (event == NULL) + break; + + memset(event, 0, sizeof(*event)); + memcpy(event->path, path, len + 1); + + if ((eventFlags[i] & kFSEventsModified) != 0 && + (eventFlags[i] & kFSEventsRenamed) == 0) + event->events = UV_CHANGE; + else + event->events = UV_RENAME; + + QUEUE_INSERT_TAIL(&head, &event->member); + } + + if (!QUEUE_EMPTY(&head)) + uv__fsevents_push_event(handle, &head, 0); + } + uv_mutex_unlock(&state->fsevent_mutex); +} + + +/* Runs in CF thread */ +static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { + uv__cf_loop_state_t* state; + FSEventStreamContext ctx; + FSEventStreamRef ref; + CFAbsoluteTime latency; + FSEventStreamCreateFlags flags; + + /* Initialize context */ + ctx.version = 0; + ctx.info = loop; + ctx.retain = NULL; + ctx.release = NULL; + ctx.copyDescription = NULL; + + latency = 0.05; + + /* Explanation of selected flags: + * 1. NoDefer - without this flag, events that are happening continuously + * (i.e. each event is happening after time interval less than `latency`, + * counted from previous event), will be deferred and passed to callback + * once they'll either fill whole OS buffer, or when this continuous stream + * will stop (i.e. there'll be delay between events, bigger than + * `latency`). + * Specifying this flag will invoke callback after `latency` time passed + * since event. + * 2. FileEvents - fire callback for file changes too (by default it is firing + * it only for directory changes). + */ + flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents; + + /* + * NOTE: It might sound like a good idea to remember last seen StreamEventId, + * but in reality one dir might have last StreamEventId less than, the other, + * that is being watched now. Which will cause FSEventStream API to report + * changes to files from the past. + */ + ref = pFSEventStreamCreate(NULL, + &uv__fsevents_event_cb, + &ctx, + paths, + kFSEventStreamEventIdSinceNow, + latency, + flags); + assert(ref != NULL); + + state = loop->cf_state; + pFSEventStreamScheduleWithRunLoop(ref, + state->loop, + *pkCFRunLoopDefaultMode); + if (!pFSEventStreamStart(ref)) { + pFSEventStreamInvalidate(ref); + pFSEventStreamRelease(ref); + return -EMFILE; + } + + state->fsevent_stream = ref; + return 0; +} + + +/* Runs in CF thread */ +static void uv__fsevents_destroy_stream(uv_loop_t* loop) { + uv__cf_loop_state_t* state; + + state = loop->cf_state; + + if (state->fsevent_stream == NULL) + return; + + /* Flush all accumulated events */ + pFSEventStreamFlushSync(state->fsevent_stream); + + /* Stop emitting events */ + pFSEventStreamStop(state->fsevent_stream); + + /* Release stream */ + pFSEventStreamInvalidate(state->fsevent_stream); + pFSEventStreamRelease(state->fsevent_stream); + state->fsevent_stream = NULL; +} + + +/* Runs in CF thread, when there're new fsevent handles to add to stream */ +static void uv__fsevents_reschedule(uv_fs_event_t* handle) { + uv__cf_loop_state_t* state; + QUEUE* q; + uv_fs_event_t* curr; + CFArrayRef cf_paths; + CFStringRef* paths; + unsigned int i; + int err; + unsigned int path_count; + + state = handle->loop->cf_state; + paths = NULL; + cf_paths = NULL; + err = 0; + /* NOTE: `i` is used in deallocation loop below */ + i = 0; + + /* Optimization to prevent O(n^2) time spent when starting to watch + * many files simultaneously + */ + uv_mutex_lock(&state->fsevent_mutex); + if (state->fsevent_need_reschedule == 0) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + state->fsevent_need_reschedule = 0; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Destroy previous FSEventStream */ + uv__fsevents_destroy_stream(handle->loop); + + /* Any failure below will be a memory failure */ + err = -ENOMEM; + + /* Create list of all watched paths */ + uv_mutex_lock(&state->fsevent_mutex); + path_count = state->fsevent_handle_count; + if (path_count != 0) { + paths = malloc(sizeof(*paths) * path_count); + if (paths == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + + q = &state->fsevent_handles; + for (; i < path_count; i++) { + q = QUEUE_NEXT(q); + assert(q != &state->fsevent_handles); + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + + assert(curr->realpath != NULL); + paths[i] = + pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath); + if (paths[i] == NULL) { + uv_mutex_unlock(&state->fsevent_mutex); + goto final; + } + } + } + uv_mutex_unlock(&state->fsevent_mutex); + err = 0; + + if (path_count != 0) { + /* Create new FSEventStream */ + cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); + if (cf_paths == NULL) { + err = -ENOMEM; + goto final; + } + err = uv__fsevents_create_stream(handle->loop, cf_paths); + } + +final: + /* Deallocate all paths in case of failure */ + if (err != 0) { + if (cf_paths == NULL) { + while (i != 0) + pCFRelease(paths[--i]); + free(paths); + } else { + /* CFArray takes ownership of both strings and original C-array */ + pCFRelease(cf_paths); + } + + /* Broadcast error to all handles */ + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_FOREACH(q, &state->fsevent_handles) { + curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + uv__fsevents_push_event(curr, NULL, err); + } + uv_mutex_unlock(&state->fsevent_mutex); + } + + /* + * Main thread will block until the removal of handle from the list, + * we must tell it when we're ready. + * + * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` + */ + if (!uv__is_active(handle)) + uv_sem_post(&state->fsevent_sem); +} + + +static int uv__fsevents_global_init(void) { + static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER; + static void* core_foundation_handle; + static void* core_services_handle; + int err; + + err = 0; + pthread_mutex_lock(&global_init_mutex); + if (core_foundation_handle != NULL) + goto out; + + /* The libraries are never unloaded because we currently don't have a good + * mechanism for keeping a reference count. It's unlikely to be an issue + * but if it ever becomes one, we can turn the dynamic library handles into + * per-event loop properties and have the dynamic linker keep track for us. + */ + err = -ENOSYS; + core_foundation_handle = dlopen("/System/Library/Frameworks/" + "CoreFoundation.framework/" + "Versions/A/CoreFoundation", + RTLD_LAZY | RTLD_LOCAL); + if (core_foundation_handle == NULL) + goto out; + + core_services_handle = dlopen("/System/Library/Frameworks/" + "CoreServices.framework/" + "Versions/A/CoreServices", + RTLD_LAZY | RTLD_LOCAL); + if (core_services_handle == NULL) + goto out; + + err = -ENOENT; +#define V(handle, symbol) \ + do { \ + p ## symbol = dlsym((handle), #symbol); \ + if (p ## symbol == NULL) \ + goto out; \ + } \ + while (0) + V(core_foundation_handle, CFArrayCreate); + V(core_foundation_handle, CFRelease); + V(core_foundation_handle, CFRunLoopAddSource); + V(core_foundation_handle, CFRunLoopGetCurrent); + V(core_foundation_handle, CFRunLoopRemoveSource); + V(core_foundation_handle, CFRunLoopRun); + V(core_foundation_handle, CFRunLoopSourceCreate); + V(core_foundation_handle, CFRunLoopSourceSignal); + V(core_foundation_handle, CFRunLoopStop); + V(core_foundation_handle, CFRunLoopWakeUp); + V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation); + V(core_foundation_handle, CFStringGetSystemEncoding); + V(core_foundation_handle, kCFRunLoopDefaultMode); + V(core_services_handle, FSEventStreamCreate); + V(core_services_handle, FSEventStreamFlushSync); + V(core_services_handle, FSEventStreamInvalidate); + V(core_services_handle, FSEventStreamRelease); + V(core_services_handle, FSEventStreamScheduleWithRunLoop); + V(core_services_handle, FSEventStreamStart); + V(core_services_handle, FSEventStreamStop); +#undef V + err = 0; + +out: + if (err && core_services_handle != NULL) { + dlclose(core_services_handle); + core_services_handle = NULL; + } + + if (err && core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } + + pthread_mutex_unlock(&global_init_mutex); + return err; +} + + +/* Runs in UV loop */ +static int uv__fsevents_loop_init(uv_loop_t* loop) { + CFRunLoopSourceContext ctx; + uv__cf_loop_state_t* state; + pthread_attr_t attr_storage; + pthread_attr_t* attr; + int err; + + if (loop->cf_state != NULL) + return 0; + + err = uv__fsevents_global_init(); + if (err) + return err; + + state = calloc(1, sizeof(*state)); + if (state == NULL) + return -ENOMEM; + + err = uv_mutex_init(&loop->cf_mutex); + if (err) + goto fail_mutex_init; + + err = uv_sem_init(&loop->cf_sem, 0); + if (err) + goto fail_sem_init; + + QUEUE_INIT(&loop->cf_signals); + + err = uv_sem_init(&state->fsevent_sem, 0); + if (err) + goto fail_fsevent_sem_init; + + err = uv_mutex_init(&state->fsevent_mutex); + if (err) + goto fail_fsevent_mutex_init; + + QUEUE_INIT(&state->fsevent_handles); + state->fsevent_need_reschedule = 0; + state->fsevent_handle_count = 0; + + memset(&ctx, 0, sizeof(ctx)); + ctx.info = loop; + ctx.perform = uv__cf_loop_cb; + state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); + if (state->signal_source == NULL) { + err = -ENOMEM; + goto fail_signal_source_create; + } + + /* In the unlikely event that pthread_attr_init() fails, create the thread + * with the default stack size. We'll use a little more address space but + * that in itself is not a fatal error. + */ + attr = &attr_storage; + if (pthread_attr_init(attr)) + attr = NULL; + + if (attr != NULL) + if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN)) + abort(); + + loop->cf_state = state; + + /* uv_thread_t is an alias for pthread_t. */ + err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); + + if (attr != NULL) + pthread_attr_destroy(attr); + + if (err) + goto fail_thread_create; + + /* Synchronize threads */ + uv_sem_wait(&loop->cf_sem); + return 0; + +fail_thread_create: + loop->cf_state = NULL; + +fail_signal_source_create: + uv_mutex_destroy(&state->fsevent_mutex); + +fail_fsevent_mutex_init: + uv_sem_destroy(&state->fsevent_sem); + +fail_fsevent_sem_init: + uv_sem_destroy(&loop->cf_sem); + +fail_sem_init: + uv_mutex_destroy(&loop->cf_mutex); + +fail_mutex_init: + free(state); + return err; +} + + +/* Runs in UV loop */ +void uv__fsevents_loop_delete(uv_loop_t* loop) { + uv__cf_loop_signal_t* s; + uv__cf_loop_state_t* state; + QUEUE* q; + + if (loop->cf_state == NULL) + return; + + if (uv__cf_loop_signal(loop, NULL) != 0) + abort(); + + uv_thread_join(&loop->cf_thread); + uv_sem_destroy(&loop->cf_sem); + uv_mutex_destroy(&loop->cf_mutex); + + /* Free any remaining data */ + while (!QUEUE_EMPTY(&loop->cf_signals)) { + q = QUEUE_HEAD(&loop->cf_signals); + s = QUEUE_DATA(q, uv__cf_loop_signal_t, member); + QUEUE_REMOVE(q); + free(s); + } + + /* Destroy state */ + state = loop->cf_state; + uv_sem_destroy(&state->fsevent_sem); + uv_mutex_destroy(&state->fsevent_mutex); + pCFRelease(state->signal_source); + free(state); + loop->cf_state = NULL; +} + + +/* Runs in CF thread. This is the CF loop's body */ +static void* uv__cf_loop_runner(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + + loop = arg; + state = loop->cf_state; + state->loop = pCFRunLoopGetCurrent(); + + pCFRunLoopAddSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + uv_sem_post(&loop->cf_sem); + + pCFRunLoopRun(); + pCFRunLoopRemoveSource(state->loop, + state->signal_source, + *pkCFRunLoopDefaultMode); + + return NULL; +} + + +/* Runs in CF thread, executed after `uv__cf_loop_signal()` */ +static void uv__cf_loop_cb(void* arg) { + uv_loop_t* loop; + uv__cf_loop_state_t* state; + QUEUE* item; + QUEUE split_head; + uv__cf_loop_signal_t* s; + + loop = arg; + state = loop->cf_state; + QUEUE_INIT(&split_head); + + uv_mutex_lock(&loop->cf_mutex); + if (!QUEUE_EMPTY(&loop->cf_signals)) { + QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals); + QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head); + } + uv_mutex_unlock(&loop->cf_mutex); + + while (!QUEUE_EMPTY(&split_head)) { + item = QUEUE_HEAD(&split_head); + + s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); + + /* This was a termination signal */ + if (s->handle == NULL) + pCFRunLoopStop(state->loop); + else + uv__fsevents_reschedule(s->handle); + + QUEUE_REMOVE(item); + free(s); + } +} + + +/* Runs in UV loop to notify CF thread */ +int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__cf_loop_signal_t* item; + uv__cf_loop_state_t* state; + + item = malloc(sizeof(*item)); + if (item == NULL) + return -ENOMEM; + + item->handle = handle; + + uv_mutex_lock(&loop->cf_mutex); + QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); + uv_mutex_unlock(&loop->cf_mutex); + + state = loop->cf_state; + assert(state != NULL); + pCFRunLoopSourceSignal(state->signal_source); + pCFRunLoopWakeUp(state->loop); + + return 0; +} + + +/* Runs in UV loop to initialize handle */ +int uv__fsevents_init(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + err = uv__fsevents_loop_init(handle->loop); + if (err) + return err; + + /* Get absolute path to file */ + handle->realpath = realpath(handle->filename, NULL); + if (handle->realpath == NULL) + return -errno; + handle->realpath_len = strlen(handle->realpath); + + /* Initialize event queue */ + QUEUE_INIT(&handle->cf_events); + handle->cf_error = 0; + + /* + * Events will occur in other thread. + * Initialize callback for getting them back into event loop's thread + */ + handle->cf_cb = malloc(sizeof(*handle->cf_cb)); + if (handle->cf_cb == NULL) { + err = -ENOMEM; + goto fail_cf_cb_malloc; + } + + handle->cf_cb->data = handle; + uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); + handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + uv_unref((uv_handle_t*) handle->cf_cb); + + err = uv_mutex_init(&handle->cf_mutex); + if (err) + goto fail_cf_mutex_init; + + /* Insert handle into the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member); + state->fsevent_handle_count++; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle); + if (err) + goto fail_loop_signal; + + return 0; + +fail_loop_signal: + uv_mutex_destroy(&handle->cf_mutex); + +fail_cf_mutex_init: + free(handle->cf_cb); + handle->cf_cb = NULL; + +fail_cf_cb_malloc: + free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return err; +} + + +/* Runs in UV loop to de-initialize handle */ +int uv__fsevents_close(uv_fs_event_t* handle) { + int err; + uv__cf_loop_state_t* state; + + if (handle->cf_cb == NULL) + return -EINVAL; + + /* Remove handle from the list */ + state = handle->loop->cf_state; + uv_mutex_lock(&state->fsevent_mutex); + QUEUE_REMOVE(&handle->cf_member); + state->fsevent_handle_count--; + state->fsevent_need_reschedule = 1; + uv_mutex_unlock(&state->fsevent_mutex); + + /* Reschedule FSEventStream */ + assert(handle != NULL); + err = uv__cf_loop_signal(handle->loop, handle); + if (err) + return -err; + + /* Wait for deinitialization */ + uv_sem_wait(&state->fsevent_sem); + + uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free); + handle->cf_cb = NULL; + + /* Free data in queue */ + UV__FSEVENTS_PROCESS(handle, { + /* NOP */ + }); + + uv_mutex_destroy(&handle->cf_mutex); + free(handle->realpath); + handle->realpath = NULL; + handle->realpath_len = 0; + + return 0; +} + +#endif /* TARGET_OS_IPHONE */ diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c new file mode 100644 index 0000000000..1db00680d1 --- /dev/null +++ b/src/unix/getaddrinfo.c @@ -0,0 +1,135 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include /* NULL */ +#include +#include + + +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + int err; + + req = container_of(w, uv_getaddrinfo_t, work_req); + err = getaddrinfo(req->hostname, req->service, req->hints, &req->res); + req->retcode = uv__getaddrinfo_translate_error(err); +} + + +static void uv__getaddrinfo_done(struct uv__work* w, int status) { + uv_getaddrinfo_t* req; + struct addrinfo *res; + + req = container_of(w, uv_getaddrinfo_t, work_req); + uv__req_unregister(req->loop, req); + + res = req->res; + req->res = NULL; + + /* See initialization in uv_getaddrinfo(). */ + if (req->hints) + free(req->hints); + else if (req->service) + free(req->service); + else if (req->hostname) + free(req->hostname); + else + assert(0); + + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + + if (status == -ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + } + + req->cb(req, req->retcode, res); +} + + +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb cb, + const char* hostname, + const char* service, + const struct addrinfo* hints) { + size_t hostname_len; + size_t service_len; + size_t hints_len; + size_t len; + char* buf; + + if (req == NULL || cb == NULL || (hostname == NULL && service == NULL)) + return -EINVAL; + + hostname_len = hostname ? strlen(hostname) + 1 : 0; + service_len = service ? strlen(service) + 1 : 0; + hints_len = hints ? sizeof(*hints) : 0; + buf = malloc(hostname_len + service_len + hints_len); + + if (buf == NULL) + return -ENOMEM; + + uv__req_init(loop, req, UV_GETADDRINFO); + req->loop = loop; + req->cb = cb; + req->res = NULL; + req->hints = NULL; + req->service = NULL; + req->hostname = NULL; + req->retcode = 0; + + /* order matters, see uv_getaddrinfo_done() */ + len = 0; + + if (hints) { + req->hints = memcpy(buf + len, hints, sizeof(*hints)); + len += sizeof(*hints); + } + + if (service) { + req->service = memcpy(buf + len, service, service_len); + len += service_len; + } + + if (hostname) { + req->hostname = memcpy(buf + len, hostname, hostname_len); + len += hostname_len; + } + + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); + + return 0; +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + if (ai) + freeaddrinfo(ai); +} diff --git a/src/unix/internal.h b/src/unix/internal.h new file mode 100644 index 0000000000..0ea82b51a0 --- /dev/null +++ b/src/unix/internal.h @@ -0,0 +1,296 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "uv-common.h" + +#include +#include /* abort */ +#include /* strrchr */ + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__sun) +# include +# include +#endif /* __sun */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +#endif + +#define STATIC_ASSERT(expr) \ + void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) + +#define ACCESS_ONCE(type, var) \ + (*(volatile type*) &(var)) + +#define UNREACHABLE() \ + do { \ + assert(0 && "unreachable code"); \ + abort(); \ + } \ + while (0) + +#define SAVE_ERRNO(block) \ + do { \ + int _saved_errno = errno; \ + do { block; } while (0); \ + errno = _saved_errno; \ + } \ + while (0) + +/* The __clang__ and __INTEL_COMPILER checks are superfluous because they + * define __GNUC__. They are here to convey to you, dear reader, that these + * macros are enabled when compiling with clang or icc. + */ +#if defined(__clang__) || \ + defined(__GNUC__) || \ + defined(__INTEL_COMPILER) || \ + defined(__SUNPRO_C) +# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration +# define UV_UNUSED(declaration) __attribute__((unused)) declaration +#else +# define UV_DESTRUCTOR(declaration) declaration +# define UV_UNUSED(declaration) declaration +#endif + +#if defined(__linux__) +# define UV__POLLIN UV__EPOLLIN +# define UV__POLLOUT UV__EPOLLOUT +# define UV__POLLERR UV__EPOLLERR +# define UV__POLLHUP UV__EPOLLHUP +#endif + +#if defined(__sun) +# define UV__POLLIN POLLIN +# define UV__POLLOUT POLLOUT +# define UV__POLLERR POLLERR +# define UV__POLLHUP POLLHUP +#endif + +#ifndef UV__POLLIN +# define UV__POLLIN 1 +#endif + +#ifndef UV__POLLOUT +# define UV__POLLOUT 2 +#endif + +#ifndef UV__POLLERR +# define UV__POLLERR 4 +#endif + +#ifndef UV__POLLHUP +# define UV__POLLHUP 8 +#endif + +/* handle flags */ +enum { + UV_CLOSING = 0x01, /* uv_close() called but not finished. */ + UV_CLOSED = 0x02, /* close(2) finished. */ + UV_STREAM_READING = 0x04, /* uv_read_start() called. */ + UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ + UV_STREAM_SHUT = 0x10, /* Write side closed. */ + UV_STREAM_READABLE = 0x20, /* The stream is readable */ + UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ + UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ + UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ + UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ + UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ + UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ + UV_TCP_SINGLE_ACCEPT = 0x1000 /* Only accept() when idle. */ +}; + +typedef enum { + UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ + UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ +} uv_clocktype_t; + +/* core */ +int uv__nonblock(int fd, int set); +int uv__close(int fd); +int uv__cloexec(int fd, int set); +int uv__socket(int domain, int type, int protocol); +int uv__dup(int fd); +ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); +void uv__make_close_pending(uv_handle_t* handle); + +void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); +void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_close(uv_loop_t* loop, uv__io_t* w); +void uv__io_feed(uv_loop_t* loop, uv__io_t* w); +int uv__io_active(const uv__io_t* w, unsigned int events); +void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ + +/* async */ +void uv__async_send(struct uv__async* wa); +void uv__async_init(struct uv__async* wa); +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb); +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa); + +/* loop */ +void uv__run_idle(uv_loop_t* loop); +void uv__run_check(uv_loop_t* loop); +void uv__run_prepare(uv_loop_t* loop); + +/* stream */ +void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, + uv_handle_type type); +int uv__stream_open(uv_stream_t*, int fd, int flags); +void uv__stream_destroy(uv_stream_t* stream); +#if defined(__APPLE__) +int uv__stream_try_select(uv_stream_t* stream, int* fd); +#endif /* defined(__APPLE__) */ +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__accept(int sockfd); + +/* tcp */ +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); +int uv__tcp_nodelay(int fd, int on); +int uv__tcp_keepalive(int fd, int on, unsigned int delay); + +/* pipe */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); + +/* timer */ +void uv__run_timers(uv_loop_t* loop); +int uv__next_timeout(const uv_loop_t* loop); + +/* signal */ +void uv__signal_close(uv_signal_t* handle); +void uv__signal_global_once_init(void); +void uv__signal_loop_cleanup(uv_loop_t* loop); + +/* thread pool */ +void uv__work_submit(uv_loop_t* loop, + struct uv__work *w, + void (*work)(struct uv__work *w), + void (*done)(struct uv__work *w, int status)); +void uv__work_done(uv_async_t* handle, int status); + +/* platform specific */ +uint64_t uv__hrtime(uv_clocktype_t type); +int uv__kqueue_init(uv_loop_t* loop); +int uv__platform_loop_init(uv_loop_t* loop, int default_loop); +void uv__platform_loop_delete(uv_loop_t* loop); +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); + +/* various */ +void uv__async_close(uv_async_t* handle); +void uv__check_close(uv_check_t* handle); +void uv__fs_event_close(uv_fs_event_t* handle); +void uv__idle_close(uv_idle_t* handle); +void uv__pipe_close(uv_pipe_t* handle); +void uv__poll_close(uv_poll_t* handle); +void uv__prepare_close(uv_prepare_t* handle); +void uv__process_close(uv_process_t* handle); +void uv__stream_close(uv_stream_t* handle); +void uv__tcp_close(uv_tcp_t* handle); +void uv__timer_close(uv_timer_t* handle); +void uv__udp_close(uv_udp_t* handle); +void uv__udp_finish_close(uv_udp_t* handle); + +#if defined(__APPLE__) +int uv___stream_fd(uv_stream_t* handle); +#define uv__stream_fd(handle) (uv___stream_fd((uv_stream_t*) (handle))) +#else +#define uv__stream_fd(handle) ((handle)->io_watcher.fd) +#endif /* defined(__APPLE__) */ + +#ifdef UV__O_NONBLOCK +# define UV__F_NONBLOCK UV__O_NONBLOCK +#else +# define UV__F_NONBLOCK 1 +#endif + +int uv__make_socketpair(int fds[2], int flags); +int uv__make_pipe(int fds[2], int flags); + +#if defined(__APPLE__) + +int uv__fsevents_init(uv_fs_event_t* handle); +int uv__fsevents_close(uv_fs_event_t* handle); +void uv__fsevents_loop_delete(uv_loop_t* loop); + +/* OSX < 10.7 has no file events, polyfill them */ +#ifndef MAC_OS_X_VERSION_10_7 + +static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; +static const int kFSEventStreamEventFlagItemCreated = 0x00000100; +static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; +static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; +static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; +static const int kFSEventStreamEventFlagItemModified = 0x00001000; +static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; +static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; +static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; +static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; +static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; +static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; + +#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ + +#endif /* defined(__APPLE__) */ + +UV_UNUSED(static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type)) { + req->type = type; + uv__req_register(loop, req); +} +#define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) + +UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { + /* Use a fast time source if available. We only need millisecond precision. + */ + loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000; +} + +UV_UNUSED(static char* uv__basename_r(const char* path)) { + char* s; + + s = strrchr(path, '/'); + if (s == NULL) + return (char*) path; + + return s + 1; +} + + +#ifdef HAVE_DTRACE +#include "uv-dtrace.h" +#else +#define UV_TICK_START(arg0, arg1) +#define UV_TICK_STOP(arg0, arg1) +#endif + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c new file mode 100644 index 0000000000..f86f291fc0 --- /dev/null +++ b/src/unix/kqueue.c @@ -0,0 +1,403 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); + + +int uv__kqueue_init(uv_loop_t* loop) { + loop->backend_fd = kqueue(); + if (loop->backend_fd == -1) + return -errno; + + uv__cloexec(loop->backend_fd, 1); + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct kevent events[1024]; + struct kevent* ev; + struct timespec spec; + unsigned int nevents; + unsigned int revents; + QUEUE* q; + uint64_t base; + uint64_t diff; + uv__io_t* w; + int filter; + int fflags; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + nevents = 0; + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { + filter = EVFILT_READ; + fflags = 0; + op = EV_ADD; + + if (w->cb == uv__fs_event) { + filter = EVFILT_VNODE; + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */ + } + + EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { + EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;; nevents = 0) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + nfds = kevent(loop->backend_fd, + events, + nevents, + events, + ARRAY_SIZE(events), + timeout == -1 ? NULL : &spec); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + ev = events + i; + fd = ev->ident; + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. */ + /* TODO batch up */ + struct kevent events[1]; + + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != EBADF && errno != ENOENT) + abort(); + + continue; + } + + if (ev->filter == EVFILT_VNODE) { + assert(w->events == UV__POLLIN); + assert(w->pevents == UV__POLLIN); + w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + nevents++; + continue; + } + + revents = 0; + + if (ev->filter == EVFILT_READ) { + if (w->pevents & UV__POLLIN) { + revents |= UV__POLLIN; + w->rcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->filter == EVFILT_WRITE) { + if (w->pevents & UV__POLLOUT) { + revents |= UV__POLLOUT; + w->wcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + + if (ev->flags & EV_ERROR) + revents |= UV__POLLERR; + + if (revents == 0) + continue; + + w->cb(loop, w, revents); + nevents++; + } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct kevent* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct kevent*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].ident == fd) + events[i].ident = -1; +} + + +static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { + uv_fs_event_t* handle; + struct kevent ev; + int events; + const char* path; +#if defined(F_GETPATH) + /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */ + char pathbuf[MAXPATHLEN]; +#endif + + handle = container_of(w, uv_fs_event_t, event_watcher); + + if (fflags & (NOTE_ATTRIB | NOTE_EXTEND)) + events = UV_CHANGE; + else + events = UV_RENAME; + + path = NULL; +#if defined(F_GETPATH) + /* Also works when the file has been unlinked from the file system. Passing + * in the path when the file has been deleted is arguably a little strange + * but it's consistent with what the inotify backend does. + */ + if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0) + path = uv__basename_r(pathbuf); +#endif + handle->cb(handle, path, events, 0); + + if (handle->event_watcher.fd == -1) + return; + + /* Watcher operates in one-shot mode, re-arm it. */ + fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME + | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; + + EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0); + + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { +#if defined(__APPLE__) + struct stat statbuf; +#endif /* defined(__APPLE__) */ + int fd; + + if (uv__is_active(handle)) + return -EINVAL; + + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(filename, O_RDONLY); + if (fd == -1) + return -errno; + + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); + handle->filename = strdup(filename); + handle->cb = cb; + +#if defined(__APPLE__) + /* Nullify field to perform checks later */ + handle->cf_cb = NULL; + handle->realpath = NULL; + handle->realpath_len = 0; + handle->cf_flags = flags; + + if (fstat(fd, &statbuf)) + goto fallback; + /* FSEvents works only with directories */ + if (!(statbuf.st_mode & S_IFDIR)) + goto fallback; + + return uv__fsevents_init(handle); + +fallback: +#endif /* defined(__APPLE__) */ + + uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return -EINVAL; + + uv__handle_stop(handle); + +#if defined(__APPLE__) + if (uv__fsevents_close(handle)) + uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN); +#else + uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN); +#endif /* defined(__APPLE__) */ + + free(handle->filename); + handle->filename = NULL; + + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c new file mode 100644 index 0000000000..f71dd2d6b9 --- /dev/null +++ b/src/unix/linux-core.c @@ -0,0 +1,816 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __ANDROID__ +#define HAVE_IFADDRS_H 1 +#endif + +#ifdef __UCLIBC__ +# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32 +# undef HAVE_IFADDRS_H +# endif +#endif +#ifdef HAVE_IFADDRS_H +# include +# include +# include +# include +#endif + +/* Available from 2.6.32 onwards. */ +#ifndef CLOCK_MONOTONIC_COARSE +# define CLOCK_MONOTONIC_COARSE 6 +#endif + +/* This is rather annoying: CLOCK_BOOTTIME lives in but we can't + * include that file because it conflicts with . We'll just have to + * define it ourselves. + */ +#ifndef CLOCK_BOOTTIME +# define CLOCK_BOOTTIME 7 +#endif + +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); +static unsigned long read_cpufreq(unsigned int cpunum); + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + int fd; + + fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + + /* epoll_create1() can fail either because it's not implemented (old kernel) + * or because it doesn't understand the EPOLL_CLOEXEC flag. + */ + if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { + fd = uv__epoll_create(256); + + if (fd != -1) + uv__cloexec(fd, 1); + } + + loop->backend_fd = fd; + loop->inotify_fd = -1; + loop->inotify_watchers = NULL; + + if (fd == -1) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__close(loop->inotify_fd); + loop->inotify_fd = -1; +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].data == fd) + events[i].data = -1; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct uv__epoll_event events[1024]; + struct uv__epoll_event* pe; + struct uv__epoll_event e; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + int nevents; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.data = w->fd; + + if (w->events == 0) + op = UV__EPOLL_CTL_ADD; + else + op = UV__EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == UV__EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + nfds = uv__epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->data; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; + + /* Work around an epoll quirk where it sometimes reports just the + * EPOLLERR or EPOLLHUP event. In order to force the event loop to + * move forward, we merge in the read/write events that the watcher + * is interested in; uv__read() and uv__write() will then deal with + * the error or hangup in the usual fashion. + * + * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user + * reads the available data, calls uv_read_stop(), then sometime later + * calls uv_read_start() again. By then, libuv has forgotten about the + * hangup and the kernel won't report EPOLLIN again because there's + * nothing left to read. If anything, libuv is to blame here. The + * current hack is just a quick bandaid; to properly fix it, libuv + * needs to remember the error/hangup event. We should get that for + * free when we switch over to edge-triggered I/O. + */ + if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP) + pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); + + if (pe->events != 0) { + w->cb(loop, w, pe->events); + nevents++; + } + } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + static clock_t fast_clock_id = -1; + struct timespec t; + clock_t clock_id; + + /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has + * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is + * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may + * decide to make a costly system call. + */ + /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE + * when it has microsecond granularity or better (unlikely). + */ + if (type == UV_CLOCK_FAST && fast_clock_id == -1) { + if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 && + t.tv_nsec <= 1 * 1000 * 1000) { + fast_clock_id = CLOCK_MONOTONIC_COARSE; + } else { + fast_clock_id = CLOCK_MONOTONIC; + } + } + + clock_id = CLOCK_MONOTONIC; + if (type == UV_CLOCK_FAST) + clock_id = fast_clock_id; + + if (clock_gettime(clock_id, &t)) + return 0; /* Not really possible. */ + + return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; +} + + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + + if (sysinfo(&info) < 0) return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} + + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL) + return -EINVAL; + + n = readlink("/proc/self/exe", buffer, *size - 1); + if (n == -1) + return -errno; + + buffer[n] = '\0'; + *size = n; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); +} + + +uint64_t uv_get_total_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); +} + + +int uv_resident_set_memory(size_t* rss) { + char buf[1024]; + const char* s; + ssize_t n; + long val; + int fd; + int i; + + do + fd = open("/proc/self/stat", O_RDONLY); + while (fd == -1 && errno == EINTR); + + if (fd == -1) + return -errno; + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + uv__close(fd); + if (n == -1) + return -errno; + buf[n] = '\0'; + + s = strchr(buf, ' '); + if (s == NULL) + goto err; + + s += 1; + if (*s != '(') + goto err; + + s = strchr(s, ')'); + if (s == NULL) + goto err; + + for (i = 1; i <= 22; i++) { + s = strchr(s + 1, ' '); + if (s == NULL) + goto err; + } + + errno = 0; + val = strtol(s, NULL, 10); + if (errno != 0) + goto err; + if (val < 0) + goto err; + + *rss = val * getpagesize(); + return 0; + +err: + return -EINVAL; +} + + +int uv_uptime(double* uptime) { + static volatile int no_clock_boottime; + struct timespec now; + int r; + + /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available + * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system + * is suspended. + */ + if (no_clock_boottime) { + retry: r = clock_gettime(CLOCK_MONOTONIC, &now); + } + else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { + no_clock_boottime = 1; + goto retry; + } + + if (r) + return -errno; + + *uptime = now.tv_sec; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus; + uv_cpu_info_t* ci; + int err; + + *cpu_infos = NULL; + *count = 0; + + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + assert(numcpus != (unsigned int) -1); + assert(numcpus != 0); + + ci = calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + return -ENOMEM; + + err = read_models(numcpus, ci); + if (err == 0) + err = read_times(numcpus, ci); + + if (err) { + uv_free_cpu_info(ci, numcpus); + return err; + } + + /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. + * We don't check for errors here. Worst case, the field is left zero. + */ + if (ci[0].speed == 0) + read_speeds(numcpus, ci); + + *cpu_infos = ci; + *count = numcpus; + + return 0; +} + + +static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned int num; + + for (num = 0; num < numcpus; num++) + ci[num].speed = read_cpufreq(num) / 1000; +} + + +/* Also reads the CPU frequency on x86. The other architectures only have + * a BogoMIPS field, which may not be very accurate. + * + * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. + */ +static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { + static const char model_marker[] = "model name\t: "; + static const char speed_marker[] = "cpu MHz\t\t: "; + const char* inferred_model; + unsigned int model_idx; + unsigned int speed_idx; + char buf[1024]; + char* model; + FILE* fp; + + /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ + (void) &model_marker; + (void) &speed_marker; + (void) &speed_idx; + (void) &model; + (void) &buf; + (void) &fp; + + model_idx = 0; + speed_idx = 0; + +#if defined(__arm__) || \ + defined(__i386__) || \ + defined(__mips__) || \ + defined(__x86_64__) + fp = fopen("/proc/cpuinfo", "r"); + if (fp == NULL) + return -errno; + + while (fgets(buf, sizeof(buf), fp)) { + if (model_idx < numcpus) { + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#if defined(__arm__) || defined(__mips__) + if (model_idx < numcpus) { +#if defined(__arm__) + /* Fallback for pre-3.8 kernels. */ + static const char model_marker[] = "Processor\t: "; +#else /* defined(__mips__) */ + static const char model_marker[] = "cpu model\t\t: "; +#endif + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -ENOMEM; + } + ci[model_idx++].model = model; + continue; + } + } +#else /* !__arm__ && !__mips__ */ + if (speed_idx < numcpus) { + if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { + ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); + continue; + } + } +#endif /* __arm__ || __mips__ */ + } + + fclose(fp); +#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ + + /* Now we want to make sure that all the models contain *something* because + * it's not safe to leave them as null. Copy the last entry unless there + * isn't one, in that case we simply put "unknown" into everything. + */ + inferred_model = "unknown"; + if (model_idx > 0) + inferred_model = ci[model_idx - 1].model; + + while (model_idx < numcpus) { + model = strndup(inferred_model, strlen(inferred_model)); + if (model == NULL) + return -ENOMEM; + ci[model_idx++].model = model; + } + + return 0; +} + + +static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { + unsigned long clock_ticks; + struct uv_cpu_times_s ts; + unsigned long user; + unsigned long nice; + unsigned long sys; + unsigned long idle; + unsigned long dummy; + unsigned long irq; + unsigned int num; + unsigned int len; + char buf[1024]; + FILE* fp; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + fp = fopen("/proc/stat", "r"); + if (fp == NULL) + return -errno; + + if (!fgets(buf, sizeof(buf), fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " marker */ + { + unsigned int n; + int r = sscanf(buf, "cpu%u ", &n); + assert(r == 1); + (void) r; /* silence build warning */ + for (len = sizeof("cpu0"); n /= 10; len++); + } + + /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, + * guest, guest_nice but we're only interested in the first four + irq. + * + * Don't use %*s to skip fields or %ll to read straight into the uint64_t + * fields, they're not allowed in C89 mode. + */ + if (6 != sscanf(buf + len, + "%lu %lu %lu %lu %lu %lu", + &user, + &nice, + &sys, + &idle, + &dummy, + &irq)) + abort(); + + ts.user = clock_ticks * user; + ts.nice = clock_ticks * nice; + ts.sys = clock_ticks * sys; + ts.idle = clock_ticks * idle; + ts.irq = clock_ticks * irq; + ci[num++].cpu_times = ts; + } + fclose(fp); + assert(num == numcpus); + + return 0; +} + + +static unsigned long read_cpufreq(unsigned int cpunum) { + unsigned long val; + char buf[1024]; + FILE* fp; + + snprintf(buf, + sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", + cpunum); + + fp = fopen(buf, "r"); + if (fp == NULL) + return 0; + + if (fscanf(fp, "%lu", &val) != 1) + val = 0; + + fclose(fp); + + return val; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { +#ifndef HAVE_IFADDRS_H + return -ENOSYS; +#else + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + /* + * On Linux getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == PF_PACKET) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_PACKET)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sll = (struct sockaddr_ll*)ent->ifa_addr; + memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +#endif +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} + + +void uv__set_process_title(const char* title) { +#if defined(PR_SET_NAME) + prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ +#endif +} diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c new file mode 100644 index 0000000000..7641f383c4 --- /dev/null +++ b/src/unix/linux-inotify.c @@ -0,0 +1,257 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct watcher_list { + RB_ENTRY(watcher_list) entry; + QUEUE watchers; + char* path; + int wd; +}; + +struct watcher_root { + struct watcher_list* rbh_root; +}; +#define CAST(p) ((struct watcher_root*)(p)) + + +static int compare_watchers(const struct watcher_list* a, + const struct watcher_list* b) { + if (a->wd < b->wd) return -1; + if (a->wd > b->wd) return 1; + return 0; +} + + +RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) + + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents); + + +static int new_inotify_fd(void) { + int err; + int fd; + + fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != ENOSYS) + return -errno; + + fd = uv__inotify_init(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err == 0) + err = uv__nonblock(fd, 1); + + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +static int init_inotify(uv_loop_t* loop) { + int err; + + if (loop->inotify_fd != -1) + return 0; + + err = new_inotify_fd(); + if (err < 0) + return err; + + loop->inotify_fd = err; + uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); + uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN); + + return 0; +} + + +static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { + struct watcher_list w; + w.wd = wd; + return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); +} + + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* dummy, + unsigned int events) { + const struct uv__inotify_event* e; + struct watcher_list* w; + uv_fs_event_t* h; + QUEUE* q; + const char* path; + ssize_t size; + const char *p; + /* needs to be large enough for sizeof(inotify_event) + strlen(filename) */ + char buf[4096]; + + while (1) { + do + size = read(loop->inotify_fd, buf, sizeof(buf)); + while (size == -1 && errno == EINTR); + + if (size == -1) { + assert(errno == EAGAIN || errno == EWOULDBLOCK); + break; + } + + assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ + + /* Now we have one or more inotify_event structs. */ + for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { + e = (const struct uv__inotify_event*)p; + + events = 0; + if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_CHANGE; + if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY)) + events |= UV_RENAME; + + w = find_watcher(loop, e->wd); + if (w == NULL) + continue; /* Stale event, no watchers left. */ + + /* inotify does not return the filename when monitoring a single file + * for modifications. Repurpose the filename for API compatibility. + * I'm not convinced this is a good thing, maybe it should go. + */ + path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); + + QUEUE_FOREACH(q, &w->watchers) { + h = QUEUE_DATA(q, uv_fs_event_t, watchers); + h->cb(h, path, events, 0); + } + } + } +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + struct watcher_list* w; + int events; + int err; + int wd; + + if (uv__is_active(handle)) + return -EINVAL; + + err = init_inotify(handle->loop); + if (err) + return err; + + events = UV__IN_ATTRIB + | UV__IN_CREATE + | UV__IN_MODIFY + | UV__IN_DELETE + | UV__IN_DELETE_SELF + | UV__IN_MOVE_SELF + | UV__IN_MOVED_FROM + | UV__IN_MOVED_TO; + + wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); + if (wd == -1) + return -errno; + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + w = malloc(sizeof(*w) + strlen(path) + 1); + if (w == NULL) + return -ENOMEM; + + w->wd = wd; + w->path = strcpy((char*)(w + 1), path); + QUEUE_INIT(&w->watchers); + RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); + +no_insert: + uv__handle_start(handle); + QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); + handle->filename = w->path; + handle->cb = cb; + handle->wd = wd; + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + struct watcher_list* w; + + if (!uv__is_active(handle)) + return -EINVAL; + + w = find_watcher(handle->loop, handle->wd); + assert(w != NULL); + + handle->wd = -1; + handle->filename = NULL; + uv__handle_stop(handle); + QUEUE_REMOVE(&handle->watchers); + + if (QUEUE_EMPTY(&w->watchers)) { + /* No watchers left for this path. Clean up. */ + RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w); + uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd); + free(w); + } + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c new file mode 100644 index 0000000000..06cc5943cf --- /dev/null +++ b/src/unix/linux-syscalls.c @@ -0,0 +1,388 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "linux-syscalls.h" +#include +#include +#include +#include + +#if defined(__i386__) +# ifndef __NR_socketcall +# define __NR_socketcall 102 +# endif +#endif + +#if defined(__arm__) +# if defined(__thumb__) || defined(__ARM_EABI__) +# define UV_SYSCALL_BASE 0 +# else +# define UV_SYSCALL_BASE 0x900000 +# endif +#endif /* __arm__ */ + +#ifndef __NR_accept4 +# if defined(__x86_64__) +# define __NR_accept4 288 +# elif defined(__i386__) + /* Nothing. Handled through socketcall(). */ +# elif defined(__arm__) +# define __NR_accept4 (UV_SYSCALL_BASE + 366) +# endif +#endif /* __NR_accept4 */ + +#ifndef __NR_eventfd +# if defined(__x86_64__) +# define __NR_eventfd 284 +# elif defined(__i386__) +# define __NR_eventfd 323 +# elif defined(__arm__) +# define __NR_eventfd (UV_SYSCALL_BASE + 351) +# endif +#endif /* __NR_eventfd */ + +#ifndef __NR_eventfd2 +# if defined(__x86_64__) +# define __NR_eventfd2 290 +# elif defined(__i386__) +# define __NR_eventfd2 328 +# elif defined(__arm__) +# define __NR_eventfd2 (UV_SYSCALL_BASE + 356) +# endif +#endif /* __NR_eventfd2 */ + +#ifndef __NR_epoll_create +# if defined(__x86_64__) +# define __NR_epoll_create 213 +# elif defined(__i386__) +# define __NR_epoll_create 254 +# elif defined(__arm__) +# define __NR_epoll_create (UV_SYSCALL_BASE + 250) +# endif +#endif /* __NR_epoll_create */ + +#ifndef __NR_epoll_create1 +# if defined(__x86_64__) +# define __NR_epoll_create1 291 +# elif defined(__i386__) +# define __NR_epoll_create1 329 +# elif defined(__arm__) +# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) +# endif +#endif /* __NR_epoll_create1 */ + +#ifndef __NR_epoll_ctl +# if defined(__x86_64__) +# define __NR_epoll_ctl 233 /* used to be 214 */ +# elif defined(__i386__) +# define __NR_epoll_ctl 255 +# elif defined(__arm__) +# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) +# endif +#endif /* __NR_epoll_ctl */ + +#ifndef __NR_epoll_wait +# if defined(__x86_64__) +# define __NR_epoll_wait 232 /* used to be 215 */ +# elif defined(__i386__) +# define __NR_epoll_wait 256 +# elif defined(__arm__) +# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) +# endif +#endif /* __NR_epoll_wait */ + +#ifndef __NR_epoll_pwait +# if defined(__x86_64__) +# define __NR_epoll_pwait 281 +# elif defined(__i386__) +# define __NR_epoll_pwait 319 +# elif defined(__arm__) +# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) +# endif +#endif /* __NR_epoll_pwait */ + +#ifndef __NR_inotify_init +# if defined(__x86_64__) +# define __NR_inotify_init 253 +# elif defined(__i386__) +# define __NR_inotify_init 291 +# elif defined(__arm__) +# define __NR_inotify_init (UV_SYSCALL_BASE + 316) +# endif +#endif /* __NR_inotify_init */ + +#ifndef __NR_inotify_init1 +# if defined(__x86_64__) +# define __NR_inotify_init1 294 +# elif defined(__i386__) +# define __NR_inotify_init1 332 +# elif defined(__arm__) +# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360) +# endif +#endif /* __NR_inotify_init1 */ + +#ifndef __NR_inotify_add_watch +# if defined(__x86_64__) +# define __NR_inotify_add_watch 254 +# elif defined(__i386__) +# define __NR_inotify_add_watch 292 +# elif defined(__arm__) +# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317) +# endif +#endif /* __NR_inotify_add_watch */ + +#ifndef __NR_inotify_rm_watch +# if defined(__x86_64__) +# define __NR_inotify_rm_watch 255 +# elif defined(__i386__) +# define __NR_inotify_rm_watch 293 +# elif defined(__arm__) +# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318) +# endif +#endif /* __NR_inotify_rm_watch */ + +#ifndef __NR_pipe2 +# if defined(__x86_64__) +# define __NR_pipe2 293 +# elif defined(__i386__) +# define __NR_pipe2 331 +# elif defined(__arm__) +# define __NR_pipe2 (UV_SYSCALL_BASE + 359) +# endif +#endif /* __NR_pipe2 */ + +#ifndef __NR_recvmmsg +# if defined(__x86_64__) +# define __NR_recvmmsg 299 +# elif defined(__i386__) +# define __NR_recvmmsg 337 +# elif defined(__arm__) +# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) +# endif +#endif /* __NR_recvmsg */ + +#ifndef __NR_sendmmsg +# if defined(__x86_64__) +# define __NR_sendmmsg 307 +# elif defined(__i386__) +# define __NR_sendmmsg 345 +# elif defined(__arm__) +# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) +# endif +#endif /* __NR_sendmmsg */ + +#ifndef __NR_utimensat +# if defined(__x86_64__) +# define __NR_utimensat 280 +# elif defined(__i386__) +# define __NR_utimensat 320 +# elif defined(__arm__) +# define __NR_utimensat (UV_SYSCALL_BASE + 348) +# endif +#endif /* __NR_utimensat */ + + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { +#if defined(__i386__) + unsigned long args[4]; + int r; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) addr; + args[2] = (unsigned long) addrlen; + args[3] = (unsigned long) flags; + + r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + + /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does + * a bad flags argument. Try to distinguish between the two cases. + */ + if (r == -1) + if (errno == EINVAL) + if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) + errno = ENOSYS; + + return r; +#elif defined(__NR_accept4) + return syscall(__NR_accept4, fd, addr, addrlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd(unsigned int count) { +#if defined(__NR_eventfd) + return syscall(__NR_eventfd, count); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__eventfd2(unsigned int count, int flags) { +#if defined(__NR_eventfd2) + return syscall(__NR_eventfd2, count, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create(int size) { +#if defined(__NR_epoll_create) + return syscall(__NR_epoll_create, size); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_create1(int flags) { +#if defined(__NR_epoll_create1) + return syscall(__NR_epoll_create1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { +#if defined(__NR_epoll_ctl) + return syscall(__NR_epoll_ctl, epfd, op, fd, events); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout) { +#if defined(__NR_epoll_wait) + return syscall(__NR_epoll_wait, epfd, events, nevents, timeout); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + const sigset_t* sigmask) { +#if defined(__NR_epoll_pwait) + return syscall(__NR_epoll_pwait, + epfd, + events, + nevents, + timeout, + sigmask, + sizeof(*sigmask)); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init(void) { +#if defined(__NR_inotify_init) + return syscall(__NR_inotify_init); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_init1(int flags) { +#if defined(__NR_inotify_init1) + return syscall(__NR_inotify_init1, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) { +#if defined(__NR_inotify_add_watch) + return syscall(__NR_inotify_add_watch, fd, path, mask); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__inotify_rm_watch(int fd, int32_t wd) { +#if defined(__NR_inotify_rm_watch) + return syscall(__NR_inotify_rm_watch, fd, wd); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__pipe2(int pipefd[2], int flags) { +#if defined(__NR_pipe2) + return syscall(__NR_pipe2, pipefd, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags) { +#if defined(__NR_sendmmsg) + return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout) { +#if defined(__NR_recvmmsg) + return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags) +{ +#if defined(__NR_utimensat) + return syscall(__NR_utimensat, dirfd, path, times, flags); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h new file mode 100644 index 0000000000..1ad9518548 --- /dev/null +++ b/src/unix/linux-syscalls.h @@ -0,0 +1,151 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_LINUX_SYSCALL_H_ +#define UV_LINUX_SYSCALL_H_ + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#if defined(__alpha__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__hppa__) +# define UV__O_CLOEXEC 0x200000 +#elif defined(__sparc__) +# define UV__O_CLOEXEC 0x400000 +#else +# define UV__O_CLOEXEC 0x80000 +#endif + +#if defined(__alpha__) +# define UV__O_NONBLOCK 0x4 +#elif defined(__hppa__) +# define UV__O_NONBLOCK 0x10004 +#elif defined(__mips__) +# define UV__O_NONBLOCK 0x80 +#elif defined(__sparc__) +# define UV__O_NONBLOCK 0x4000 +#else +# define UV__O_NONBLOCK 0x800 +#endif + +#define UV__EFD_CLOEXEC UV__O_CLOEXEC +#define UV__EFD_NONBLOCK UV__O_NONBLOCK + +#define UV__IN_CLOEXEC UV__O_CLOEXEC +#define UV__IN_NONBLOCK UV__O_NONBLOCK + +#define UV__SOCK_CLOEXEC UV__O_CLOEXEC +#define UV__SOCK_NONBLOCK UV__O_NONBLOCK + +/* epoll flags */ +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD 1 +#define UV__EPOLL_CTL_DEL 2 +#define UV__EPOLL_CTL_MOD 3 + +#define UV__EPOLLIN 1 +#define UV__EPOLLOUT 4 +#define UV__EPOLLERR 8 +#define UV__EPOLLHUP 16 +#define UV__EPOLLONESHOT 0x40000000 +#define UV__EPOLLET 0x80000000 + +/* inotify flags */ +#define UV__IN_ACCESS 0x001 +#define UV__IN_MODIFY 0x002 +#define UV__IN_ATTRIB 0x004 +#define UV__IN_CLOSE_WRITE 0x008 +#define UV__IN_CLOSE_NOWRITE 0x010 +#define UV__IN_OPEN 0x020 +#define UV__IN_MOVED_FROM 0x040 +#define UV__IN_MOVED_TO 0x080 +#define UV__IN_CREATE 0x100 +#define UV__IN_DELETE 0x200 +#define UV__IN_DELETE_SELF 0x400 +#define UV__IN_MOVE_SELF 0x800 + +#if defined(__x86_64__) +struct uv__epoll_event { + uint32_t events; + uint64_t data; +} __attribute__((packed)); +#else +struct uv__epoll_event { + uint32_t events; + uint64_t data; +}; +#endif + +struct uv__inotify_event { + int32_t wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + /* char name[0]; */ +}; + +struct uv__mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); +int uv__eventfd(unsigned int count); +int uv__epoll_create(int size); +int uv__epoll_create1(int flags); +int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); +int uv__epoll_wait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout); +int uv__epoll_pwait(int epfd, + struct uv__epoll_event* events, + int nevents, + int timeout, + const sigset_t* sigmask); +int uv__eventfd2(unsigned int count, int flags); +int uv__inotify_init(void); +int uv__inotify_init1(int flags); +int uv__inotify_add_watch(int fd, const char* path, uint32_t mask); +int uv__inotify_rm_watch(int fd, int32_t wd); +int uv__pipe2(int pipefd[2], int flags); +int uv__recvmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags, + struct timespec* timeout); +int uv__sendmmsg(int fd, + struct uv__mmsghdr* mmsg, + unsigned int vlen, + unsigned int flags); +int uv__utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags); + +#endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c new file mode 100644 index 0000000000..dc03c206d2 --- /dev/null +++ b/src/unix/loop-watcher.c @@ -0,0 +1,63 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#define UV_LOOP_WATCHER_DEFINE(name, type) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ + handle->name##_cb = NULL; \ + return 0; \ + } \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + if (uv__is_active(handle)) return 0; \ + if (cb == NULL) return -EINVAL; \ + QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + return 0; \ + } \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + if (!uv__is_active(handle)) return 0; \ + QUEUE_REMOVE(&handle->queue); \ + uv__handle_stop(handle); \ + return 0; \ + } \ + \ + void uv__run_##name(uv_loop_t* loop) { \ + uv_##name##_t* h; \ + QUEUE* q; \ + QUEUE_FOREACH(q, &loop->name##_handles) { \ + h = QUEUE_DATA(q, uv_##name##_t, queue); \ + h->name##_cb(h, 0); \ + } \ + } \ + \ + void uv__##name##_close(uv_##name##_t* handle) { \ + uv_##name##_stop(handle); \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/unix/loop.c b/src/unix/loop.c new file mode 100644 index 0000000000..94a5c03819 --- /dev/null +++ b/src/unix/loop.c @@ -0,0 +1,163 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "tree.h" +#include "internal.h" +#include +#include +#include + +static int uv__loop_init(uv_loop_t* loop, int default_loop); +static void uv__loop_delete(uv_loop_t* loop); + +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; + + +uv_loop_t* uv_default_loop(void) { + if (default_loop_ptr != NULL) + return default_loop_ptr; + + if (uv__loop_init(&default_loop_struct, /* default_loop? */ 1)) + return NULL; + + default_loop_ptr = &default_loop_struct; + return default_loop_ptr; +} + + +uv_loop_t* uv_loop_new(void) { + uv_loop_t* loop; + + loop = malloc(sizeof(*loop)); + if (loop == NULL) + return NULL; + + if (uv__loop_init(loop, /* default_loop? */ 0)) { + free(loop); + return NULL; + } + + return loop; +} + + +void uv_loop_delete(uv_loop_t* loop) { + uv__loop_delete(loop); +#ifndef NDEBUG + memset(loop, -1, sizeof(*loop)); +#endif + if (loop == default_loop_ptr) + default_loop_ptr = NULL; + else + free(loop); +} + + +static int uv__loop_init(uv_loop_t* loop, int default_loop) { + unsigned int i; + int err; + + uv__signal_global_once_init(); + + memset(loop, 0, sizeof(*loop)); + RB_INIT(&loop->timer_handles); + QUEUE_INIT(&loop->wq); + QUEUE_INIT(&loop->active_reqs); + QUEUE_INIT(&loop->idle_handles); + QUEUE_INIT(&loop->async_handles); + QUEUE_INIT(&loop->check_handles); + QUEUE_INIT(&loop->prepare_handles); + QUEUE_INIT(&loop->handle_queue); + + loop->nfds = 0; + loop->watchers = NULL; + loop->nwatchers = 0; + QUEUE_INIT(&loop->pending_queue); + QUEUE_INIT(&loop->watcher_queue); + + loop->closing_handles = NULL; + uv__update_time(loop); + uv__async_init(&loop->async_watcher); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + loop->backend_fd = -1; + loop->emfile_fd = -1; + + loop->timer_counter = 0; + loop->stop_flag = 0; + + err = uv__platform_loop_init(loop, default_loop); + if (err) + return err; + + uv_signal_init(loop, &loop->child_watcher); + uv__handle_unref(&loop->child_watcher); + loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + + for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) + QUEUE_INIT(loop->process_handles + i); + + if (uv_mutex_init(&loop->wq_mutex)) + abort(); + + if (uv_async_init(loop, &loop->wq_async, uv__work_done)) + abort(); + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + + return 0; +} + + +static void uv__loop_delete(uv_loop_t* loop) { + uv__signal_loop_cleanup(loop); + uv__platform_loop_delete(loop); + uv__async_stop(loop, &loop->async_watcher); + + if (loop->emfile_fd != -1) { + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + + uv_mutex_lock(&loop->wq_mutex); + assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(!uv__has_active_reqs(loop)); + uv_mutex_unlock(&loop->wq_mutex); + uv_mutex_destroy(&loop->wq_mutex); + +#if 0 + assert(QUEUE_EMPTY(&loop->pending_queue)); + assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(loop->nfds == 0); +#endif + + free(loop->watchers); + loop->watchers = NULL; + loop->nwatchers = 0; +} diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c new file mode 100644 index 0000000000..7423a71078 --- /dev/null +++ b/src/unix/netbsd.c @@ -0,0 +1,367 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + size_t cb; + pid_t mypid; + + if (buffer == NULL || size == NULL) + return -EINVAL; + + mypid = getpid(); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + + cb = *size; + if (sysctl(mib, 4, buffer, &cb, NULL, 0)) + return -errno; + *size = strlen(buffer); + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { +#if defined(HW_PHYSMEM64) + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; +#else + unsigned int info; + int which[] = {CTL_HW, HW_PHYSMEM}; +#endif + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title) free(process_title); + + process_title = strdup(title); + setproctitle("%s", title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (process_title) { + strncpy(buffer, process_title, size); + } else { + if (size > 0) { + buffer[0] = '\0'; + } + } + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc2 *kinfo = NULL; + pid_t pid; + int nprocs; + int max_size = sizeof(struct kinfo_proc2); + int page_size; + + page_size = getpagesize(); + pid = getpid(); + + kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); + + if (kd == NULL) goto error; + + kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs); + if (kinfo == NULL) goto error; + + *rss = kinfo->p_vm_rssize * page_size; + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK); + unsigned int multiplier = ((uint64_t)1000L / ticks); + unsigned int cur = 0; + uv_cpu_info_t* cpu_info; + u_int64_t* cp_times; + char model[512]; + u_int64_t cpuspeed; + int numcpus; + size_t size; + int i; + + size = sizeof(model); + if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && + sysctlbyname("hw.model", &model, &size, NULL, 0)) { + return -errno; + } + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return -errno; + *count = numcpus; + + /* Only i386 and amd64 have machdep.tsc_freq */ + size = sizeof(cpuspeed); + if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + + size = numcpus * CPUSTATES * sizeof(*cp_times); + cp_times = malloc(size); + if (cp_times == NULL) + return -ENOMEM; + + if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) + return -errno; + + *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + free(cp_times); + free(*cpu_infos); + return -ENOMEM; + } + + for (i = 0; i < numcpus; i++) { + cpu_info = &(*cpu_infos)[i]; + cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; + cpu_info->model = strdup(model); + cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6); + cur += CPUSTATES; + } + free(cp_times); + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c new file mode 100644 index 0000000000..f052d80c57 --- /dev/null +++ b/src/unix/openbsd.c @@ -0,0 +1,388 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + +static char *process_title; + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +} + + +void uv_loadavg(double avg[3]) { + struct loadavg info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_LOADAVG}; + + if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return; + + avg[0] = (double) info.ldavg[0] / info.fscale; + avg[1] = (double) info.ldavg[1] / info.fscale; + avg[2] = (double) info.ldavg[2] / info.fscale; +} + + +int uv_exepath(char* buffer, size_t* size) { + int mib[4]; + char **argsbuf = NULL; + char **argsbuf_tmp; + size_t argsbuf_size = 100U; + size_t exepath_size; + pid_t mypid; + int err; + + if (buffer == NULL || size == NULL) + return -EINVAL; + + mypid = getpid(); + for (;;) { + err = -ENOMEM; + argsbuf_tmp = realloc(argsbuf, argsbuf_size); + if (argsbuf_tmp == NULL) + goto out; + argsbuf = argsbuf_tmp; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = mypid; + mib[3] = KERN_PROC_ARGV; + if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) { + break; + } + if (errno != ENOMEM) { + err = -errno; + goto out; + } + argsbuf_size *= 2U; + } + if (argsbuf[0] == NULL) { + err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ + goto out; + } + exepath_size = strlen(argsbuf[0]); + if (exepath_size >= *size) { + err = -EINVAL; + goto out; + } + memcpy(buffer, argsbuf[0], exepath_size + 1U); + *size = exepath_size; + err = 0; + +out: + free(argsbuf); + + return err; +} + + +uint64_t uv_get_free_memory(void) { + struct uvmexp info; + size_t size = sizeof(info); + int which[] = {CTL_VM, VM_UVMEXP}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info.free * sysconf(_SC_PAGESIZE); +} + + +uint64_t uv_get_total_memory(void) { + uint64_t info; + int which[] = {CTL_HW, HW_PHYSMEM64}; + size_t size = sizeof(info); + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + return (uint64_t) info; +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc ? strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title) free(process_title); + process_title = strdup(title); + setproctitle(title); + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (process_title) { + strncpy(buffer, process_title, size); + } else { + if (size > 0) { + buffer[0] = '\0'; + } + } + + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + kvm_t *kd = NULL; + struct kinfo_proc *kinfo = NULL; + pid_t pid; + int nprocs, max_size = sizeof(struct kinfo_proc); + size_t page_size = getpagesize(); + + pid = getpid(); + + kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open"); + if (kd == NULL) goto error; + + kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, max_size, &nprocs); + if (kinfo == NULL) goto error; + + *rss = kinfo->p_vm_rssize * page_size; + + kvm_close(kd); + + return 0; + +error: + if (kd) kvm_close(kd); + return -EPERM; +} + + +int uv_uptime(double* uptime) { + time_t now; + struct timeval info; + size_t size = sizeof(info); + static int which[] = {CTL_KERN, KERN_BOOTTIME}; + + if (sysctl(which, 2, &info, &size, NULL, 0)) + return -errno; + + now = time(NULL); + + *uptime = (double)(now - info.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), + multiplier = ((uint64_t)1000L / ticks), cpuspeed; + uint64_t info[CPUSTATES]; + char model[512]; + int numcpus = 1; + int which[] = {CTL_HW,HW_MODEL,0}; + size_t size; + int i; + uv_cpu_info_t* cpu_info; + + size = sizeof(model); + if (sysctl(which, 2, &model, &size, NULL, 0)) + return -errno; + + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0)) + return -errno; + + *cpu_infos = malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return -ENOMEM; + + *count = numcpus; + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { + SAVE_ERRNO(free(*cpu_infos)); + return -errno; + } + + size = sizeof(info); + which[0] = CTL_KERN; + which[1] = KERN_CPTIME2; + for (i = 0; i < numcpus; i++) { + which[2] = i; + size = sizeof(info); + if (sysctl(which, 3, &info, &size, NULL, 0)) { + SAVE_ERRNO(free(*cpu_infos)); + return -errno; + } + + cpu_info = &(*cpu_infos)[i]; + + cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; + cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; + cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; + cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; + cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; + + cpu_info->model = strdup(model); + cpu_info->speed = cpuspeed; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_dl *sa_addr; + + if (getifaddrs(&addrs) != 0) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != PF_INET)) { + continue; + } + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + if (ent->ifa_addr->sa_family != PF_INET) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/pipe.c b/src/unix/pipe.c new file mode 100644 index 0000000000..fd4afb6370 --- /dev/null +++ b/src/unix/pipe.c @@ -0,0 +1,216 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + handle->shutdown_req = NULL; + handle->connect_req = NULL; + handle->pipe_fname = NULL; + handle->ipc = ipc; + return 0; +} + + +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + struct sockaddr_un saddr; + const char* pipe_fname; + int sockfd; + int bound; + int err; + + pipe_fname = NULL; + sockfd = -1; + bound = 0; + err = -EINVAL; + + /* Already bound? */ + if (uv__stream_fd(handle) >= 0) + return -EINVAL; + + /* Make a copy of the file name, it outlives this function's scope. */ + pipe_fname = strdup(name); + if (pipe_fname == NULL) { + err = -ENOMEM; + goto out; + } + + /* We've got a copy, don't touch the original any more. */ + name = NULL; + + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto out; + sockfd = err; + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { + err = -errno; + /* Convert ENOENT to EACCES for compatibility with Windows. */ + if (err == -ENOENT) + err = -EACCES; + goto out; + } + bound = 1; + + /* Success. */ + handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->io_watcher.fd = sockfd; + return 0; + +out: + if (bound) { + /* unlink() before uv__close() to avoid races. */ + assert(pipe_fname != NULL); + unlink(pipe_fname); + } + uv__close(sockfd); + free((void*)pipe_fname); + return err; +} + + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + if (uv__stream_fd(handle) == -1) + return -EINVAL; + + if (listen(uv__stream_fd(handle), backlog)) + return -errno; + + handle->connection_cb = cb; + handle->io_watcher.cb = uv__server_io; + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + return 0; +} + + +void uv__pipe_close(uv_pipe_t* handle) { + if (handle->pipe_fname) { + /* + * Unlink the file system entity before closing the file descriptor. + * Doing it the other way around introduces a race where our process + * unlinks a socket with the same name that's just been created by + * another thread or process. + */ + unlink(handle->pipe_fname); + free((void*)handle->pipe_fname); + handle->pipe_fname = NULL; + } + + uv__stream_close((uv_stream_t*)handle); +} + + +int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { +#if defined(__APPLE__) + int err; + + err = uv__stream_try_select((uv_stream_t*) handle, &fd); + if (err) + return err; +#endif /* defined(__APPLE__) */ + + return uv__stream_open((uv_stream_t*)handle, + fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb) { + struct sockaddr_un saddr; + int new_sock; + int err; + int r; + + new_sock = (uv__stream_fd(handle) == -1); + err = -EINVAL; + + if (new_sock) { + err = uv__socket(AF_UNIX, SOCK_STREAM, 0); + if (err < 0) + goto out; + handle->io_watcher.fd = err; + } + + memset(&saddr, 0, sizeof saddr); + strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1); + saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + saddr.sun_family = AF_UNIX; + + do { + r = connect(uv__stream_fd(handle), + (struct sockaddr*)&saddr, sizeof saddr); + } + while (r == -1 && errno == EINTR); + + if (r == -1 && errno != EINPROGRESS) { + err = -errno; + goto out; + } + + err = 0; + if (new_sock) { + err = uv__stream_open((uv_stream_t*)handle, + uv__stream_fd(handle), + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + } + + if (err == 0) + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + +out: + handle->delayed_error = err; + handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); + req->handle = (uv_stream_t*)handle; + req->cb = cb; + QUEUE_INIT(&req->queue); + + /* Force callback to run on next tick in case of error. */ + if (err) + uv__io_feed(handle->loop, &handle->io_watcher); + + /* Mimic the Windows pipe implementation, always + * return 0 and let the callback handle errors. + */ +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { +} diff --git a/src/unix/poll.c b/src/unix/poll.c new file mode 100644 index 0000000000..a34a8d1e14 --- /dev/null +++ b/src/unix/poll.c @@ -0,0 +1,107 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + + +static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_poll_t* handle; + int pevents; + + handle = container_of(w, uv_poll_t, io_watcher); + + if (events & UV__POLLERR) { + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__handle_stop(handle); + handle->poll_cb(handle, -EBADF, 0); + return; + } + + pevents = 0; + if (events & UV__POLLIN) + pevents |= UV_READABLE; + if (events & UV__POLLOUT) + pevents |= UV_WRITABLE; + + handle->poll_cb(handle, 0, pevents); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + uv__io_init(&handle->io_watcher, uv__poll_io, fd); + handle->poll_cb = NULL; + return 0; +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + return uv_poll_init(loop, handle, socket); +} + + +static void uv__poll_stop(uv_poll_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__handle_stop(handle); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__poll_stop(handle); + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { + int events; + + assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + uv__poll_stop(handle); + + if (pevents == 0) + return 0; + + events = 0; + if (pevents & UV_READABLE) + events |= UV__POLLIN; + if (pevents & UV_WRITABLE) + events |= UV__POLLOUT; + + uv__io_start(handle->loop, &handle->io_watcher, events); + uv__handle_start(handle); + handle->poll_cb = poll_cb; + + return 0; +} + + +void uv__poll_close(uv_poll_t* handle) { + uv__poll_stop(handle); +} diff --git a/src/unix/process.c b/src/unix/process.c new file mode 100644 index 0000000000..6f96b754d8 --- /dev/null +++ b/src/unix/process.c @@ -0,0 +1,517 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + + +static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) { + assert(pid > 0); + return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles); +} + + +static void uv__chld(uv_signal_t* handle, int signum) { + uv_process_t* process; + uv_loop_t* loop; + int exit_status; + int term_signal; + unsigned int i; + int status; + pid_t pid; + QUEUE pending; + QUEUE* h; + QUEUE* q; + + assert(signum == SIGCHLD); + + QUEUE_INIT(&pending); + loop = handle->loop; + + for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) { + h = loop->process_handles + i; + q = QUEUE_HEAD(h); + + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); + + do + pid = waitpid(process->pid, &status, WNOHANG); + while (pid == -1 && errno == EINTR); + + if (pid == 0) + continue; + + if (pid == -1) { + if (errno != ECHILD) + abort(); + continue; + } + + process->status = status; + QUEUE_REMOVE(&process->queue); + QUEUE_INSERT_TAIL(&pending, &process->queue); + } + + while (!QUEUE_EMPTY(&pending)) { + q = QUEUE_HEAD(&pending); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + process = QUEUE_DATA(q, uv_process_t, queue); + uv__handle_stop(process); + + if (process->exit_cb == NULL) + continue; + + exit_status = 0; + if (WIFEXITED(process->status)) + exit_status = WEXITSTATUS(process->status); + + term_signal = 0; + if (WIFSIGNALED(process->status)) + term_signal = WTERMSIG(process->status); + + process->exit_cb(process, exit_status, term_signal); + } + } +} + + +int uv__make_socketpair(int fds[2], int flags) { +#if defined(__linux__) + static int no_cloexec; + + if (no_cloexec) + goto skip; + + if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0) + return 0; + + /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported. + * Anything else is a genuine error. + */ + if (errno != EINVAL) + return -errno; + + no_cloexec = 1; + +skip: +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +int uv__make_pipe(int fds[2], int flags) { +#if defined(__linux__) + static int no_pipe2; + + if (no_pipe2) + goto skip; + + if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0) + return 0; + + if (errno != ENOSYS) + return -errno; + + no_pipe2 = 1; + +skip: +#endif + + if (pipe(fds)) + return -errno; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +/* + * Used for initializing stdio streams like options.stdin_stream. Returns + * zero on success. See also the cleanup section in uv_spawn(). + */ +static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { + int mask; + int fd; + + mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + + switch (container->flags & mask) { + case UV_IGNORE: + return 0; + + case UV_CREATE_PIPE: + assert(container->data.stream != NULL); + if (container->data.stream->type != UV_NAMED_PIPE) + return -EINVAL; + else + return uv__make_socketpair(fds, 0); + + case UV_INHERIT_FD: + case UV_INHERIT_STREAM: + if (container->flags & UV_INHERIT_FD) + fd = container->data.fd; + else + fd = uv__stream_fd(container->data.stream); + + if (fd == -1) + return -EINVAL; + + fds[1] = fd; + return 0; + + default: + assert(0 && "Unexpected flags"); + return -EINVAL; + } +} + + +static int uv__process_open_stream(uv_stdio_container_t* container, + int pipefds[2], + int writable) { + int flags; + + if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) + return 0; + + if (uv__close(pipefds[1])) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + pipefds[1] = -1; + uv__nonblock(pipefds[0], 1); + + if (container->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*)container->data.stream)->ipc) + flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; + else if (writable) + flags = UV_STREAM_WRITABLE; + else + flags = UV_STREAM_READABLE; + + return uv__stream_open(container->data.stream, pipefds[0], flags); +} + + +static void uv__process_close_stream(uv_stdio_container_t* container) { + if (!(container->flags & UV_CREATE_PIPE)) return; + uv__stream_close((uv_stream_t*)container->data.stream); +} + + +static void uv__write_int(int fd, int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == -1 && errno == EPIPE) + return; /* parent process has quit */ + + assert(n == sizeof(val)); +} + + +static void uv__process_child_init(const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + int error_fd) { + int close_fd; + int use_fd; + int fd; + + if (options->flags & UV_PROCESS_DETACHED) + setsid(); + + for (fd = 0; fd < stdio_count; fd++) { + close_fd = pipes[fd][0]; + use_fd = pipes[fd][1]; + + if (use_fd < 0) { + if (fd >= 3) + continue; + else { + /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set + */ + use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); + close_fd = use_fd; + + if (use_fd == -1) { + uv__write_int(error_fd, -errno); + perror("failed to open stdio"); + _exit(127); + } + } + } + + if (fd == use_fd) + uv__cloexec(use_fd, 0); + else + dup2(use_fd, fd); + + if (fd <= 2) + uv__nonblock(fd, 0); + + if (close_fd != -1) + uv__close(close_fd); + } + + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + + if (use_fd >= 0 && fd != use_fd) + close(use_fd); + } + + if (options->cwd != NULL && chdir(options->cwd)) { + uv__write_int(error_fd, -errno); + perror("chdir()"); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { + uv__write_int(error_fd, -errno); + perror("setgid()"); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { + uv__write_int(error_fd, -errno); + perror("setuid()"); + _exit(127); + } + + if (options->env != NULL) { + environ = options->env; + } + + execvp(options->file, options->args); + uv__write_int(error_fd, -errno); + perror("execvp()"); + _exit(127); +} + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { + int signal_pipe[2] = { -1, -1 }; + int (*pipes)[2]; + int stdio_count; + QUEUE* q; + ssize_t r; + pid_t pid; + int err; + int exec_errorno; + int i; + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); + QUEUE_INIT(&process->queue); + + stdio_count = options->stdio_count; + if (stdio_count < 3) + stdio_count = 3; + + err = -ENOMEM; + pipes = malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) + goto error; + + for (i = 0; i < stdio_count; i++) { + pipes[i][0] = -1; + pipes[i][1] = -1; + } + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_init_stdio(options->stdio + i, pipes[i]); + if (err) + goto error; + } + + /* This pipe is used by the parent to wait until + * the child has called `execve()`. We need this + * to avoid the following race condition: + * + * if ((pid = fork()) > 0) { + * kill(pid, SIGTERM); + * } + * else if (pid == 0) { + * execve("/bin/cat", argp, envp); + * } + * + * The parent sends a signal immediately after forking. + * Since the child may not have called `execve()` yet, + * there is no telling what process receives the signal, + * our fork or /bin/cat. + * + * To avoid ambiguity, we create a pipe with both ends + * marked close-on-exec. Then, after the call to `fork()`, + * the parent polls the read end until it EOFs or errors with EPIPE. + */ + err = uv__make_pipe(signal_pipe, 0); + if (err) + goto error; + + uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); + + pid = fork(); + + if (pid == -1) { + err = -errno; + uv__close(signal_pipe[0]); + uv__close(signal_pipe[1]); + goto error; + } + + if (pid == 0) { + uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + abort(); + } + + uv__close(signal_pipe[1]); + + process->status = 0; + exec_errorno = 0; + do + r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); + while (r == -1 && errno == EINTR); + + if (r == 0) + ; /* okay, EOF */ + else if (r == sizeof(exec_errorno)) + ; /* okay, read errorno */ + else if (r == -1 && errno == EPIPE) + ; /* okay, got EPIPE */ + else + abort(); + + uv__close(signal_pipe[0]); + + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); + if (err == 0) + continue; + + while (i--) + uv__process_close_stream(options->stdio + i); + + goto error; + } + + /* Only activate this handle if exec() happened successfully */ + if (exec_errorno == 0) { + q = uv__process_queue(loop, pid); + QUEUE_INSERT_TAIL(q, &process->queue); + uv__handle_start(process); + } + + process->pid = pid; + process->exit_cb = options->exit_cb; + + free(pipes); + return exec_errorno; + +error: + if (pipes != NULL) { + for (i = 0; i < stdio_count; i++) { + if (i < options->stdio_count) + if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) + continue; + if (pipes[i][0] != -1) + close(pipes[i][0]); + if (pipes[i][1] != -1) + close(pipes[i][1]); + } + free(pipes); + } + + return err; +} + + +int uv_process_kill(uv_process_t* process, int signum) { + return uv_kill(process->pid, signum); +} + + +int uv_kill(int pid, int signum) { + if (kill(pid, signum)) + return -errno; + else + return 0; +} + + +void uv__process_close(uv_process_t* handle) { + /* TODO stop signal watcher when this is the last handle */ + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c new file mode 100644 index 0000000000..16b0523731 --- /dev/null +++ b/src/unix/proctitle.c @@ -0,0 +1,102 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +extern void uv__set_process_title(const char* title); + +static void* args_mem; + +static struct { + char* str; + size_t len; +} process_title; + + +char** uv_setup_args(int argc, char** argv) { + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + process_title.str = argv[0]; + process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; + assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ + + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); + + new_argv = malloc(size); + if (new_argv == NULL) + return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; + } + new_argv[i] = NULL; + + return new_argv; +} + + +int uv_set_process_title(const char* title) { + if (process_title.len == 0) + return 0; + + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (process_title.len > 0) + strncpy(buffer, process_title.str, size); + else if (size > 0) + buffer[0] = '\0'; + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c new file mode 100644 index 0000000000..2e4c542bc2 --- /dev/null +++ b/src/unix/pthread-fixes.c @@ -0,0 +1,80 @@ +/* Copyright (c) 2013, Sony Mobile Communications AB + * Copyright (c) 2012, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/*Android doesn't provide pthread_barrier_t for now.*/ +#ifndef PTHREAD_BARRIER_SERIAL_THREAD + +#include "pthread-fixes.h" + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + barrier->count = count; + pthread_mutex_init(&barrier->mutex, NULL); + pthread_cond_init(&barrier->cond, NULL); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + /* Lock the mutex*/ + pthread_mutex_lock(&barrier->mutex); + /* Decrement the count. If this is the first thread to reach 0, wake up + waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/ + if (--barrier->count == 0) { + /* First thread to reach the barrier */ + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until the count reaches 0, then + return 0 to indicate this is not the first thread.*/ + do { + pthread_cond_wait(&barrier->cond, &barrier->mutex); + } while (barrier->count > 0); + + pthread_mutex_unlock(&barrier->mutex); + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + barrier->count = 0; + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ + +int pthread_yield(void) { + sched_yield(); + return 0; +} diff --git a/src/unix/signal.c b/src/unix/signal.c new file mode 100644 index 0000000000..0b7a405c15 --- /dev/null +++ b/src/unix/signal.c @@ -0,0 +1,465 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct { + uv_signal_t* handle; + int signum; +} uv__signal_msg_t; + +RB_HEAD(uv__signal_tree_s, uv_signal_s); + + +static int uv__signal_unlock(void); +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); +static void uv__signal_stop(uv_signal_t* handle); + + +static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT; +static struct uv__signal_tree_s uv__signal_tree = + RB_INITIALIZER(uv__signal_tree); +static int uv__signal_lock_pipefd[2]; + + +RB_GENERATE_STATIC(uv__signal_tree_s, + uv_signal_s, tree_entry, + uv__signal_compare) + + +static void uv__signal_global_init(void) { + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); +} + + +void uv__signal_global_once_init(void) { + pthread_once(&uv__signal_global_init_guard, uv__signal_global_init); +} + + + +static int uv__signal_lock(void) { + int r; + char data; + + do { + r = read(uv__signal_lock_pipefd[0], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static int uv__signal_unlock(void) { + int r; + char data = 42; + + do { + r = write(uv__signal_lock_pipefd[1], &data, sizeof data); + } while (r < 0 && errno == EINTR); + + return (r < 0) ? -1 : 0; +} + + +static void uv__signal_block_and_lock(sigset_t* saved_sigmask) { + sigset_t new_mask; + + if (sigfillset(&new_mask)) + abort(); + + if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask)) + abort(); + + if (uv__signal_lock()) + abort(); +} + + +static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) { + if (uv__signal_unlock()) + abort(); + + if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL)) + abort(); +} + + +static uv_signal_t* uv__signal_first_handle(int signum) { + /* This function must be called with the signal lock held. */ + uv_signal_t lookup; + uv_signal_t* handle; + + lookup.signum = signum; + lookup.loop = NULL; + + handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup); + + if (handle != NULL && handle->signum == signum) + return handle; + + return NULL; +} + + +static void uv__signal_handler(int signum) { + uv__signal_msg_t msg; + uv_signal_t* handle; + int saved_errno; + + saved_errno = errno; + memset(&msg, 0, sizeof msg); + + if (uv__signal_lock()) { + errno = saved_errno; + return; + } + + for (handle = uv__signal_first_handle(signum); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) { + int r; + + msg.signum = signum; + msg.handle = handle; + + /* write() should be atomic for small data chunks, so the entire message + * should be written at once. In theory the pipe could become full, in + * which case the user is out of luck. + */ + do { + r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg); + } while (r == -1 && errno == EINTR); + + assert(r == sizeof msg || + (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))); + + if (r != -1) + handle->caught_signals++; + } + + uv__signal_unlock(); + errno = saved_errno; +} + + +static int uv__signal_register_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + /* XXX use a separate signal stack? */ + memset(&sa, 0, sizeof(sa)); + if (sigfillset(&sa.sa_mask)) + abort(); + sa.sa_handler = uv__signal_handler; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return -errno; + + return 0; +} + + +static void uv__signal_unregister_handler(int signum) { + /* When this function is called, the signal lock must be held. */ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a + * signal implies that it was successfully registered earlier, so EINVAL + * should never happen. + */ + if (sigaction(signum, &sa, NULL)) + abort(); +} + + +static int uv__signal_loop_once_init(uv_loop_t* loop) { + int err; + + /* Return if already initialized. */ + if (loop->signal_pipefd[0] != -1) + return 0; + + err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK); + if (err) + return err; + + uv__io_init(&loop->signal_io_watcher, + uv__signal_event, + loop->signal_pipefd[0]); + uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN); + + return 0; +} + + +void uv__signal_loop_cleanup(uv_loop_t* loop) { + QUEUE* q; + + /* Stop all the signal watchers that are still attached to this loop. This + * ensures that the (shared) signal tree doesn't contain any invalid entries + * entries, and that signal handlers are removed when appropriate. + */ + QUEUE_FOREACH(q, &loop->handle_queue) { + uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (handle->type == UV_SIGNAL) + uv__signal_stop((uv_signal_t*) handle); + } + + if (loop->signal_pipefd[0] != -1) { + uv__close(loop->signal_pipefd[0]); + loop->signal_pipefd[0] = -1; + } + + if (loop->signal_pipefd[1] != -1) { + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[1] = -1; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + int err; + + err = uv__signal_loop_once_init(loop); + if (err) + return err; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->signum = 0; + handle->caught_signals = 0; + handle->dispatched_signals = 0; + + return 0; +} + + +void uv__signal_close(uv_signal_t* handle) { + + uv__signal_stop(handle); + + /* If there are any caught signals "trapped" in the signal pipe, we can't + * call the close callback yet. Otherwise, add the handle to the finish_close + * queue. + */ + if (handle->caught_signals == handle->dispatched_signals) { + uv__make_close_pending((uv_handle_t*) handle); + } +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + sigset_t saved_sigmask; + int err; + + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + /* If the user supplies signum == 0, then return an error already. If the + * signum is otherwise invalid then uv__signal_register will find out + * eventually. + */ + if (signum == 0) + return -EINVAL; + + /* Short circuit: if the signal watcher is already watching {signum} don't + * go through the process of deregistering and registering the handler. + * Additionally, this avoids pending signals getting lost in the small time + * time frame that handle->signum == 0. + */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + uv__signal_stop(handle); + } + + uv__signal_block_and_lock(&saved_sigmask); + + /* If at this point there are no active signal watchers for this signum (in + * any of the loops), it's time to try and register a handler for it here. + */ + if (uv__signal_first_handle(signum) == NULL) { + err = uv__signal_register_handler(signum); + if (err) { + /* Registering the signal handler failed. Must be an invalid signal. */ + uv__signal_unlock_and_unblock(&saved_sigmask); + return err; + } + } + + handle->signum = signum; + RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +static void uv__signal_event(uv_loop_t* loop, + uv__io_t* w, + unsigned int events) { + uv__signal_msg_t* msg; + uv_signal_t* handle; + char buf[sizeof(uv__signal_msg_t) * 32]; + size_t bytes, end, i; + int r; + + bytes = 0; + end = 0; + + do { + r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes); + + if (r == -1 && errno == EINTR) + continue; + + if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + /* If there are bytes in the buffer already (which really is extremely + * unlikely if possible at all) we can't exit the function here. We'll + * spin until more bytes are read instead. + */ + if (bytes > 0) + continue; + + /* Otherwise, there was nothing there. */ + return; + } + + /* Other errors really should never happen. */ + if (r == -1) + abort(); + + bytes += r; + + /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */ + end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t); + + for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) { + msg = (uv__signal_msg_t*) (buf + i); + handle = msg->handle; + + if (msg->signum == handle->signum) { + assert(!(handle->flags & UV_CLOSING)); + handle->signal_cb(handle, handle->signum); + } + + handle->dispatched_signals++; + + /* If uv_close was called while there were caught signals that were not + * yet dispatched, the uv__finish_close was deferred. Make close pending + * now if this has happened. + */ + if ((handle->flags & UV_CLOSING) && + (handle->caught_signals == handle->dispatched_signals)) { + uv__make_close_pending((uv_handle_t*) handle); + } + } + + bytes -= end; + + /* If there are any "partial" messages left, move them to the start of the + * the buffer, and spin. This should not happen. + */ + if (bytes) { + memmove(buf, buf + end, bytes); + continue; + } + } while (end == sizeof buf); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up + * adjacent. + */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after + * { .signum = x, .loop = NULL }. + */ + if (w1->loop < w2->loop) return -1; + if (w1->loop > w2->loop) return 1; + + if (w1 < w2) return -1; + if (w1 > w2) return 1; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__signal_stop(handle); + return 0; +} + + +static void uv__signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + sigset_t saved_sigmask; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return; + + uv__signal_block_and_lock(&saved_sigmask); + + removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + (void) removed_handle; + + /* Check if there are other active signal watchers observing this signal. If + * not, unregister the signal handler. + */ + if (uv__signal_first_handle(handle->signum) == NULL) + uv__signal_unregister_handler(handle->signum); + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signum = 0; + uv__handle_stop(handle); +} diff --git a/src/unix/spinlock.h b/src/unix/spinlock.h new file mode 100644 index 0000000000..a20c83cc60 --- /dev/null +++ b/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SPINLOCK_H_ +#define UV_SPINLOCK_H_ + +#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */ +#include "atomic-ops.h" + +#define UV_SPINLOCK_INITIALIZER { 0 } + +typedef struct { + int lock; +} uv_spinlock_t; + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)); +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)); +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)); + +UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) { + while (!uv_spinlock_trylock(spinlock)) cpu_relax(); +} + +UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) { + ACCESS_ONCE(int, spinlock->lock) = 0; +} + +UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) { + /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing. + * Not really critical until we have locks that are (frequently) contended + * for by several threads. + */ + return 0 == cmpxchgi(&spinlock->lock, 0, 1); +} + +#endif /* UV_SPINLOCK_H_ */ diff --git a/src/unix/stream.c b/src/unix/stream.c new file mode 100644 index 0000000000..9f5d40cf4b --- /dev/null +++ b/src/unix/stream.c @@ -0,0 +1,1511 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* IOV_MAX */ + +#if defined(__APPLE__) +# include +# include +# include + +/* Forward declaration */ +typedef struct uv__stream_select_s uv__stream_select_t; + +struct uv__stream_select_s { + uv_stream_t* stream; + uv_thread_t thread; + uv_sem_t close_sem; + uv_sem_t async_sem; + uv_async_t async; + int events; + int fake_fd; + int int_fd; + int fd; +}; +#endif /* defined(__APPLE__) */ + +static void uv__stream_connect(uv_stream_t*); +static void uv__write(uv_stream_t* stream); +static void uv__read(uv_stream_t* stream); +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static size_t uv__write_req_size(uv_write_t* req); + + +/* Used by the accept() EMFILE party trick. */ +static int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(__linux__) + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return -errno; + + /* O_CLOEXEC not supported. */ +#endif + + fd = open(path, flags); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { + unsigned int i; + size_t bytes; + + bytes = 0; + for (i = 0; i < nbufs; i++) + bytes += bufs[i].len; + + return bytes; +} + + +void uv__stream_init(uv_loop_t* loop, + uv_stream_t* stream, + uv_handle_type type) { + int err; + + uv__handle_init(loop, (uv_handle_t*)stream, type); + stream->read_cb = NULL; + stream->read2_cb = NULL; + stream->alloc_cb = NULL; + stream->close_cb = NULL; + stream->connection_cb = NULL; + stream->connect_req = NULL; + stream->shutdown_req = NULL; + stream->accepted_fd = -1; + stream->delayed_error = 0; + QUEUE_INIT(&stream->write_queue); + QUEUE_INIT(&stream->write_completed_queue); + stream->write_queue_size = 0; + + if (loop->emfile_fd == -1) { + err = uv__open_cloexec("/", O_RDONLY); + if (err >= 0) + loop->emfile_fd = err; + } + +#if defined(__APPLE__) + stream->select = NULL; +#endif /* defined(__APPLE_) */ + + uv__io_init(&stream->io_watcher, uv__stream_io, -1); +} + + +static void uv__stream_osx_interrupt_select(uv_stream_t* stream) { +#if defined(__APPLE__) + /* Notify select() thread about state change */ + uv__stream_select_t* s; + int r; + + s = stream->select; + if (s == NULL) + return; + + /* Interrupt select() loop + * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will + * emit read event on other side + */ + do + r = write(s->fake_fd, "x", 1); + while (r == -1 && errno == EINTR); + + assert(r == 1); +#else /* !defined(__APPLE__) */ + /* No-op on any other platform */ +#endif /* !defined(__APPLE__) */ +} + + +#if defined(__APPLE__) +static void uv__stream_osx_select(void* arg) { + uv_stream_t* stream; + uv__stream_select_t* s; + char buf[1024]; + fd_set sread; + fd_set swrite; + int events; + int fd; + int r; + int max_fd; + + stream = arg; + s = stream->select; + fd = s->fd; + + if (fd > s->int_fd) + max_fd = fd; + else + max_fd = s->int_fd; + + while (1) { + /* Terminate on semaphore */ + if (uv_sem_trywait(&s->close_sem) == 0) + break; + + /* Watch fd using select(2) */ + FD_ZERO(&sread); + FD_ZERO(&swrite); + + if (uv__io_active(&stream->io_watcher, UV__POLLIN)) + FD_SET(fd, &sread); + if (uv__io_active(&stream->io_watcher, UV__POLLOUT)) + FD_SET(fd, &swrite); + FD_SET(s->int_fd, &sread); + + /* Wait indefinitely for fd events */ + r = select(max_fd + 1, &sread, &swrite, NULL, NULL); + if (r == -1) { + if (errno == EINTR) + continue; + + /* XXX: Possible?! */ + abort(); + } + + /* Ignore timeouts */ + if (r == 0) + continue; + + /* Empty socketpair's buffer in case of interruption */ + if (FD_ISSET(s->int_fd, &sread)) + while (1) { + r = read(s->int_fd, buf, sizeof(buf)); + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + /* Handle events */ + events = 0; + if (FD_ISSET(fd, &sread)) + events |= UV__POLLIN; + if (FD_ISSET(fd, &swrite)) + events |= UV__POLLOUT; + + assert(events != 0 || FD_ISSET(s->int_fd, &sread)); + if (events != 0) { + ACCESS_ONCE(int, s->events) = events; + + uv_async_send(&s->async); + uv_sem_wait(&s->async_sem); + + /* Should be processed at this stage */ + assert((s->events == 0) || (stream->flags & UV_CLOSING)); + } + } +} + + +static void uv__stream_osx_select_cb(uv_async_t* handle, int status) { + uv__stream_select_t* s; + uv_stream_t* stream; + int events; + + s = container_of(handle, uv__stream_select_t, async); + stream = s->stream; + + /* Get and reset stream's events */ + events = s->events; + ACCESS_ONCE(int, s->events) = 0; + uv_sem_post(&s->async_sem); + + assert(events != 0); + assert(events == (events & (UV__POLLIN | UV__POLLOUT))); + + /* Invoke callback on event-loop */ + if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN); + + if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT); +} + + +static void uv__stream_osx_cb_close(uv_handle_t* async) { + uv__stream_select_t* s; + + s = container_of(async, uv__stream_select_t, async); + free(s); +} + + +int uv__stream_try_select(uv_stream_t* stream, int* fd) { + /* + * kqueue doesn't work with some files from /dev mount on osx. + * select(2) in separate thread for those fds + */ + + struct kevent filter[1]; + struct kevent events[1]; + struct timespec timeout; + uv__stream_select_t* s; + int fds[2]; + int err; + int ret; + int kq; + + kq = kqueue(); + if (kq == -1) { + perror("(libuv) kqueue()"); + return -errno; + } + + EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + + /* Use small timeout, because we only want to capture EINVALs */ + timeout.tv_sec = 0; + timeout.tv_nsec = 1; + + ret = kevent(kq, filter, 1, events, 1, &timeout); + uv__close(kq); + + if (ret == -1) + return -errno; + + if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) + return 0; + + /* At this point we definitely know that this fd won't work with kqueue */ + s = malloc(sizeof(*s)); + if (s == NULL) + return -ENOMEM; + + s->events = 0; + s->fd = *fd; + + err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb); + if (err) { + free(s); + return err; + } + + s->async.flags |= UV__HANDLE_INTERNAL; + uv__handle_unref(&s->async); + + if (uv_sem_init(&s->close_sem, 0)) + goto fatal1; + + if (uv_sem_init(&s->async_sem, 0)) + goto fatal2; + + /* Create fds for io watcher and to interrupt the select() loop. */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + goto fatal3; + + s->fake_fd = fds[0]; + s->int_fd = fds[1]; + + if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) + goto fatal4; + + s->stream = stream; + stream->select = s; + *fd = s->fake_fd; + + return 0; + +fatal4: + uv__close(s->fake_fd); + uv__close(s->int_fd); + s->fake_fd = -1; + s->int_fd = -1; +fatal3: + uv_sem_destroy(&s->async_sem); +fatal2: + uv_sem_destroy(&s->close_sem); +fatal1: + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + return -errno; +} +#endif /* defined(__APPLE__) */ + + +int uv__stream_open(uv_stream_t* stream, int fd, int flags) { + assert(fd >= 0); + stream->flags |= flags; + + if (stream->type == UV_TCP) { + if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return -errno; + + /* TODO Use delay the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + return -errno; + } + + stream->io_watcher.fd = fd; + + return 0; +} + + +void uv__stream_destroy(uv_stream_t* stream) { + uv_write_t* req; + QUEUE* q; + + assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(stream->flags & UV_CLOSED); + + if (stream->connect_req) { + uv__req_unregister(stream->loop, stream->connect_req); + stream->connect_req->cb(stream->connect_req, -ECANCELED); + stream->connect_req = NULL; + } + + while (!QUEUE_EMPTY(&stream->write_queue)) { + q = QUEUE_HEAD(&stream->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + + if (req->cb != NULL) + req->cb(req, -ECANCELED); + } + + while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + q = QUEUE_HEAD(&stream->write_completed_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + } + + if (req->cb) + req->cb(req, req->error); + } + + if (stream->shutdown_req) { + /* The ECANCELED error code is a lie, the shutdown(2) syscall is a + * fait accompli at this point. Maybe we should revisit this in v0.11. + * A possible reason for leaving it unchanged is that it informs the + * callee that the handle has been destroyed. + */ + uv__req_unregister(stream->loop, stream->shutdown_req); + stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); + stream->shutdown_req = NULL; + } +} + + +/* Implements a best effort approach to mitigating accept() EMFILE errors. + * We have a spare file descriptor stashed away that we close to get below + * the EMFILE limit. Next, we accept all pending connections and close them + * immediately to signal the clients that we're overloaded - and we are, but + * we still keep on trucking. + * + * There is one caveat: it's not reliable in a multi-threaded environment. + * The file descriptor limit is per process. Our party trick fails if another + * thread opens a file or creates a socket in the time window between us + * calling close() and accept(). + */ +static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { + int err; + + if (loop->emfile_fd == -1) + return -EMFILE; + + uv__close(loop->emfile_fd); + loop->emfile_fd = -1; + + do { + err = uv__accept(accept_fd); + if (err >= 0) + uv__close(err); + } while (err >= 0 || err == -EINTR); + + SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY)); + return err; +} + + +#if defined(UV_HAVE_KQUEUE) +# define UV_DEC_BACKLOG(w) w->rcount--; +#else +# define UV_DEC_BACKLOG(w) /* no-op */ +#endif /* defined(UV_HAVE_KQUEUE) */ + + +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + int err; + + stream = container_of(w, uv_stream_t, io_watcher); + assert(events == UV__POLLIN); + assert(stream->accepted_fd == -1); + assert(!(stream->flags & UV_CLOSING)); + + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + + /* connection_cb can close the server socket while we're + * in the loop so check it on each iteration. + */ + while (uv__stream_fd(stream) != -1) { + assert(stream->accepted_fd == -1); + +#if defined(UV_HAVE_KQUEUE) + if (w->rcount <= 0) + return; +#endif /* defined(UV_HAVE_KQUEUE) */ + + err = uv__accept(uv__stream_fd(stream)); + if (err < 0) { + if (err == -EAGAIN || err == -EWOULDBLOCK) + return; /* Not an error. */ + + if (err == -ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ + + if (err == -EMFILE || err == -ENFILE) { + err = uv__emfile_trick(loop, uv__stream_fd(stream)); + if (err == -EAGAIN || err == -EWOULDBLOCK) + break; + } + + stream->connection_cb(stream, err); + continue; + } + + UV_DEC_BACKLOG(w) + stream->accepted_fd = err; + stream->connection_cb(stream, 0); + + if (stream->accepted_fd != -1) { + /* The user hasn't yet accepted called uv_accept() */ + uv__io_stop(loop, &stream->io_watcher, UV__POLLIN); + return; + } + + if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + /* Give other processes a chance to accept connections. */ + struct timespec timeout = { 0, 1 }; + nanosleep(&timeout, NULL); + } + } +} + + +#undef UV_DEC_BACKLOG + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + /* TODO document this */ + assert(server->loop == client->loop); + + if (server->accepted_fd == -1) + return -EAGAIN; + + switch (client->type) { + case UV_NAMED_PIPE: + case UV_TCP: + err = uv__stream_open(client, + server->accepted_fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) { + /* TODO handle error */ + uv__close(server->accepted_fd); + server->accepted_fd = -1; + return err; + } + break; + + case UV_UDP: + err = uv_udp_open((uv_udp_t*) client, server->accepted_fd); + if (err) { + uv__close(server->accepted_fd); + server->accepted_fd = -1; + return err; + } + break; + + default: + assert(0); + } + + uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); + server->accepted_fd = -1; + return 0; +} + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + err = -EINVAL; + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + + default: + assert(0); + } + + if (err == 0) + uv__handle_start(stream); + + return err; +} + + +static void uv__drain(uv_stream_t* stream) { + uv_shutdown_t* req; + int err; + + assert(QUEUE_EMPTY(&stream->write_queue)); + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__stream_osx_interrupt_select(stream); + + /* Shutdown? */ + if ((stream->flags & UV_STREAM_SHUTTING) && + !(stream->flags & UV_CLOSING) && + !(stream->flags & UV_STREAM_SHUT)) { + assert(stream->shutdown_req); + + req = stream->shutdown_req; + stream->shutdown_req = NULL; + stream->flags &= ~UV_STREAM_SHUTTING; + uv__req_unregister(stream->loop, req); + + err = 0; + if (shutdown(uv__stream_fd(stream), SHUT_WR)) + err = -errno; + + if (err == 0) + stream->flags |= UV_STREAM_SHUT; + + if (req->cb != NULL) + req->cb(req, err); + } +} + + +static size_t uv__write_req_size(uv_write_t* req) { + size_t size; + + assert(req->bufs != NULL); + size = uv_count_bufs(req->bufs + req->write_index, + req->nbufs - req->write_index); + assert(req->handle->write_queue_size >= size); + + return size; +} + + +static void uv__write_req_finish(uv_write_t* req) { + uv_stream_t* stream = req->handle; + + /* Pop the req off tcp->write_queue. */ + QUEUE_REMOVE(&req->queue); + + /* Only free when there was no error. On error, we touch up write_queue_size + * right before making the callback. The reason we don't do that right away + * is that a write_queue_size > 0 is our only way to signal to the user that + * they should stop writing - which they should if we got an error. Something + * to revisit in future revisions of the libuv API. + */ + if (req->error == 0) { + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + } + + /* Add it to the write_completed_queue where it will have its + * callback called in the near future. + */ + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + uv__io_feed(stream->loop, &stream->io_watcher); +} + + +static int uv__handle_fd(uv_handle_t* handle) { + switch (handle->type) { + case UV_NAMED_PIPE: + case UV_TCP: + return ((uv_stream_t*) handle)->io_watcher.fd; + + case UV_UDP: + return ((uv_udp_t*) handle)->io_watcher.fd; + + default: + return -1; + } +} + +static int uv__getiovmax() { +#if defined(IOV_MAX) + return IOV_MAX; +#elif defined(_SC_IOV_MAX) + static int iovmax = -1; + if (iovmax == -1) + iovmax = sysconf(_SC_IOV_MAX); + return iovmax; +#else + return 1024; +#endif +} + +static void uv__write(uv_stream_t* stream) { + struct iovec* iov; + QUEUE* q; + uv_write_t* req; + int iovmax; + int iovcnt; + ssize_t n; + +start: + + assert(uv__stream_fd(stream) >= 0); + + if (QUEUE_EMPTY(&stream->write_queue)) + return; + + q = QUEUE_HEAD(&stream->write_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + assert(req->handle == stream); + + /* + * Cast to iovec. We had to have our own uv_buf_t instead of iovec + * because Windows's WSABUF is not an iovec. + */ + assert(sizeof(uv_buf_t) == sizeof(struct iovec)); + iov = (struct iovec*) &(req->bufs[req->write_index]); + iovcnt = req->nbufs - req->write_index; + + iovmax = uv__getiovmax(); + + /* Limit iov count to avoid EINVALs from writev() */ + if (iovcnt > iovmax) + iovcnt = iovmax; + + /* + * Now do the actual writev. Note that we've been updating the pointers + * inside the iov each time we write. So there is no need to offset it. + */ + + if (req->send_handle) { + struct msghdr msg; + char scratch[64]; + struct cmsghdr *cmsg; + int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + + assert(fd_to_send >= 0); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = iovcnt; + msg.msg_flags = 0; + + msg.msg_control = (void*) scratch; + msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send)); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = msg.msg_controllen; + + /* silence aliasing warning */ + { + void* pv = CMSG_DATA(cmsg); + int* pi = pv; + *pi = fd_to_send; + } + + do { + n = sendmsg(uv__stream_fd(stream), &msg, 0); + } + while (n == -1 && errno == EINTR); + } else { + do { + if (iovcnt == 1) { + n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); + } else { + n = writev(uv__stream_fd(stream), iov, iovcnt); + } + } + while (n == -1 && errno == EINTR); + } + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + /* Error */ + req->error = -errno; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + if (!uv__io_active(&stream->io_watcher, UV__POLLIN)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + return; + } else if (stream->flags & UV_STREAM_BLOCKING) { + /* If this is a blocking stream, try again. */ + goto start; + } + } else { + /* Successful write */ + + while (n >= 0) { + uv_buf_t* buf = &(req->bufs[req->write_index]); + size_t len = buf->len; + + assert(req->write_index < req->nbufs); + + if ((size_t)n < len) { + buf->base += n; + buf->len -= n; + stream->write_queue_size -= n; + n = 0; + + /* There is more to write. */ + if (stream->flags & UV_STREAM_BLOCKING) { + /* + * If we're blocking then we should not be enabling the write + * watcher - instead we need to try again. + */ + goto start; + } else { + /* Break loop and ensure the watcher is pending. */ + break; + } + + } else { + /* Finished writing the buf at index req->write_index. */ + req->write_index++; + + assert((size_t)n >= len); + n -= len; + + assert(stream->write_queue_size >= len); + stream->write_queue_size -= len; + + if (req->write_index == req->nbufs) { + /* Then we're done! */ + assert(n == 0); + uv__write_req_finish(req); + /* TODO: start trying to write the next request. */ + return; + } + } + } + } + + /* Either we've counted n down to zero or we've got EAGAIN. */ + assert(n == 0 || n == -1); + + /* Only non-blocking streams should use the write_watcher. */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + + /* We're not done. */ + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); +} + + +static void uv__write_callbacks(uv_stream_t* stream) { + uv_write_t* req; + QUEUE* q; + + while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + /* Pop a req off write_completed_queue. */ + q = QUEUE_HEAD(&stream->write_completed_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + QUEUE_REMOVE(q); + uv__req_unregister(stream->loop, req); + + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + } + + /* NOTE: call callback AFTER freeing the request data. */ + if (req->cb) + req->cb(req, req->error); + } + + assert(QUEUE_EMPTY(&stream->write_completed_queue)); + + /* Write queue drained. */ + if (QUEUE_EMPTY(&stream->write_queue)) + uv__drain(stream); +} + + +static uv_handle_type uv__handle_type(int fd) { + struct sockaddr_storage ss; + socklen_t len; + int type; + + memset(&ss, 0, sizeof(ss)); + len = sizeof(ss); + + if (getsockname(fd, (struct sockaddr*)&ss, &len)) + return UV_UNKNOWN_HANDLE; + + len = sizeof type; + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_STREAM) { + switch (ss.ss_family) { + case AF_UNIX: + return UV_NAMED_PIPE; + case AF_INET: + case AF_INET6: + return UV_TCP; + } + } + + if (type == SOCK_DGRAM && + (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)) + return UV_UDP; + + return UV_UNKNOWN_HANDLE; +} + + +static void uv__stream_read_cb(uv_stream_t* stream, + int status, + const uv_buf_t* buf, + uv_handle_type type) { + if (stream->read_cb != NULL) + stream->read_cb(stream, status, buf); + else + stream->read2_cb((uv_pipe_t*) stream, status, buf, type); +} + + +static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { + stream->flags |= UV_STREAM_READ_EOF; + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); + if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + uv__stream_read_cb(stream, UV_EOF, buf, UV_UNKNOWN_HANDLE); +} + + +static void uv__read(uv_stream_t* stream) { + uv_buf_t buf; + ssize_t nread; + struct msghdr msg; + struct cmsghdr* cmsg; + char cmsg_space[64]; + int count; + + stream->flags &= ~UV_STREAM_READ_PARTIAL; + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + /* XXX: Maybe instead of having UV_STREAM_READING we just test if + * tcp->read_cb is NULL or not? + */ + while ((stream->read_cb || stream->read2_cb) + && (stream->flags & UV_STREAM_READING) + && (count-- > 0)) { + assert(stream->alloc_cb != NULL); + + stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); + if (buf.len == 0) { + /* User indicates it can't or won't handle the read. */ + uv__stream_read_cb(stream, UV_ENOBUFS, &buf, UV_UNKNOWN_HANDLE); + return; + } + + assert(buf.base != NULL); + assert(uv__stream_fd(stream) >= 0); + + if (stream->read_cb) { + do { + nread = read(uv__stream_fd(stream), buf.base, buf.len); + } + while (nread < 0 && errno == EINTR); + } else { + assert(stream->read2_cb); + /* read2_cb uses recvmsg */ + msg.msg_flags = 0; + msg.msg_iov = (struct iovec*) &buf; + msg.msg_iovlen = 1; + msg.msg_name = NULL; + msg.msg_namelen = 0; + /* Set up to receive a descriptor even if one isn't in the message */ + msg.msg_controllen = 64; + msg.msg_control = (void*) cmsg_space; + + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + } + while (nread < 0 && errno == EINTR); + } + + if (nread < 0) { + /* Error */ + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* Wait for the next one. */ + if (stream->flags & UV_STREAM_READING) { + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__stream_osx_interrupt_select(stream); + } + uv__stream_read_cb(stream, 0, &buf, UV_UNKNOWN_HANDLE); + } else { + /* Error. User should call uv_close(). */ + uv__stream_read_cb(stream, -errno, &buf, UV_UNKNOWN_HANDLE); + assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) && + "stream->read_cb(status=-1) did not call uv_close()"); + } + return; + } else if (nread == 0) { + uv__stream_eof(stream, &buf); + return; + } else { + /* Successful read */ + ssize_t buflen = buf.len; + + if (stream->read_cb) { + stream->read_cb(stream, nread, &buf); + } else { + assert(stream->read2_cb); + + /* + * XXX: Some implementations can send multiple file descriptors in a + * single message. We should be using CMSG_NXTHDR() to walk the + * chain to get at them all. This would require changing the API to + * hand these back up the caller, is a pain. + */ + + for (cmsg = CMSG_FIRSTHDR(&msg); + msg.msg_controllen > 0 && cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + + if (cmsg->cmsg_type == SCM_RIGHTS) { + if (stream->accepted_fd != -1) { + fprintf(stderr, "(libuv) ignoring extra FD received\n"); + } + + /* silence aliasing warning */ + { + void* pv = CMSG_DATA(cmsg); + int* pi = pv; + stream->accepted_fd = *pi; + } + + } else { + fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", + cmsg->cmsg_type); + } + } + + + if (stream->accepted_fd >= 0) { + stream->read2_cb((uv_pipe_t*) stream, + nread, + &buf, + uv__handle_type(stream->accepted_fd)); + } else { + stream->read2_cb((uv_pipe_t*) stream, nread, &buf, UV_UNKNOWN_HANDLE); + } + } + + /* Return if we didn't fill the buffer, there is no more data to read. */ + if (nread < buflen) { + stream->flags |= UV_STREAM_READ_PARTIAL; + return; + } + } + } +} + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { + assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && + "uv_shutdown (unix) only supports uv_handle_t right now"); + + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || + stream->flags & UV_CLOSED || + stream->flags & UV_CLOSING) { + return -ENOTCONN; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Initialize request */ + uv__req_init(stream->loop, req, UV_SHUTDOWN); + req->handle = stream; + req->cb = cb; + stream->shutdown_req = req; + stream->flags |= UV_STREAM_SHUTTING; + + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + uv_stream_t* stream; + + stream = container_of(w, uv_stream_t, io_watcher); + + assert(stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + assert(!(stream->flags & UV_CLOSING)); + + if (stream->connect_req) { + uv__stream_connect(stream); + return; + } + + assert(uv__stream_fd(stream) >= 0); + + /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + if (events & (UV__POLLIN | UV__POLLERR)) + uv__read(stream); + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + /* Short-circuit iff POLLHUP is set, the user is still interested in read + * events and uv__read() reported a partial read but not EOF. If the EOF + * flag is set, uv__read() called read_cb with err=UV_EOF and we don't + * have to do anything. If the partial read flag is not set, we can't + * report the EOF yet because there is still data to read. + */ + if ((events & UV__POLLHUP) && + (stream->flags & UV_STREAM_READING) && + (stream->flags & UV_STREAM_READ_PARTIAL) && + !(stream->flags & UV_STREAM_READ_EOF)) { + uv_buf_t buf = { NULL, 0 }; + uv__stream_eof(stream, &buf); + } + + if (uv__stream_fd(stream) == -1) + return; /* read_cb closed stream. */ + + if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { + uv__write(stream); + uv__write_callbacks(stream); + } +} + + +/** + * We get called here from directly following a call to connect(2). + * In order to determine if we've errored out or succeeded must call + * getsockopt. + */ +static void uv__stream_connect(uv_stream_t* stream) { + int error; + uv_connect_t* req = stream->connect_req; + socklen_t errorsize = sizeof(int); + + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE); + assert(req); + + if (stream->delayed_error) { + /* To smooth over the differences between unixes errors that + * were reported synchronously on the first connect can be delayed + * until the next tick--which is now. + */ + error = stream->delayed_error; + stream->delayed_error = 0; + } else { + /* Normal situation: we need to get the socket error from the kernel. */ + assert(uv__stream_fd(stream) >= 0); + getsockopt(uv__stream_fd(stream), + SOL_SOCKET, + SO_ERROR, + &error, + &errorsize); + error = -error; + } + + if (error == -EINPROGRESS) + return; + + stream->connect_req = NULL; + uv__req_unregister(stream->loop, req); + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + + if (req->cb) + req->cb(req, error); +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int empty_queue; + + assert(nbufs > 0); + assert((stream->type == UV_TCP || + stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY) && + "uv_write (unix) does not yet support other types of streams"); + + if (uv__stream_fd(stream) < 0) + return -EBADF; + + if (send_handle) { + if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) + return -EINVAL; + + /* XXX We abuse uv_write2() to send over UDP handles to child processes. + * Don't call uv__stream_fd() on those handles, it's a macro that on OS X + * evaluates to a function that operates on a uv_stream_t with a couple of + * OS X specific fields. On other Unices it does (handle)->io_watcher.fd, + * which works but only by accident. + */ + if (uv__handle_fd((uv_handle_t*) send_handle) < 0) + return -EBADF; + } + + /* It's legal for write_queue_size > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up write_queue_size later, see also uv__write_req_finish(). + * We chould check that write_queue is empty instead but that implies making + * a write() syscall when we know that the handle is in error mode. + */ + empty_queue = (stream->write_queue_size == 0); + + /* Initialize the req */ + uv__req_init(stream->loop, req, UV_WRITE); + req->cb = cb; + req->handle = stream; + req->error = 0; + req->send_handle = send_handle; + QUEUE_INIT(&req->queue); + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + req->nbufs = nbufs; + req->write_index = 0; + stream->write_queue_size += uv_count_bufs(bufs, nbufs); + + /* Append the request to write_queue. */ + QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); + + /* If the queue was empty when this function began, we should attempt to + * do the write immediately. Otherwise start the write_watcher and wait + * for the fd to become writable. + */ + if (stream->connect_req) { + /* Still connecting, do nothing. */ + } + else if (empty_queue) { + uv__write(stream); + } + else { + /* + * blocking streams should never have anything in the queue. + * if this assert fires then somehow the blocking stream isn't being + * sufficiently flushed in uv__write. + */ + assert(!(stream->flags & UV_STREAM_BLOCKING)); + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + return 0; +} + + +/* The buffers to be written must remain valid until the callback is called. + * This is not required for the uv_buf_t array. + */ +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_write2(req, handle, bufs, nbufs, NULL, cb); +} + + +void uv_try_write_cb(uv_write_t* req, int status) { + /* Should not be called */ + abort(); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + int r; + int has_pollout; + size_t written; + size_t req_size; + uv_write_t req; + + /* Connecting or already writing some data */ + if (stream->connect_req != NULL || stream->write_queue_size != 0) + return 0; + + has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); + + r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); + if (r != 0) + return r; + + /* Remove not written bytes from write queue size */ + written = uv_count_bufs(bufs, nbufs); + if (req.bufs != NULL) + req_size = uv__write_req_size(&req); + else + req_size = 0; + written -= req_size; + stream->write_queue_size -= req_size; + + /* Unqueue request, regardless of immediateness */ + QUEUE_REMOVE(&req.queue); + uv__req_unregister(stream->loop, &req); + if (req.bufs != req.bufsml) + free(req.bufs); + req.bufs = NULL; + + /* Do not poll for writable, if we wasn't before calling this */ + if (!has_pollout) { + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + return (int) written; +} + + +static int uv__read_start_common(uv_stream_t* stream, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb, + uv_read2_cb read2_cb) { + assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || + stream->type == UV_TTY); + + if (stream->flags & UV_CLOSING) + return -EINVAL; + + /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + * expresses the desired state of the user. + */ + stream->flags |= UV_STREAM_READING; + + /* TODO: try to do the read inline? */ + /* TODO: keep track of tcp state. If we've gotten a EOF then we should + * not start the IO watcher. + */ + assert(uv__stream_fd(stream) >= 0); + assert(alloc_cb); + + stream->read_cb = read_cb; + stream->read2_cb = read2_cb; + stream->alloc_cb = alloc_cb; + + uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__handle_start(stream); + uv__stream_osx_interrupt_select(stream); + + return 0; +} + + +int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + return uv__read_start_common(stream, alloc_cb, read_cb, NULL); +} + + +int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, + uv_read2_cb read_cb) { + return uv__read_start_common(stream, alloc_cb, NULL, read_cb); +} + + +int uv_read_stop(uv_stream_t* stream) { + /* Sanity check. We're going to stop the handle unless it's primed for + * writing but that means there should be some kind of write action in + * progress. + */ + assert(!uv__io_active(&stream->io_watcher, UV__POLLOUT) || + !QUEUE_EMPTY(&stream->write_completed_queue) || + !QUEUE_EMPTY(&stream->write_queue) || + stream->shutdown_req != NULL || + stream->connect_req != NULL); + + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); + if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); + + stream->read_cb = NULL; + stream->read2_cb = NULL; + stream->alloc_cb = NULL; + return 0; +} + + +int uv_is_readable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_READABLE); +} + + +int uv_is_writable(const uv_stream_t* stream) { + return !!(stream->flags & UV_STREAM_WRITABLE); +} + + +#if defined(__APPLE__) +int uv___stream_fd(uv_stream_t* handle) { + uv__stream_select_t* s; + + assert(handle->type == UV_TCP || + handle->type == UV_TTY || + handle->type == UV_NAMED_PIPE); + + s = handle->select; + if (s != NULL) + return s->fd; + + return handle->io_watcher.fd; +} +#endif /* defined(__APPLE__) */ + + +void uv__stream_close(uv_stream_t* handle) { +#if defined(__APPLE__) + /* Terminate select loop first */ + if (handle->select != NULL) { + uv__stream_select_t* s; + + s = handle->select; + + uv_sem_post(&s->close_sem); + uv_sem_post(&s->async_sem); + uv__stream_osx_interrupt_select(handle); + uv_thread_join(&s->thread); + uv_sem_destroy(&s->close_sem); + uv_sem_destroy(&s->async_sem); + uv__close(s->fake_fd); + uv__close(s->int_fd); + uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); + + handle->select = NULL; + } +#endif /* defined(__APPLE__) */ + + uv__io_close(handle->loop, &handle->io_watcher); + uv_read_stop(handle); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + /* Don't close stdio file descriptors. Nothing good comes from it. */ + if (handle->io_watcher.fd > STDERR_FILENO) + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } + + if (handle->accepted_fd != -1) { + uv__close(handle->accepted_fd); + handle->accepted_fd = -1; + } + + assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + assert(0 && "implement me"); + abort(); + return 0; +} diff --git a/src/unix/sunos.c b/src/unix/sunos.c new file mode 100644 index 0000000000..f31a23fb3c --- /dev/null +++ b/src/unix/sunos.c @@ -0,0 +1,734 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#ifndef SUNOS_NO_IFADDRS +# include +#endif +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define PORT_FIRED 0x69 +#define PORT_UNUSED 0x0 +#define PORT_LOADED 0x99 +#define PORT_DELETED -1 + +#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) +#define PROCFS_FILE_OFFSET_BITS_HACK 1 +#undef _FILE_OFFSET_BITS +#else +#define PROCFS_FILE_OFFSET_BITS_HACK 0 +#endif + +#include + +#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1) +#define _FILE_OFFSET_BITS 64 +#endif + + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + int err; + int fd; + + loop->fs_fd = -1; + loop->backend_fd = -1; + + fd = port_create(); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + loop->backend_fd = fd; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct port_event* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct port_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].portev_object == fd) + events[i].portev_object = -1; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct port_event events[1024]; + struct port_event* pe; + struct timespec spec; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + unsigned int nfds; + unsigned int i; + int saved_errno; + int nevents; + int count; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) + abort(); + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + /* Work around a kernel bug where nfds is not updated. */ + events[0].portev_source = 0; + + nfds = 1; + saved_errno = 0; + if (port_getn(loop->backend_fd, + events, + ARRAY_SIZE(events), + &nfds, + timeout == -1 ? NULL : &spec)) { + /* Work around another kernel bug: port_getn() may return events even + * on error. + */ + if (errno == EINTR || errno == ETIME) + saved_errno = errno; + else + abort(); + } + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (events[0].portev_source == 0) { + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + goto update_timeout; + } + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->portev_object; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + /* File descriptor that we've stopped watching, ignore. */ + if (w == NULL) + continue; + + w->cb(loop, w, pe->portev_events); + nevents++; + + if (w != loop->watchers[fd]) + continue; /* Disabled by callback. */ + + /* Events Ports operates in oneshot mode, rearm timer on next run. */ + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (saved_errno == ETIME) { + assert(timeout != -1); + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + return gethrtime(); +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + */ +int uv_exepath(char* buffer, size_t* size) { + ssize_t res; + char buf[128]; + + if (buffer == NULL || size == NULL) + return -EINVAL; + + snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); + res = readlink(buf, buffer, *size - 1); + if (res == -1) + return -errno; + + buffer[res] = '\0'; + *size = res; + return 0; +} + + +uint64_t uv_get_free_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); +} + + +uint64_t uv_get_total_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); +} + + +void uv_loadavg(double avg[3]) { + (void) getloadavg(avg, 3); +} + + +#if defined(PORT_SOURCE_FILE) + +static int uv__fs_event_rearm(uv_fs_event_t *handle) { + if (handle->fd == -1) + return -EBADF; + + if (port_associate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo, + FILE_ATTRIB | FILE_MODIFIED, + handle) == -1) { + return -errno; + } + handle->fd = PORT_LOADED; + + return 0; +} + + +static void uv__fs_event_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents) { + uv_fs_event_t *handle = NULL; + timespec_t timeout; + port_event_t pe; + int events; + int r; + + (void) w; + (void) revents; + + do { + uint_t n = 1; + + /* + * Note that our use of port_getn() here (and not port_get()) is deliberate: + * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout + * causes port_get() to return success instead of ETIME when there aren't + * actually any events (!); by using port_getn() in lieu of port_get(), + * we can at least workaround the bug by checking for zero returned events + * and treating it as we would ETIME. + */ + do { + memset(&timeout, 0, sizeof timeout); + r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout); + } + while (r == -1 && errno == EINTR); + + if ((r == -1 && errno == ETIME) || n == 0) + break; + + handle = (uv_fs_event_t*) pe.portev_user; + assert((r == 0) && "unexpected port_get() error"); + + events = 0; + if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_CHANGE; + if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED)) + events |= UV_RENAME; + assert(events != 0); + handle->fd = PORT_FIRED; + handle->cb(handle, NULL, events, 0); + } + while (handle->fd != PORT_DELETED); + + if (handle != NULL && handle->fd != PORT_DELETED) + uv__fs_event_rearm(handle); /* FIXME(bnoordhuis) Check return code. */ +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + int portfd; + int first_run; + + if (uv__is_active(handle)) + return -EINVAL; + + first_run = 0; + if (handle->loop->fs_fd == -1) { + portfd = port_create(); + if (portfd == -1) + return -errno; + handle->loop->fs_fd = portfd; + first_run = 1; + } + + uv__handle_start(handle); + handle->filename = strdup(filename); + handle->fd = PORT_UNUSED; + handle->cb = cb; + + memset(&handle->fo, 0, sizeof handle->fo); + handle->fo.fo_name = handle->filename; + uv__fs_event_rearm(handle); /* FIXME(bnoordhuis) Check return code. */ + + if (first_run) { + uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN); + } + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return -EINVAL; + + if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) { + port_dissociate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo); + } + + handle->fd = PORT_DELETED; + free(handle->filename); + handle->filename = NULL; + handle->fo.fo_name = NULL; + uv__handle_stop(handle); + + return 0; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + +#else /* !defined(PORT_SOURCE_FILE) */ + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + +#endif /* defined(PORT_SOURCE_FILE) */ + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (size > 0) { + buffer[0] = '\0'; + } + return 0; +} + + +int uv_resident_set_memory(size_t* rss) { + psinfo_t psinfo; + int err; + int fd; + + fd = open("/proc/self/psinfo", O_RDONLY); + if (fd == -1) + return -errno; + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = -EINVAL; + if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { + *rss = (size_t)psinfo.pr_rssize * 1024; + err = 0; + } + uv__close(fd); + + return err; +} + + +int uv_uptime(double* uptime) { + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + long hz = sysconf(_SC_CLK_TCK); + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc"); + if (kstat_read(kc, ksp, NULL) == -1) { + *uptime = -1; + } else { + knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr"); + *uptime = knp->value.ul / hz; + } + kstat_close(kc); + + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + int lookup_instance; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + uv_cpu_info_t* cpu_info; + + kc = kstat_open(); + if (kc == NULL) + return -EPERM; + + /* Get count of cpus */ + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + lookup_instance++; + } + + *cpu_infos = malloc(lookup_instance * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + kstat_close(kc); + return -ENOMEM; + } + + *count = lookup_instance; + + cpu_info = *cpu_infos; + lookup_instance = 0; + while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) { + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->speed = 0; + cpu_info->model = NULL; + } else { + knp = kstat_data_lookup(ksp, (char*) "clock_MHz"); + assert(knp->data_type == KSTAT_DATA_INT32 || + knp->data_type == KSTAT_DATA_INT64); + cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32 + : knp->value.i64; + + knp = kstat_data_lookup(ksp, (char*) "brand"); + assert(knp->data_type == KSTAT_DATA_STRING); + cpu_info->model = strdup(KSTAT_NAMED_STR_PTR(knp)); + } + + lookup_instance++; + cpu_info++; + } + + cpu_info = *cpu_infos; + lookup_instance = 0; + for (;;) { + ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys"); + + if (ksp == NULL) + break; + + if (kstat_read(kc, ksp, NULL) == -1) { + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.nice = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + } else { + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.user = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.sys = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.idle = knp->value.ui64; + + knp = kstat_data_lookup(ksp, (char*) "intr"); + assert(knp->data_type == KSTAT_DATA_UINT64); + cpu_info->cpu_times.irq = knp->value.ui64; + cpu_info->cpu_times.nice = 0; + } + + lookup_instance++; + cpu_info++; + } + + kstat_close(kc); + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { +#ifdef SUNOS_NO_IFADDRS + return -ENOSYS; +#else + uv_interface_address_t* address; + struct sockaddr_dl* sa_addr; + struct ifaddrs* addrs; + struct ifaddrs* ent; + int i; + + if (getifaddrs(&addrs)) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family == PF_PACKET)) { + continue; + } + + (*count)++; + } + + *addresses = malloc(*count * sizeof(**addresses)); + if (!(*addresses)) + return -ENOMEM; + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + continue; + + if (ent->ifa_addr == NULL) + continue; + + address->name = strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || + (ent->ifa_flags & IFF_LOOPBACK)); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || + (ent->ifa_addr == NULL) || + (ent->ifa_addr->sa_family != AF_LINK)) { + continue; + } + + address = *addresses; + + for (i = 0; i < (*count); i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +#endif /* SUNOS_NO_IFADDRS */ +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; i++) { + free(addresses[i].name); + } + + free(addresses); +} diff --git a/src/unix/tcp.c b/src/unix/tcp.c new file mode 100644 index 0000000000..2c36dc3ffc --- /dev/null +++ b/src/unix/tcp.c @@ -0,0 +1,312 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { + uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); + return 0; +} + + +static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { + int sockfd; + int err; + + if (uv__stream_fd(handle) != -1) + return 0; + + err = uv__socket(domain, SOCK_STREAM, 0); + if (err < 0) + return err; + sockfd = err; + + err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); + if (err) { + uv__close(sockfd); + return err; + } + + return 0; +} + + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int on; + + err = maybe_new_socket(tcp, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + on = 1; + if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) + return -errno; + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + on = (flags & UV_TCP_IPV6ONLY) != 0; + if (setsockopt(tcp->io_watcher.fd, + IPPROTO_IPV6, + IPV6_V6ONLY, + &on, + sizeof on) == -1) { + return -errno; + } + } +#endif + + errno = 0; + if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) + return -errno; + + tcp->delayed_error = -errno; + return 0; +} + + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + int r; + + assert(handle->type == UV_TCP); + + if (handle->connect_req != NULL) + return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */ + + err = maybe_new_socket(handle, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + handle->delayed_error = 0; + + do + r = connect(uv__stream_fd(handle), addr, addrlen); + while (r == -1 && errno == EINTR); + + if (r == -1) { + if (errno == EINPROGRESS) + ; /* not an error */ + else if (errno == ECONNREFUSED) + /* If we get a ECONNREFUSED wait until the next tick to report the + * error. Solaris wants to report immediately--other unixes want to + * wait. + */ + handle->delayed_error = -errno; + else + return -errno; + } + + uv__req_init(handle->loop, req, UV_CONNECT); + req->cb = cb; + req->handle = (uv_stream_t*) handle; + QUEUE_INIT(&req->queue); + handle->connect_req = req; + + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + + if (handle->delayed_error) + uv__io_feed(handle->loop, &handle->io_watcher); + + return 0; +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + return uv__stream_open((uv_stream_t*)handle, + sock, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); +} + + +int uv_tcp_getsockname(uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_getpeername(uv_tcp_t* handle, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + + if (handle->delayed_error) + return handle->delayed_error; + + if (uv__stream_fd(handle) < 0) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getpeername(uv__stream_fd(handle), name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { + static int single_accept = -1; + int err; + + if (tcp->delayed_error) + return tcp->delayed_error; + + if (single_accept == -1) { + const char* val = getenv("UV_TCP_SINGLE_ACCEPT"); + single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */ + } + + if (single_accept) + tcp->flags |= UV_TCP_SINGLE_ACCEPT; + + err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE); + if (err) + return err; + + if (listen(tcp->io_watcher.fd, backlog)) + return -errno; + + tcp->connection_cb = cb; + + /* Start listening for connections. */ + tcp->io_watcher.cb = uv__server_io; + uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN); + + return 0; +} + + +int uv__tcp_nodelay(int fd, int on) { + return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); +} + + +int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) + return -errno; + +#ifdef TCP_KEEPIDLE + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return -errno; +#endif + + /* Solaris/SmartOS, if you don't support keep-alive, + * then don't advertise it in your system headers... + */ + /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ +#if defined(TCP_KEEPALIVE) && !defined(__sun) + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return -errno; +#endif + + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int on) { + int err; + + if (uv__stream_fd(handle) != -1) { + err = uv__tcp_nodelay(uv__stream_fd(handle), on); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_NODELAY; + else + handle->flags &= ~UV_TCP_NODELAY; + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { + int err; + + if (uv__stream_fd(handle) != -1) { + err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay); + if (err) + return err; + } + + if (on) + handle->flags |= UV_TCP_KEEPALIVE; + else + handle->flags &= ~UV_TCP_KEEPALIVE; + + /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge + * uv_tcp_t with an int that's almost never used... + */ + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (enable) + handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + else + handle->flags |= UV_TCP_SINGLE_ACCEPT; + return 0; +} + + +void uv__tcp_close(uv_tcp_t* handle) { + uv__stream_close((uv_stream_t*)handle); +} diff --git a/src/unix/thread.c b/src/unix/thread.c new file mode 100644 index 0000000000..f2ce082842 --- /dev/null +++ b/src/unix/thread.c @@ -0,0 +1,464 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +int uv_thread_join(uv_thread_t *tid) { + return -pthread_join(*tid, NULL); +} + + +int uv_mutex_init(uv_mutex_t* mutex) { +#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) + return -pthread_mutex_init(mutex, NULL); +#else + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return -err; +#endif +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + int err; + + /* FIXME(bnoordhuis) EAGAIN means recursive lock limit reached. Arguably + * a bug, should probably abort rather than return -EAGAIN. + */ + err = pthread_mutex_trylock(mutex); + if (err && err != EBUSY && err != EAGAIN) + abort(); + + return -err; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + return -pthread_rwlock_init(rwlock, NULL); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (pthread_rwlock_destroy(rwlock)) + abort(); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_rdlock(rwlock)) + abort(); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_tryrdlock(rwlock); + if (err && err != EBUSY && err != EAGAIN) + abort(); + + return -err; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_wrlock(rwlock)) + abort(); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + int err; + + err = pthread_rwlock_trywrlock(rwlock); + if (err && err != EBUSY && err != EAGAIN) + abort(); + + return -err; +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (pthread_rwlock_unlock(rwlock)) + abort(); +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +#if defined(__APPLE__) && defined(__MACH__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + kern_return_t err; + + err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_INVALID_ARGUMENT) + return -EINVAL; + if (err == KERN_RESOURCE_SHORTAGE) + return -ENOMEM; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (semaphore_destroy(mach_task_self(), *sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (semaphore_signal(*sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = semaphore_wait(*sem); + while (r == KERN_ABORTED); + + if (r != KERN_SUCCESS) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + mach_timespec_t interval; + kern_return_t err; + + interval.tv_sec = 0; + interval.tv_nsec = 0; + + err = semaphore_timedwait(*sem, interval); + if (err == KERN_SUCCESS) + return 0; + if (err == KERN_OPERATION_TIMED_OUT) + return -EAGAIN; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + if (sem_init(sem, 0, value)) + return -errno; + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (sem_destroy(sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (sem_post(sem)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + int r; + + do + r = sem_wait(sem); + while (r == -1 && errno == EINTR); + + if (r) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + int r; + + do + r = sem_trywait(sem); + while (r == -1 && errno == EINTR); + + if (r) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +#if defined(__APPLE__) && defined(__MACH__) + +int uv_cond_init(uv_cond_t* cond) { + return -pthread_cond_init(cond, NULL); +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_cond_init(uv_cond_t* cond) { + pthread_condattr_t attr; + int err; + + err = pthread_condattr_init(&attr); + if (err) + return -err; + +#if !defined(__ANDROID__) + err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (err) + goto error2; +#endif + + err = pthread_cond_init(cond, &attr); + if (err) + goto error2; + + err = pthread_condattr_destroy(&attr); + if (err) + goto error; + + return 0; + +error: + pthread_cond_destroy(cond); +error2: + pthread_condattr_destroy(&attr); + return -err; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +void uv_cond_destroy(uv_cond_t* cond) { + if (pthread_cond_destroy(cond)) + abort(); +} + +void uv_cond_signal(uv_cond_t* cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void uv_cond_broadcast(uv_cond_t* cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (pthread_cond_wait(cond, mutex)) + abort(); +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if defined(__APPLE__) && defined(__MACH__) + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + timeout += uv__hrtime(UV_CLOCK_PRECISE); + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID__) + /* + * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, + * but has this alternative function instead. + */ + r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif /* __ANDROID__ */ +#endif + + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -ETIMEDOUT; + + abort(); + return -EINVAL; /* Satisfy the compiler. */ +} + + +#if defined(__APPLE__) && defined(__MACH__) + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + int err; + + barrier->n = count; + barrier->count = 0; + + err = uv_mutex_init(&barrier->mutex); + if (err) + return -err; + + err = uv_sem_init(&barrier->turnstile1, 0); + if (err) + goto error2; + + err = uv_sem_init(&barrier->turnstile2, 1); + if (err) + goto error; + + return 0; + +error: + uv_sem_destroy(&barrier->turnstile1); +error2: + uv_mutex_destroy(&barrier->mutex); + return -err; + +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + uv_sem_destroy(&barrier->turnstile2); + uv_sem_destroy(&barrier->turnstile1); + uv_mutex_destroy(&barrier->mutex); +} + + +void uv_barrier_wait(uv_barrier_t* barrier) { + uv_mutex_lock(&barrier->mutex); + if (++barrier->count == barrier->n) { + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile1); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile1); + + uv_mutex_lock(&barrier->mutex); + if (--barrier->count == 0) { + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile2); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile2); +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return -pthread_barrier_init(barrier, NULL, count); +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + + +void uv_barrier_wait(uv_barrier_t* barrier) { + int r = pthread_barrier_wait(barrier); + if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +int uv_key_create(uv_key_t* key) { + return -pthread_key_create(key, NULL); +} + + +void uv_key_delete(uv_key_t* key) { + if (pthread_key_delete(*key)) + abort(); +} + + +void* uv_key_get(uv_key_t* key) { + return pthread_getspecific(*key); +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (pthread_setspecific(*key, value)) + abort(); +} diff --git a/src/unix/threadpool.c b/src/unix/threadpool.c new file mode 100644 index 0000000000..7923250a09 --- /dev/null +++ b/src/unix/threadpool.c @@ -0,0 +1,280 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "internal.h" +#include + +#define MAX_THREADPOOL_SIZE 128 + +static uv_once_t once = UV_ONCE_INIT; +static uv_cond_t cond; +static uv_mutex_t mutex; +static unsigned int nthreads; +static uv_thread_t* threads; +static uv_thread_t default_threads[4]; +static QUEUE exit_message; +static QUEUE wq; +static volatile int initialized; + + +static void uv__cancelled(struct uv__work* w) { + abort(); +} + + +/* To avoid deadlock with uv_cancel() it's crucial that the worker + * never holds the global mutex and the loop-local mutex at the same time. + */ +static void worker(void* arg) { + struct uv__work* w; + QUEUE* q; + + (void) arg; + + for (;;) { + uv_mutex_lock(&mutex); + + while (QUEUE_EMPTY(&wq)) + uv_cond_wait(&cond, &mutex); + + q = QUEUE_HEAD(&wq); + + if (q == &exit_message) + uv_cond_signal(&cond); + else { + QUEUE_REMOVE(q); + QUEUE_INIT(q); /* Signal uv_cancel() that the work req is + executing. */ + } + + uv_mutex_unlock(&mutex); + + if (q == &exit_message) + break; + + w = QUEUE_DATA(q, struct uv__work, wq); + w->work(w); + + uv_mutex_lock(&w->loop->wq_mutex); + w->work = NULL; /* Signal uv_cancel() that the work req is done + executing. */ + QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); + uv_async_send(&w->loop->wq_async); + uv_mutex_unlock(&w->loop->wq_mutex); + } +} + + +static void post(QUEUE* q) { + uv_mutex_lock(&mutex); + QUEUE_INSERT_TAIL(&wq, q); + uv_cond_signal(&cond); + uv_mutex_unlock(&mutex); +} + + +static void init_once(void) { + unsigned int i; + const char* val; + + nthreads = ARRAY_SIZE(default_threads); + val = getenv("UV_THREADPOOL_SIZE"); + if (val != NULL) + nthreads = atoi(val); + if (nthreads == 0) + nthreads = 1; + if (nthreads > MAX_THREADPOOL_SIZE) + nthreads = MAX_THREADPOOL_SIZE; + + threads = default_threads; + if (nthreads > ARRAY_SIZE(default_threads)) { + threads = malloc(nthreads * sizeof(threads[0])); + if (threads == NULL) { + nthreads = ARRAY_SIZE(default_threads); + threads = default_threads; + } + } + + if (uv_cond_init(&cond)) + abort(); + + if (uv_mutex_init(&mutex)) + abort(); + + QUEUE_INIT(&wq); + + for (i = 0; i < nthreads; i++) + if (uv_thread_create(threads + i, worker, NULL)) + abort(); + + initialized = 1; +} + + +UV_DESTRUCTOR(static void cleanup(void)) { + unsigned int i; + + if (initialized == 0) + return; + + post(&exit_message); + + for (i = 0; i < nthreads; i++) + if (uv_thread_join(threads + i)) + abort(); + + if (threads != default_threads) + free(threads); + + uv_mutex_destroy(&mutex); + uv_cond_destroy(&cond); + + threads = NULL; + nthreads = 0; + initialized = 0; +} + + +void uv__work_submit(uv_loop_t* loop, + struct uv__work* w, + void (*work)(struct uv__work* w), + void (*done)(struct uv__work* w, int status)) { + uv_once(&once, init_once); + w->loop = loop; + w->work = work; + w->done = done; + post(&w->wq); +} + + +static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { + int cancelled; + + uv_mutex_lock(&mutex); + uv_mutex_lock(&w->loop->wq_mutex); + + cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL; + if (cancelled) + QUEUE_REMOVE(&w->wq); + + uv_mutex_unlock(&w->loop->wq_mutex); + uv_mutex_unlock(&mutex); + + if (!cancelled) + return -EBUSY; + + w->work = uv__cancelled; + uv_mutex_lock(&loop->wq_mutex); + QUEUE_INSERT_TAIL(&loop->wq, &w->wq); + uv_async_send(&loop->wq_async); + uv_mutex_unlock(&loop->wq_mutex); + + return 0; +} + + +void uv__work_done(uv_async_t* handle, int status) { + struct uv__work* w; + uv_loop_t* loop; + QUEUE* q; + QUEUE wq; + int err; + + loop = container_of(handle, uv_loop_t, wq_async); + QUEUE_INIT(&wq); + + uv_mutex_lock(&loop->wq_mutex); + if (!QUEUE_EMPTY(&loop->wq)) { + q = QUEUE_HEAD(&loop->wq); + QUEUE_SPLIT(&loop->wq, q, &wq); + } + uv_mutex_unlock(&loop->wq_mutex); + + while (!QUEUE_EMPTY(&wq)) { + q = QUEUE_HEAD(&wq); + QUEUE_REMOVE(q); + + w = container_of(q, struct uv__work, wq); + err = (w->work == uv__cancelled) ? -ECANCELED : 0; + w->done(w, err); + } +} + + +static void uv__queue_work(struct uv__work* w) { + uv_work_t* req = container_of(w, uv_work_t, work_req); + + req->work_cb(req); +} + + +static void uv__queue_done(struct uv__work* w, int err) { + uv_work_t* req; + + req = container_of(w, uv_work_t, work_req); + uv__req_unregister(req->loop, req); + + if (req->after_work_cb == NULL) + return; + + req->after_work_cb(req, err); +} + + +int uv_queue_work(uv_loop_t* loop, + uv_work_t* req, + uv_work_cb work_cb, + uv_after_work_cb after_work_cb) { + if (work_cb == NULL) + return -EINVAL; + + uv__req_init(loop, req, UV_WORK); + req->loop = loop; + req->work_cb = work_cb; + req->after_work_cb = after_work_cb; + uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done); + return 0; +} + + +int uv_cancel(uv_req_t* req) { + struct uv__work* wreq; + uv_loop_t* loop; + + switch (req->type) { + case UV_FS: + loop = ((uv_fs_t*) req)->loop; + wreq = &((uv_fs_t*) req)->work_req; + break; + case UV_GETADDRINFO: + loop = ((uv_getaddrinfo_t*) req)->loop; + wreq = &((uv_getaddrinfo_t*) req)->work_req; + break; + case UV_WORK: + loop = ((uv_work_t*) req)->loop; + wreq = &((uv_work_t*) req)->work_req; + break; + default: + return -EINVAL; + } + + return uv__work_cancel(loop, req, wreq); +} diff --git a/src/unix/timer.c b/src/unix/timer.c new file mode 100644 index 0000000000..240efad503 --- /dev/null +++ b/src/unix/timer.c @@ -0,0 +1,153 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" +#include +#include + + +static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) { + if (a->timeout < b->timeout) + return -1; + if (a->timeout > b->timeout) + return 1; + /* + * compare start_id when both has the same timeout. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return -1; + if (a->start_id > b->start_id) + return 1; + return 0; +} + + +RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp) + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + + return 0; +} + + +int uv_timer_start(uv_timer_t* handle, + uv_timer_cb cb, + uint64_t timeout, + uint64_t repeat) { + uint64_t clamped_timeout; + + if (uv__is_active(handle)) + uv_timer_stop(handle); + + clamped_timeout = handle->loop->time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + handle->timer_cb = cb; + handle->timeout = clamped_timeout; + handle->repeat = repeat; + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + RB_INSERT(uv__timers, &handle->loop->timer_handles, handle); + uv__handle_start(handle); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + if (!uv__is_active(handle)) + return 0; + + RB_REMOVE(uv__timers, &handle->loop->timer_handles, handle); + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + if (handle->timer_cb == NULL) + return -EINVAL; + + if (handle->repeat) { + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + return handle->repeat; +} + + +int uv__next_timeout(const uv_loop_t* loop) { + const uv_timer_t* handle; + uint64_t diff; + + /* RB_MIN expects a non-const tree root. That's okay, it doesn't modify it. */ + handle = RB_MIN(uv__timers, (struct uv__timers*) &loop->timer_handles); + + if (handle == NULL) + return -1; /* block indefinitely */ + + if (handle->timeout <= loop->time) + return 0; + + diff = handle->timeout - loop->time; + if (diff > INT_MAX) + diff = INT_MAX; + + return diff; +} + + +void uv__run_timers(uv_loop_t* loop) { + uv_timer_t* handle; + + while ((handle = RB_MIN(uv__timers, &loop->timer_handles))) { + if (handle->timeout > loop->time) + break; + + uv_timer_stop(handle); + uv_timer_again(handle); + handle->timer_cb(handle, 0); + } +} + + +void uv__timer_close(uv_timer_t* handle) { + uv_timer_stop(handle); +} diff --git a/src/unix/tty.c b/src/unix/tty.c new file mode 100644 index 0000000000..ca9459dd0d --- /dev/null +++ b/src/unix/tty.c @@ -0,0 +1,184 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" +#include "spinlock.h" + +#include +#include +#include +#include +#include + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { + uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); + +#if defined(__APPLE__) + { + int err = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (err) + return err; + } +#endif /* defined(__APPLE__) */ + + if (readable) { + uv__nonblock(fd, 1); + uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); + } else { + /* Note: writable tty we set to blocking mode. */ + uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE); + tty->flags |= UV_STREAM_BLOCKING; + } + + tty->mode = 0; + return 0; +} + + +int uv_tty_set_mode(uv_tty_t* tty, int mode) { + struct termios raw; + int fd; + + fd = uv__stream_fd(tty); + + if (mode && tty->mode == 0) { /* on */ + if (tcgetattr(fd, &tty->orig_termios)) + return -errno; + + /* This is used for uv_tty_reset_mode() */ + uv_spinlock_lock(&termios_spinlock); + if (orig_termios_fd == -1) { + orig_termios = tty->orig_termios; + orig_termios_fd = fd; + } + uv_spinlock_unlock(&termios_spinlock); + + raw = tty->orig_termios; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag |= (ONLCR); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + raw.c_cc[VMIN] = 1; + raw.c_cc[VTIME] = 0; + + /* Put terminal in raw mode after draining */ + if (tcsetattr(fd, TCSADRAIN, &raw)) + return -errno; + + tty->mode = 1; + } else if (mode == 0 && tty->mode) { /* off */ + /* Put terminal in original mode after flushing */ + if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) + return -errno; + tty->mode = 0; + } + + return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + struct winsize ws; + + if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws)) + return -errno; + + *width = ws.ws_col; + *height = ws.ws_row; + + return 0; +} + + +uv_handle_type uv_guess_handle(uv_file file) { + struct sockaddr sa; + struct stat s; + socklen_t len; + int type; + + if (file < 0) + return UV_UNKNOWN_HANDLE; + + if (isatty(file)) + return UV_TTY; + + if (fstat(file, &s)) + return UV_UNKNOWN_HANDLE; + + if (S_ISREG(s.st_mode)) + return UV_FILE; + + if (S_ISCHR(s.st_mode)) + return UV_FILE; /* XXX UV_NAMED_PIPE? */ + + if (S_ISFIFO(s.st_mode)) + return UV_NAMED_PIPE; + + if (!S_ISSOCK(s.st_mode)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(type); + if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(sa); + if (getsockname(file, &sa, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_DGRAM) + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_UDP; + + if (type == SOCK_STREAM) { + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_TCP; + if (sa.sa_family == AF_UNIX) + return UV_NAMED_PIPE; + } + + return UV_UNKNOWN_HANDLE; +} + + +/* This function is async signal-safe, meaning that it's safe to call from + * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s + * critical section when the signal was raised. + */ +int uv_tty_reset_mode(void) { + int err; + + if (!uv_spinlock_trylock(&termios_spinlock)) + return -EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = -errno; + + uv_spinlock_unlock(&termios_spinlock); + return err; +} diff --git a/src/unix/udp.c b/src/unix/udp.c new file mode 100644 index 0000000000..a2b3dc3298 --- /dev/null +++ b/src/unix/udp.c @@ -0,0 +1,595 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + + +static void uv__udp_run_completed(uv_udp_t* handle); +static void uv__udp_run_pending(uv_udp_t* handle); +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); +static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); +static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain); + + +void uv__udp_close(uv_udp_t* handle) { + uv__io_close(handle->loop, &handle->io_watcher); + uv__handle_stop(handle); + + if (handle->io_watcher.fd != -1) { + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + } +} + + +void uv__udp_finish_close(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(handle->io_watcher.fd == -1); + + uv__udp_run_completed(handle); + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + + if (req->send_cb != NULL) + req->send_cb(req, -ECANCELED); + } + + /* Now tear down the handle. */ + handle->recv_cb = NULL; + handle->alloc_cb = NULL; + /* but _do not_ touch close_cb */ +} + + +static void uv__udp_run_pending(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + struct msghdr h; + ssize_t size; + + while (!QUEUE_EMPTY(&handle->write_queue)) { + q = QUEUE_HEAD(&handle->write_queue); + assert(q != NULL); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + assert(req != NULL); + + memset(&h, 0, sizeof h); + h.msg_name = &req->addr; + h.msg_namelen = (req->addr.sin6_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + h.msg_iov = (struct iovec*) req->bufs; + h.msg_iovlen = req->nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } + while (size == -1 && errno == EINTR); + + /* TODO try to write once or twice more in the + * hope that the socket becomes readable again? + */ + if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + break; + + req->status = (size == -1 ? -errno : size); + + /* Sending a datagram is an atomic operation: either all data + * is written or nothing is (and EMSGSIZE is raised). That is + * why we don't handle partial writes. Just pop the request + * off the write queue and onto the completed queue, done. + */ + QUEUE_REMOVE(&req->queue); + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } +} + + +static void uv__udp_run_completed(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + + while (!QUEUE_EMPTY(&handle->write_completed_queue)) { + q = QUEUE_HEAD(&handle->write_completed_queue); + QUEUE_REMOVE(q); + + req = QUEUE_DATA(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + + if (req->send_cb == NULL) + continue; + + /* req->status >= 0 == bytes written + * req->status < 0 == errno + */ + if (req->status >= 0) + req->send_cb(req, 0); + else + req->send_cb(req, req->status); + } +} + + +static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { + if (revents & UV__POLLIN) + uv__udp_recvmsg(loop, w, revents); + + if (revents & UV__POLLOUT) + uv__udp_sendmsg(loop, w, revents); +} + + +static void uv__udp_recvmsg(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents) { + struct sockaddr_storage peer; + struct msghdr h; + uv_udp_t* handle; + ssize_t nread; + uv_buf_t buf; + int flags; + int count; + + handle = container_of(w, uv_udp_t, io_watcher); + assert(handle->type == UV_UDP); + assert(revents & UV__POLLIN); + + assert(handle->recv_cb != NULL); + assert(handle->alloc_cb != NULL); + + /* Prevent loop starvation when the data comes in as fast as (or faster than) + * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. + */ + count = 32; + + memset(&h, 0, sizeof(h)); + h.msg_name = &peer; + + do { + handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + if (buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + return; + } + assert(buf.base != NULL); + + h.msg_namelen = sizeof(peer); + h.msg_iov = (void*) &buf; + h.msg_iovlen = 1; + + do { + nread = recvmsg(handle->io_watcher.fd, &h, 0); + } + while (nread == -1 && errno == EINTR); + + if (nread == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + handle->recv_cb(handle, 0, &buf, NULL, 0); + else + handle->recv_cb(handle, -errno, &buf, NULL, 0); + } + else { + flags = 0; + + if (h.msg_flags & MSG_TRUNC) + flags |= UV_UDP_PARTIAL; + + handle->recv_cb(handle, + nread, + &buf, + (const struct sockaddr*) &peer, + flags); + } + } + /* recv_cb callback may decide to pause or close the handle */ + while (nread != -1 + && count-- > 0 + && handle->io_watcher.fd != -1 + && handle->recv_cb != NULL); +} + + +static void uv__udp_sendmsg(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents) { + uv_udp_t* handle; + + handle = container_of(w, uv_udp_t, io_watcher); + assert(handle->type == UV_UDP); + assert(revents & UV__POLLOUT); + + assert(!QUEUE_EMPTY(&handle->write_queue) + || !QUEUE_EMPTY(&handle->write_completed_queue)); + + /* Write out pending data first. */ + uv__udp_run_pending(handle); + + /* Drain 'request completed' queue. */ + uv__udp_run_completed(handle); + + if (!QUEUE_EMPTY(&handle->write_completed_queue)) { + /* Schedule completion callbacks. */ + uv__io_feed(handle->loop, &handle->io_watcher); + } + else if (QUEUE_EMPTY(&handle->write_queue)) { + /* Pending queue and completion queue empty, stop watcher. */ + uv__io_stop(loop, &handle->io_watcher, UV__POLLOUT); + + if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) + uv__handle_stop(handle); + } +} + + +/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional + * refinements for programs that use multicast. + * + * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that + * are different from the BSDs: it _shares_ the port rather than steal it + * from the current listener. While useful, it's not something we can emulate + * on other platforms so we don't enable it. + */ +static int uv__set_reuse(int fd) { + int yes; + +#if defined(SO_REUSEPORT) && !defined(__linux__) + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) + return -errno; +#else + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return -errno; +#endif + + return 0; +} + + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + int yes; + int fd; + + err = -EINVAL; + fd = -1; + + /* Check for bad flags. */ + if (flags & ~UV_UDP_IPV6ONLY) + return -EINVAL; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) + return -EINVAL; + + fd = handle->io_watcher.fd; + if (fd == -1) { + fd = uv__socket(addr->sa_family, SOCK_DGRAM, 0); + if (fd == -1) + return -errno; + handle->io_watcher.fd = fd; + } + + err = uv__set_reuse(fd); + if (err) + goto out; + + if (flags & UV_UDP_IPV6ONLY) { +#ifdef IPV6_V6ONLY + yes = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { + err = -errno; + goto out; + } +#else + err = -ENOTSUP; + goto out; +#endif + } + + if (bind(fd, addr, addrlen)) { + err = -errno; + goto out; + } + + return 0; + +out: + uv__close(handle->io_watcher.fd); + handle->io_watcher.fd = -1; + return err; +} + + +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain) { + unsigned char taddr[sizeof(struct sockaddr_in6)]; + socklen_t addrlen; + + assert(domain == AF_INET || domain == AF_INET6); + + if (handle->io_watcher.fd != -1) + return 0; + + switch (domain) { + case AF_INET: + { + struct sockaddr_in* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = INADDR_ANY; + addrlen = sizeof *addr; + break; + } + case AF_INET6: + { + struct sockaddr_in6* addr = (void*)&taddr; + memset(addr, 0, sizeof *addr); + addr->sin6_family = AF_INET6; + addr->sin6_addr = in6addr_any; + addrlen = sizeof *addr; + break; + } + default: + assert(0 && "unsupported address family"); + abort(); + } + + return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, 0); +} + + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + int err; + + assert(nbufs > 0); + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family); + if (err) + return err; + + uv__req_init(handle->loop, req, UV_UDP_SEND); + + assert(addrlen <= sizeof(req->addr)); + memcpy(&req->addr, addr, addrlen); + req->send_cb = send_cb; + req->handle = handle; + req->nbufs = nbufs; + + req->bufs = req->bufsml; + if (nbufs > ARRAY_SIZE(req->bufsml)) + req->bufs = malloc(nbufs * sizeof(bufs[0])); + + if (req->bufs == NULL) + return -ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__handle_start(handle); + + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + uv__io_init(&handle->io_watcher, uv__udp_io, -1); + QUEUE_INIT(&handle->write_queue); + QUEUE_INIT(&handle->write_completed_queue); + return 0; +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + int err; + + /* Check for already active socket. */ + if (handle->io_watcher.fd != -1) + return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + + err = uv__set_reuse(sock); + if (err) + return err; + + handle->io_watcher.fd = sock; + return 0; +} + + +int uv_udp_set_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + uv_membership membership) { + struct ip_mreq mreq; + int optname; + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + mreq.imr_interface.s_addr = inet_addr(interface_addr); + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr); + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return -EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { + return -errno; + } + + return 0; +} + + +static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { +#if defined(__sun) + char arg = val; +#else + int arg = val; +#endif + + if (val < 0 || val > 255) + return -EINVAL; + + if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, option, &arg, sizeof(arg))) + return -errno; + + return 0; +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int on) { + if (setsockopt(handle->io_watcher.fd, + SOL_SOCKET, + SO_BROADCAST, + &on, + sizeof(on))) { + return -errno; + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (ttl < 1 || ttl > 255) + return -EINVAL; + + if (setsockopt(handle->io_watcher.fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) + return -errno; + + return 0; +} + + +int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { + return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, ttl); +} + + +int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { + return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on); +} + + +int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { + socklen_t socklen; + + if (handle->io_watcher.fd == -1) + return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(handle->io_watcher.fd, name, &socklen)) + return -errno; + + *namelen = (int) socklen; + return 0; +} + + +int uv__udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + int err; + + if (alloc_cb == NULL || recv_cb == NULL) + return -EINVAL; + + if (uv__io_active(&handle->io_watcher, UV__POLLIN)) + return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + + err = uv__udp_maybe_deferred_bind(handle, AF_INET); + if (err) + return err; + + handle->alloc_cb = alloc_cb; + handle->recv_cb = recv_cb; + + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__handle_start(handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN); + + if (!uv__io_active(&handle->io_watcher, UV__POLLOUT)) + uv__handle_stop(handle); + + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + + return 0; +} diff --git a/src/unix/uv-dtrace.d b/src/unix/uv-dtrace.d new file mode 100644 index 0000000000..7848450c94 --- /dev/null +++ b/src/unix/uv-dtrace.d @@ -0,0 +1,25 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +provider uv { + probe tick__start(void* loop, int mode); + probe tick__stop(void* loop, int mode); +}; diff --git a/src/uv-common.c b/src/uv-common.c new file mode 100644 index 0000000000..e5fc507756 --- /dev/null +++ b/src/uv-common.c @@ -0,0 +1,446 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Expose glibc-specific EAI_* error codes. Needs to be defined before we + * include any headers. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include "uv.h" +#include "uv-common.h" + +#include +#include +#include /* NULL */ +#include /* malloc */ +#include /* memset */ + +#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) && !defined(_WIN32) +# include /* if_nametoindex */ +#endif + +/* EAI_* constants. */ +#if !defined(_WIN32) +# include +# include +# include +#endif + +#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); + +size_t uv_handle_size(uv_handle_type type) { + switch (type) { + UV_HANDLE_TYPE_MAP(XX) + default: + return -1; + } +} + +size_t uv_req_size(uv_req_type type) { + switch(type) { + UV_REQ_TYPE_MAP(XX) + default: + return -1; + } +} + +#undef XX + + +uv_buf_t uv_buf_init(char* base, unsigned int len) { + uv_buf_t buf; + buf.base = base; + buf.len = len; + return buf; +} + + +#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; +const char* uv_err_name(int err) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN) + default: + assert(0); + return NULL; + } +} +#undef UV_ERR_NAME_GEN + + +#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; +const char* uv_strerror(int err) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN) + default: + return "Unknown system error"; + } +} +#undef UV_STRERROR_GEN + + +int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) { + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr)); +} + + +int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) { +#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) + char address_part[40]; + size_t address_part_size; + const char* zone_index; +#endif + + memset(addr, 0, sizeof(*addr)); + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(port); + +#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) + zone_index = strchr(ip, '%'); + if (zone_index != NULL) { + address_part_size = zone_index - ip; + if (address_part_size >= sizeof(address_part)) + address_part_size = sizeof(address_part) - 1; + + memcpy(address_part, ip, address_part_size); + address_part[address_part_size] = '\0'; + ip = address_part; + + zone_index++; /* skip '%' */ + /* NOTE: unknown interface (id=0) is silently ignored */ +#ifdef _WIN32 + addr->sin6_scope_id = atoi(zone_index); +#else + addr->sin6_scope_id = if_nametoindex(zone_index); +#endif + } +#endif + + return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr); +} + + +int uv_ip4_name(struct sockaddr_in* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size); +} + + +int uv_ip6_name(struct sockaddr_in6* src, char* dst, size_t size) { + return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); +} + + +int uv_tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_bind(handle, addr, addrlen, flags); +} + + +int uv_udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int flags) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_bind(handle, addr, addrlen, flags); +} + + +int uv_tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + uv_connect_cb cb) { + unsigned int addrlen; + + if (handle->type != UV_TCP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__tcp_connect(req, handle, addr, addrlen, cb); +} + + +int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + + return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb); +} + + +int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) + return UV_EINVAL; + else + return uv__udp_recv_start(handle, alloc_cb, recv_cb); +} + + +int uv_udp_recv_stop(uv_udp_t* handle) { + if (handle->type != UV_UDP) + return UV_EINVAL; + else + return uv__udp_recv_stop(handle); +} + + +struct thread_ctx { + void (*entry)(void* arg); + void* arg; +}; + + +#ifdef _WIN32 +static UINT __stdcall uv__thread_start(void* arg) +#else +static void* uv__thread_start(void *arg) +#endif +{ + struct thread_ctx *ctx_p; + struct thread_ctx ctx; + + ctx_p = arg; + ctx = *ctx_p; + free(ctx_p); + ctx.entry(ctx.arg); + + return 0; +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + struct thread_ctx* ctx; + int err; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return UV_ENOMEM; + + ctx->entry = entry; + ctx->arg = arg; + +#ifdef _WIN32 + *tid = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, ctx, 0, NULL); + err = *tid ? 0 : errno; +#else + err = pthread_create(tid, NULL, uv__thread_start, ctx); +#endif + + if (err) + free(ctx); + + return err ? -1 : 0; +} + + +unsigned long uv_thread_self(void) { +#ifdef _WIN32 + return (unsigned long) GetCurrentThreadId(); +#else + return (unsigned long) pthread_self(); +#endif +} + + +void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { + QUEUE* q; + uv_handle_t* h; + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + if (h->flags & UV__HANDLE_INTERNAL) continue; + walk_cb(h, arg); + } +} + + +#ifndef NDEBUG +static void uv__print_handles(uv_loop_t* loop, int only_active) { + const char* type; + QUEUE* q; + uv_handle_t* h; + + if (loop == NULL) + loop = uv_default_loop(); + + QUEUE_FOREACH(q, &loop->handle_queue) { + h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + if (only_active && !uv__is_active(h)) + continue; + + switch (h->type) { +#define X(uc, lc) case UV_##uc: type = #lc; break; + UV_HANDLE_TYPE_MAP(X) +#undef X + default: type = ""; + } + + fprintf(stderr, + "[%c%c%c] %-8s %p\n", + "R-"[!(h->flags & UV__HANDLE_REF)], + "A-"[!(h->flags & UV__HANDLE_ACTIVE)], + "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + type, + (void*)h); + } +} + + +void uv_print_all_handles(uv_loop_t* loop) { + uv__print_handles(loop, 0); +} + + +void uv_print_active_handles(uv_loop_t* loop) { + uv__print_handles(loop, 1); +} +#endif + + +void uv_ref(uv_handle_t* handle) { + uv__handle_ref(handle); +} + + +void uv_unref(uv_handle_t* handle) { + uv__handle_unref(handle); +} + + +int uv_has_ref(const uv_handle_t* handle) { + return uv__has_ref(handle); +} + + +void uv_stop(uv_loop_t* loop) { + loop->stop_flag = 1; +} + + +uint64_t uv_now(uv_loop_t* loop) { + return loop->time; +} + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; +#endif +#if defined(EAI_AGAIN) + case EAI_AGAIN: return UV_EAI_AGAIN; +#endif +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: return UV_EAI_BADFLAGS; +#endif +#if defined(EAI_BADHINTS) + case EAI_BADHINTS: return UV_EAI_BADHINTS; +#endif +#if defined(EAI_CANCELED) + case EAI_CANCELED: return UV_EAI_CANCELED; +#endif +#if defined(EAI_FAIL) + case EAI_FAIL: return UV_EAI_FAIL; +#endif +#if defined(EAI_FAMILY) + case EAI_FAMILY: return UV_EAI_FAMILY; +#endif +#if defined(EAI_MEMORY) + case EAI_MEMORY: return UV_EAI_MEMORY; +#endif +#if defined(EAI_NODATA) + case EAI_NODATA: return UV_EAI_NODATA; +#endif +#if defined(EAI_NONAME) +# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME + case EAI_NONAME: return UV_EAI_NONAME; +# endif +#endif +#if defined(EAI_OVERFLOW) + case EAI_OVERFLOW: return UV_EAI_OVERFLOW; +#endif +#if defined(EAI_PROTOCOL) + case EAI_PROTOCOL: return UV_EAI_PROTOCOL; +#endif +#if defined(EAI_SERVICE) + case EAI_SERVICE: return UV_EAI_SERVICE; +#endif +#if defined(EAI_SOCKTYPE) + case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; +#endif +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: return UV_EAI_SYSTEM; +#endif + } + assert(!"unknown EAI_* error code"); + abort(); + return 0; /* Pacify compiler. */ +} diff --git a/src/uv-common.h b/src/uv-common.h new file mode 100644 index 0000000000..3bcdcef3d4 --- /dev/null +++ b/src/uv-common.h @@ -0,0 +1,187 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * This file is private to libuv. It provides common functionality to both + * Windows and Unix backends. + */ + +#ifndef UV_COMMON_H_ +#define UV_COMMON_H_ + +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "tree.h" +#include "queue.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +#ifndef _WIN32 +enum { + UV__HANDLE_INTERNAL = 0x8000, + UV__HANDLE_ACTIVE = 0x4000, + UV__HANDLE_REF = 0x2000, + UV__HANDLE_CLOSING = 0 /* no-op on unix */ +}; +#else +# define UV__HANDLE_INTERNAL 0x80 +# define UV__HANDLE_ACTIVE 0x40 +# define UV__HANDLE_REF 0x20 +# define UV__HANDLE_CLOSING 0x01 +#endif + +int uv__tcp_bind(uv_tcp_t* tcp, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb); + +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags); + +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb); + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, + uv_udp_recv_cb recv_cb); + +int uv__udp_recv_stop(uv_udp_t* handle); + +void uv__fs_poll_close(uv_fs_poll_t* handle); + +int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ + +#define uv__has_active_reqs(loop) \ + (QUEUE_EMPTY(&(loop)->active_reqs) == 0) + +#define uv__req_register(loop, req) \ + do { \ + QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \ + } \ + while (0) + +#define uv__req_unregister(loop, req) \ + do { \ + assert(uv__has_active_reqs(loop)); \ + QUEUE_REMOVE(&(req)->active_queue); \ + } \ + while (0) + +#define uv__has_active_handles(loop) \ + ((loop)->active_handles > 0) + +#define uv__active_handle_add(h) \ + do { \ + (h)->loop->active_handles++; \ + } \ + while (0) + +#define uv__active_handle_rm(h) \ + do { \ + (h)->loop->active_handles--; \ + } \ + while (0) + +#define uv__is_active(h) \ + (((h)->flags & UV__HANDLE_ACTIVE) != 0) + +#define uv__is_closing(h) \ + (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + +#define uv__handle_start(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_stop(h) \ + do { \ + assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ + if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV__HANDLE_ACTIVE; \ + if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__handle_ref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) != 0) break; \ + (h)->flags |= UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_unref(h) \ + do { \ + if (((h)->flags & UV__HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV__HANDLE_REF; \ + if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__has_ref(h) \ + (((h)->flags & UV__HANDLE_REF) != 0) + +#if defined(_WIN32) +# define uv__handle_platform_init(h) +#else +# define uv__handle_platform_init(h) ((h)->next_closing = NULL) +#endif + +#define uv__handle_init(loop_, h, type_) \ + do { \ + (h)->loop = (loop_); \ + (h)->type = (type_); \ + (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \ + QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ + uv__handle_platform_init(h); \ + } \ + while (0) + +#endif /* UV_COMMON_H_ */ diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000000..0636348dae --- /dev/null +++ b/src/version.c @@ -0,0 +1,63 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" + + /* + * Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI + * stable. When the minor version is odd, the API can change between patch + * releases. Make sure you update the -soname directives in config-unix.mk + * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * not UV_VERSION_PATCH.) + */ + +#define UV_VERSION_MAJOR 0 +#define UV_VERSION_MINOR 11 +#define UV_VERSION_PATCH 19 +#define UV_VERSION_IS_RELEASE 1 + + +#define UV_VERSION ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) + +#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v) +#define UV_STRINGIFY_HELPER(v) #v + +#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \ + UV_STRINGIFY(UV_VERSION_MINOR) "." \ + UV_STRINGIFY(UV_VERSION_PATCH) + +#if UV_VERSION_IS_RELEASE +# define UV_VERSION_STRING UV_VERSION_STRING_BASE +#else +# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-pre" +#endif + + +unsigned int uv_version(void) { + return UV_VERSION; +} + + +const char* uv_version_string(void) { + return UV_VERSION_STRING; +} diff --git a/src/win/async.c b/src/win/async.c new file mode 100644 index 0000000000..e192ead90d --- /dev/null +++ b/src/win/async.c @@ -0,0 +1,99 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "atomicops-inl.h" +#include "handle-inl.h" +#include "req-inl.h" + + +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + !handle->async_sent) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC); + handle->async_sent = 0; + handle->async_cb = async_cb; + + req = &handle->async_req; + uv_req_init(loop, req); + req->type = UV_WAKEUP; + req->data = handle; + + uv__handle_start(handle); + + return 0; +} + + +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_closing(handle); +} + + +int uv_async_send(uv_async_t* handle) { + uv_loop_t* loop = handle->loop; + + if (handle->type != UV_ASYNC) { + /* Can't set errno because that's not thread-safe. */ + return -1; + } + + /* The user should make sure never to call uv_async_send to a closing */ + /* or closed handle. */ + assert(!(handle->flags & UV__HANDLE_CLOSING)); + + if (!uv__atomic_exchange_set(&handle->async_sent)) { + POST_COMPLETION_FOR_REQ(loop, &handle->async_req); + } + + return 0; +} + + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req) { + assert(handle->type == UV_ASYNC); + assert(req->type == UV_WAKEUP); + + handle->async_sent = 0; + + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (handle->async_cb != NULL) { + handle->async_cb(handle, 0); + } +} diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h new file mode 100644 index 0000000000..61e006026c --- /dev/null +++ b/src/win/atomicops-inl.h @@ -0,0 +1,56 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_ATOMICOPS_INL_H_ +#define UV_WIN_ATOMICOPS_INL_H_ + +#include "uv.h" + + +/* Atomic set operation on char */ +#ifdef _MSC_VER /* MSVC */ + +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ +/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ +/* exist, and interlocked operations on larger targets might require the */ +/* target to be aligned. */ +#pragma intrinsic(_InterlockedOr8) + +static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC */ + +/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ +static inline char uv__atomic_exchange_set(char volatile* target) { + const char one = 1; + char old_value; + __asm__ __volatile__ ("lock xchgb %0, %1\n\t" + : "=r"(old_value), "=m"(*target) + : "0"(one), "m"(*target) + : "memory"); + return old_value; +} + +#endif + +#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/src/win/core.c b/src/win/core.c new file mode 100644 index 0000000000..e1a77655ac --- /dev/null +++ b/src/win/core.c @@ -0,0 +1,362 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +/* The only event loop we support right now */ +static uv_loop_t uv_default_loop_; + +/* uv_once intialization guards */ +static uv_once_t uv_init_guard_ = UV_ONCE_INIT; +static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT; + + +#ifdef _DEBUG +/* Our crt debug report handler allows us to temporarily disable asserts */ +/* just for the current thread. */ + +__declspec( thread ) int uv__crt_assert_enabled = TRUE; + +static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) { + if (uv__crt_assert_enabled || report_type != _CRT_ASSERT) + return FALSE; + + if (ret_val) { + /* Set ret_val to 0 to continue with normal execution. */ + /* Set ret_val to 1 to trigger a breakpoint. */ + + if(IsDebuggerPresent()) + *ret_val = 1; + else + *ret_val = 0; + } + + /* Don't call _CrtDbgReport. */ + return TRUE; +} +#endif + + +static void uv__crt_invalid_parameter_handler(const wchar_t* expression, + const wchar_t* function, const wchar_t * file, unsigned int line, + uintptr_t reserved) { + /* No-op. */ +} + + +static void uv_init(void) { + /* Tell Windows that we will handle critical errors. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + + /* Tell the CRT to not exit the application when an invalid parameter is */ + /* passed. The main issue is that invalid FDs will trigger this behavior. */ +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 + _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); +#endif + + /* We also need to setup our debug report handler because some CRT */ + /* functions (eg _get_osfhandle) raise an assert when called with invalid */ + /* FDs even though they return the proper error code in the release build. */ +#ifdef _DEBUG + _CrtSetReportHook(uv__crt_dbg_report_handler); +#endif + + /* Fetch winapi function pointers. This must be done first because other */ + /* intialization code might need these function pointers to be loaded. */ + uv_winapi_init(); + + /* Initialize winsock */ + uv_winsock_init(); + + /* Initialize FS */ + uv_fs_init(); + + /* Initialize signal stuff */ + uv_signals_init(); + + /* Initialize console */ + uv_console_init(); + + /* Initialize utilities */ + uv__util_init(); +} + + +static void uv_loop_init(uv_loop_t* loop) { + /* Create an I/O completion port */ + loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + if (loop->iocp == NULL) { + uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); + } + + /* To prevent uninitialized memory access, loop->time must be intialized */ + /* to zero before calling uv_update_time for the first time. */ + loop->time = 0; + loop->last_tick_count = 0; + uv_update_time(loop); + + QUEUE_INIT(&loop->handle_queue); + QUEUE_INIT(&loop->active_reqs); + loop->active_handles = 0; + + loop->pending_reqs_tail = NULL; + + loop->endgame_handles = NULL; + + RB_INIT(&loop->timers); + + loop->check_handles = NULL; + loop->prepare_handles = NULL; + loop->idle_handles = NULL; + + loop->next_prepare_handle = NULL; + loop->next_check_handle = NULL; + loop->next_idle_handle = NULL; + + memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); + + loop->active_tcp_streams = 0; + loop->active_udp_streams = 0; + + loop->timer_counter = 0; + loop->stop_flag = 0; +} + + +static void uv_default_loop_init(void) { + /* Initialize libuv itself first */ + uv__once_init(); + + /* Initialize the main loop */ + uv_loop_init(&uv_default_loop_); +} + + +void uv__once_init(void) { + uv_once(&uv_init_guard_, uv_init); +} + + +uv_loop_t* uv_default_loop(void) { + uv_once(&uv_default_loop_init_guard_, uv_default_loop_init); + return &uv_default_loop_; +} + + +uv_loop_t* uv_loop_new(void) { + uv_loop_t* loop; + + /* Initialize libuv itself first */ + uv__once_init(); + + loop = (uv_loop_t*)malloc(sizeof(uv_loop_t)); + + if (!loop) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + uv_loop_init(loop); + return loop; +} + + +void uv_loop_delete(uv_loop_t* loop) { + if (loop != &uv_default_loop_) { + int i; + for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { + SOCKET sock = loop->poll_peer_sockets[i]; + if (sock != 0 && sock != INVALID_SOCKET) { + closesocket(sock); + } + } + + free(loop); + } +} + + +int uv_backend_fd(const uv_loop_t* loop) { + return -1; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + return 0; +} + + +static void uv_poll(uv_loop_t* loop, int block) { + DWORD bytes, timeout; + ULONG_PTR key; + OVERLAPPED* overlapped; + uv_req_t* req; + + if (block) { + timeout = uv_get_poll_timeout(loop); + } else { + timeout = 0; + } + + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); + + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else { + /* We're sure that at least `timeout` milliseconds have expired, but */ + /* this may not be reflected yet in the GetTickCount() return value. */ + /* Therefore we ensure it's taken into account here. */ + uv__time_forward(loop, timeout); + } +} + + +static void uv_poll_ex(uv_loop_t* loop, int block) { + BOOL success; + DWORD timeout; + uv_req_t* req; + OVERLAPPED_ENTRY overlappeds[128]; + ULONG count; + ULONG i; + + if (block) { + timeout = uv_get_poll_timeout(loop); + } else { + timeout = 0; + } + + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } else if (timeout > 0) { + /* We're sure that at least `timeout` milliseconds have expired, but */ + /* this may not be reflected yet in the GetTickCount() return value. */ + /* Therefore we ensure it's taken into account here. */ + uv__time_forward(loop, timeout); + } +} + + +static int uv__loop_alive(const uv_loop_t* loop) { + return loop->active_handles > 0 || + !QUEUE_EMPTY(&loop->active_reqs) || + loop->endgame_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + +int uv_run(uv_loop_t *loop, uv_run_mode mode) { + int r; + void (*poll)(uv_loop_t* loop, int block); + + if (pGetQueuedCompletionStatusEx) + poll = &uv_poll_ex; + else + poll = &uv_poll; + + r = uv__loop_alive(loop); + if (!r) + uv_update_time(loop); + + while (r != 0 && loop->stop_flag == 0) { + uv_update_time(loop); + uv_process_timers(loop); + + uv_process_reqs(loop); + uv_idle_invoke(loop); + uv_prepare_invoke(loop); + + (*poll)(loop, loop->idle_handles == NULL && + loop->pending_reqs_tail == NULL && + loop->endgame_handles == NULL && + !loop->stop_flag && + (loop->active_handles > 0 || + !QUEUE_EMPTY(&loop->active_reqs)) && + !(mode & UV_RUN_NOWAIT)); + + uv_check_invoke(loop); + uv_process_endgames(loop); + + if (mode == UV_RUN_ONCE) { + /* UV_RUN_ONCE implies forward progess: at least one callback must have + * been invoked when it returns. uv__io_poll() can return without doing + * I/O (meaning: no callbacks) when its timeout expires - which means we + * have pending timers that satisfy the forward progress constraint. + * + * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from + * the check. + */ + uv_update_time(loop); + uv_process_timers(loop); + } + + r = uv__loop_alive(loop); + if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + break; + } + + /* The if statement lets the compiler compile it to a conditional store. + * Avoids dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + + return r; +} diff --git a/src/win/dl.c b/src/win/dl.c new file mode 100644 index 0000000000..d5b8f7c7d3 --- /dev/null +++ b/src/win/dl.c @@ -0,0 +1,86 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +static int uv__dlerror(uv_lib_t* lib, int errorno); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + WCHAR filename_w[32768]; + + lib->handle = NULL; + lib->errmsg = NULL; + + if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, GetLastError()); + } + + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, GetLastError()); + } + + return 0; +} + + +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + FreeLibrary(lib->handle); + lib->handle = NULL; + } +} + + +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + *ptr = (void*) GetProcAddress(lib->handle, name); + return uv__dlerror(lib, *ptr ? 0 : GetLastError()); +} + + +const char* uv_dlerror(uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; +} + + +static int uv__dlerror(uv_lib_t* lib, int errorno) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno) { + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&lib->errmsg, 0, NULL); + } + + return errorno ? -1 : 0; +} diff --git a/src/win/error.c b/src/win/error.c new file mode 100644 index 0000000000..3162bc787f --- /dev/null +++ b/src/win/error.c @@ -0,0 +1,169 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* + * Display an error message and abort the event loop. + */ +void uv_fatal_error(const int errorno, const char* syscall) { + char* buf = NULL; + const char* errmsg; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); + + if (buf) { + errmsg = buf; + } else { + errmsg = "Unknown error"; + } + + /* FormatMessage messages include a newline character already, */ + /* so don't add another. */ + if (syscall) { + fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); + } else { + fprintf(stderr, "(%d) %s", errorno, errmsg); + } + + if (buf) { + LocalFree(buf); + } + + *((char*)NULL) = 0xff; /* Force debug break */ + abort(); +} + + +int uv_translate_sys_error(int sys_errno) { + if (sys_errno <= 0) { + return sys_errno; /* If < 0 then it's already a libuv error. */ + } + + switch (sys_errno) { + case ERROR_NOACCESS: return UV_EACCES; + case WSAEACCES: return UV_EACCES; + case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; + case WSAEADDRINUSE: return UV_EADDRINUSE; + case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT; + case WSAEWOULDBLOCK: return UV_EAGAIN; + case WSAEALREADY: return UV_EALREADY; + case ERROR_INVALID_FLAGS: return UV_EBADF; + case ERROR_INVALID_HANDLE: return UV_EBADF; + case ERROR_LOCK_VIOLATION: return UV_EBUSY; + case ERROR_PIPE_BUSY: return UV_EBUSY; + case ERROR_SHARING_VIOLATION: return UV_EBUSY; + case ERROR_OPERATION_ABORTED: return UV_ECANCELED; + case WSAEINTR: return UV_ECANCELED; + case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; + case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED; + case WSAECONNABORTED: return UV_ECONNABORTED; + case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; + case WSAECONNREFUSED: return UV_ECONNREFUSED; + case ERROR_NETNAME_DELETED: return UV_ECONNRESET; + case WSAECONNRESET: return UV_ECONNRESET; + case ERROR_ALREADY_EXISTS: return UV_EEXIST; + case ERROR_FILE_EXISTS: return UV_EEXIST; + case ERROR_BUFFER_OVERFLOW: return UV_EFAULT; + case WSAEFAULT: return UV_EFAULT; + case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; + case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; + case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; + case ERROR_INVALID_DATA: return UV_EINVAL; + case ERROR_INVALID_PARAMETER: return UV_EINVAL; + case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; + case WSAEINVAL: return UV_EINVAL; + case WSAEPFNOSUPPORT: return UV_EINVAL; + case WSAESOCKTNOSUPPORT: return UV_EINVAL; + case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; + case ERROR_BUS_RESET: return UV_EIO; + case ERROR_CRC: return UV_EIO; + case ERROR_DEVICE_DOOR_OPEN: return UV_EIO; + case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO; + case ERROR_DISK_CORRUPT: return UV_EIO; + case ERROR_EOM_OVERFLOW: return UV_EIO; + case ERROR_FILEMARK_DETECTED: return UV_EIO; + case ERROR_GEN_FAILURE: return UV_EIO; + case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO; + case ERROR_IO_DEVICE: return UV_EIO; + case ERROR_NO_DATA_DETECTED: return UV_EIO; + case ERROR_NO_SIGNAL_SENT: return UV_EIO; + case ERROR_OPEN_FAILED: return UV_EIO; + case ERROR_SETMARK_DETECTED: return UV_EIO; + case ERROR_SIGNAL_REFUSED: return UV_EIO; + case WSAEISCONN: return UV_EISCONN; + case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; + case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; + case WSAEMFILE: return UV_EMFILE; + case WSAEMSGSIZE: return UV_EMSGSIZE; + case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG; + case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; + case WSAENETUNREACH: return UV_ENETUNREACH; + case WSAENOBUFS: return UV_ENOBUFS; + case ERROR_DIRECTORY: return UV_ENOENT; + case ERROR_FILE_NOT_FOUND: return UV_ENOENT; + case ERROR_INVALID_NAME: return UV_ENOENT; + case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT; + case ERROR_MOD_NOT_FOUND: return UV_ENOENT; + case ERROR_PATH_NOT_FOUND: return UV_ENOENT; + case WSAHOST_NOT_FOUND: return UV_ENOENT; + case WSANO_DATA: return UV_ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM; + case ERROR_OUTOFMEMORY: return UV_ENOMEM; + case ERROR_CANNOT_MAKE: return UV_ENOSPC; + case ERROR_DISK_FULL: return UV_ENOSPC; + case ERROR_EA_TABLE_FULL: return UV_ENOSPC; + case ERROR_END_OF_MEDIA: return UV_ENOSPC; + case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC; + case ERROR_NOT_CONNECTED: return UV_ENOTCONN; + case WSAENOTCONN: return UV_ENOTCONN; + case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY; + case WSAENOTSOCK: return UV_ENOTSOCK; + case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; + case ERROR_BROKEN_PIPE: return UV_EOF; + case ERROR_ACCESS_DENIED: return UV_EPERM; + case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; + case ERROR_BAD_PIPE: return UV_EPIPE; + case ERROR_NO_DATA: return UV_EPIPE; + case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE; + case WSAESHUTDOWN: return UV_EPIPE; + case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT; + case ERROR_WRITE_PROTECT: return UV_EROFS; + case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT; + case WSAETIMEDOUT: return UV_ETIMEDOUT; + case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; + case ERROR_INVALID_FUNCTION: return UV_EISDIR; + case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; + default: return UV_UNKNOWN; + } +} diff --git a/src/win/fs-event.c b/src/win/fs-event.c new file mode 100644 index 0000000000..6132b79c82 --- /dev/null +++ b/src/win/fs-event.c @@ -0,0 +1,527 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +const unsigned int uv_directory_watcher_buffer_size = 4096; + + +static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, + uv_fs_event_t* handle) { + assert(handle->dir_handle != INVALID_HANDLE_VALUE); + assert(!handle->req_pending); + + memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped)); + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.overlapped, + NULL)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(&handle->req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)&handle->req); + } + + handle->req_pending = 1; +} + + +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { + int len = wcslen(filename); + int i = len; + while (i > 0 && filename[--i] != '\\' && filename[i] != '/'); + + if (i == 0) { + if (dir) { + *dir = (WCHAR*)malloc((MAX_PATH + 1) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!GetCurrentDirectoryW(MAX_PATH, *dir)) { + free(*dir); + *dir = NULL; + return -1; + } + } + + *file = wcsdup(filename); + } else { + if (dir) { + *dir = (WCHAR*)malloc((i + 1) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + wcsncpy(*dir, filename, i); + (*dir)[i] = L'\0'; + } + + *file = (WCHAR*)malloc((len - i) * sizeof(WCHAR)); + if (!*file) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + wcsncpy(*file, filename + i + 1, len - i - 1); + (*file)[len - i - 1] = L'\0'; + } + + return 0; +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT); + handle->dir_handle = INVALID_HANDLE_VALUE; + handle->buffer = NULL; + handle->req_pending = 0; + handle->filew = NULL; + handle->short_filew = NULL; + handle->dirw = NULL; + + uv_req_init(loop, (uv_req_t*)&handle->req); + handle->req.type = UV_FS_EVENT_REQ; + handle->req.data = handle; + + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + int name_size, is_path_dir; + DWORD attr, last_error; + WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL; + WCHAR short_path[MAX_PATH]; + + if (uv__is_active(handle)) + return UV_EINVAL; + + handle->cb = cb; + handle->filename = strdup(filename); + if (!handle->filename) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + uv__handle_start(handle); + + /* Convert name to UTF16. */ + name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(WCHAR); + filenamew = (WCHAR*)malloc(name_size); + if (!filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!uv_utf8_to_utf16(filename, filenamew, + name_size / sizeof(WCHAR))) { + return uv_translate_sys_error(GetLastError()); + } + + /* Determine whether filename is a file or a directory. */ + attr = GetFileAttributesW(filenamew); + if (attr == INVALID_FILE_ATTRIBUTES) { + last_error = GetLastError(); + goto error; + } + + is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + + if (is_path_dir) { + /* filename is a directory, so that's the directory that we will watch. */ + handle->dirw = filenamew; + dir_to_watch = filenamew; + } else { + /* + * filename is a file. So we split filename into dir & file parts, and + * watch the dir directory. + */ + + /* Convert to short path. */ + if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(filenamew, &dir, &handle->filew) != 0) { + last_error = GetLastError(); + goto error; + } + + if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { + last_error = GetLastError(); + goto error; + } + + dir_to_watch = dir; + free(filenamew); + filenamew = NULL; + } + + handle->dir_handle = CreateFileW(dir_to_watch, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_DELETE | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + + if (dir) { + free(dir); + dir = NULL; + } + + if (handle->dir_handle == INVALID_HANDLE_VALUE) { + last_error = GetLastError(); + goto error; + } + + if (CreateIoCompletionPort(handle->dir_handle, + handle->loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + last_error = GetLastError(); + goto error; + } + + if (!handle->buffer) { + handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, + sizeof(DWORD)); + } + if (!handle->buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + memset(&(handle->req.overlapped), 0, sizeof(handle->req.overlapped)); + + if (!ReadDirectoryChangesW(handle->dir_handle, + handle->buffer, + uv_directory_watcher_buffer_size, + FALSE, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY, + NULL, + &handle->req.overlapped, + NULL)) { + last_error = GetLastError(); + goto error; + } + + handle->req_pending = 1; + return 0; + +error: + if (handle->filename) { + free(handle->filename); + handle->filename = NULL; + } + + if (handle->filew) { + free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + free(handle->short_filew); + handle->short_filew = NULL; + } + + free(filenamew); + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + if (handle->buffer) { + _aligned_free(handle->buffer); + handle->buffer = NULL; + } + + return uv_translate_sys_error(last_error); +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + if (!uv__is_active(handle)) + return UV_EINVAL; + + if (handle->dir_handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->dir_handle); + handle->dir_handle = INVALID_HANDLE_VALUE; + } + + uv__handle_stop(handle); + + if (handle->filew) { + free(handle->filew); + handle->filew = NULL; + } + + if (handle->short_filew) { + free(handle->short_filew); + handle->short_filew = NULL; + } + + if (handle->filename) { + free(handle->filename); + handle->filename = NULL; + } + + if (handle->dirw) { + free(handle->dirw); + handle->dirw = NULL; + } + + return 0; +} + + +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle) { + FILE_NOTIFY_INFORMATION* file_info; + int err, sizew, size, result; + char* filename = NULL; + WCHAR* filenamew, *long_filenamew = NULL; + DWORD offset = 0; + + assert(req->type == UV_FS_EVENT_REQ); + assert(handle->req_pending); + handle->req_pending = 0; + + /* Don't report any callbacks if: + * - We're closing, just push the handle onto the endgame queue + * - We are not active, just ignore the callback + */ + if (!uv__is_active(handle)) { + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + return; + } + + file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset); + + if (REQ_SUCCESS(req)) { + if (req->overlapped.InternalHigh > 0) { + do { + file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); + assert(!filename); + assert(!long_filenamew); + + /* + * Fire the event only if we were asked to watch a directory, + * or if the filename filter matches. + */ + if (handle->dirw || + _wcsnicmp(handle->filew, file_info->FileName, + file_info->FileNameLength / sizeof(WCHAR)) == 0 || + _wcsnicmp(handle->short_filew, file_info->FileName, + file_info->FileNameLength / sizeof(WCHAR)) == 0) { + + if (handle->dirw) { + /* + * We attempt to convert the file name to its long form for + * events that still point to valid files on disk. + * For removed and renamed events, we do not provide the file name. + */ + if (file_info->Action != FILE_ACTION_REMOVED && + file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { + /* Construct a full path to the file. */ + size = wcslen(handle->dirw) + + file_info->FileNameLength / sizeof(WCHAR) + 2; + + filenamew = (WCHAR*)malloc(size * sizeof(WCHAR)); + if (!filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, + file_info->FileNameLength / sizeof(WCHAR), + file_info->FileName); + + filenamew[size - 1] = L'\0'; + + /* Convert to long name. */ + size = GetLongPathNameW(filenamew, NULL, 0); + + if (size) { + long_filenamew = (WCHAR*)malloc(size * sizeof(WCHAR)); + if (!long_filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + size = GetLongPathNameW(filenamew, long_filenamew, size); + if (size) { + long_filenamew[size] = '\0'; + } else { + free(long_filenamew); + long_filenamew = NULL; + } + } + + free(filenamew); + + if (long_filenamew) { + /* Get the file name out of the long path. */ + result = uv_split_path(long_filenamew, NULL, &filenamew); + free(long_filenamew); + + if (result == 0) { + long_filenamew = filenamew; + sizew = -1; + } else { + long_filenamew = NULL; + } + } + + /* + * If we couldn't get the long name - just use the name + * provided by ReadDirectoryChangesW. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } + } else { + /* Removed or renamed callbacks don't provide filename. */ + filenamew = NULL; + } + } else { + /* We already have the long name of the file, so just use it. */ + filenamew = handle->filew; + sizew = -1; + } + + if (filenamew) { + /* Convert the filename to utf8. */ + size = uv_utf16_to_utf8(filenamew, + sizew, + NULL, + 0); + if (size) { + filename = (char*)malloc(size + 1); + if (!filename) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + size = uv_utf16_to_utf8(filenamew, + sizew, + filename, + size); + if (size) { + filename[size] = '\0'; + } else { + free(filename); + filename = NULL; + } + } + } + + switch (file_info->Action) { + case FILE_ACTION_ADDED: + case FILE_ACTION_REMOVED: + case FILE_ACTION_RENAMED_OLD_NAME: + case FILE_ACTION_RENAMED_NEW_NAME: + handle->cb(handle, filename, UV_RENAME, 0); + break; + + case FILE_ACTION_MODIFIED: + handle->cb(handle, filename, UV_CHANGE, 0); + break; + } + + free(filename); + filename = NULL; + free(long_filenamew); + long_filenamew = NULL; + } + + offset = file_info->NextEntryOffset; + } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); + } else { + handle->cb(handle, NULL, UV_CHANGE, 0); + } + } else { + err = GET_REQ_ERROR(req); + handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); + } + + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_fs_event_queue_readdirchanges(loop, handle); + } else { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { + uv_fs_event_stop(handle); + + uv__handle_closing(handle); + + if (!handle->req_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + +} + + +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { + if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->buffer) { + _aligned_free(handle->buffer); + handle->buffer = NULL; + } + + uv__handle_close(handle); + } +} diff --git a/src/win/fs.c b/src/win/fs.c new file mode 100644 index 0000000000..c4182758c7 --- /dev/null +++ b/src/win/fs.c @@ -0,0 +1,2043 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" +#include "handle-inl.h" + + +#define UV_FS_FREE_PATHS 0x0002 +#define UV_FS_FREE_PTR 0x0008 +#define UV_FS_CLEANEDUP 0x0010 + + +#define QUEUE_FS_TP_JOB(loop, req) \ + do { \ + if (!QueueUserWorkItem(&uv_fs_thread_proc, \ + req, \ + WT_EXECUTEDEFAULT)) { \ + return uv_translate_sys_error(GetLastError()); \ + } \ + uv__req_register(loop, req); \ + } while (0) + +#define SET_REQ_RESULT(req, result_value) \ + do { \ + req->result = (result_value); \ + if (req->result == -1) { \ + req->sys_errno_ = _doserrno; \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } \ + } while (0) + +#define SET_REQ_WIN32_ERROR(req, sys_errno) \ + do { \ + req->sys_errno_ = (sys_errno); \ + req->result = uv_translate_sys_error(req->sys_errno_); \ + } while (0) + +#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \ + do { \ + req->result = (uv_errno); \ + req->sys_errno_ = (sys_errno); \ + } while (0) + +#define VERIFY_FD(fd, req) \ + if (fd == -1) { \ + req->result = UV_EBADF; \ + req->sys_errno_ = ERROR_INVALID_HANDLE; \ + return; \ + } + +#define FILETIME_TO_UINT(filetime) \ + (*((uint64_t*) &(filetime)) - 116444736000000000ULL) + +#define FILETIME_TO_TIME_T(filetime) \ + (FILETIME_TO_UINT(filetime) / 10000000ULL) + +#define FILETIME_TO_TIME_NS(filetime, secs) \ + ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100) + +#define FILETIME_TO_TIMESPEC(ts, filetime) \ + do { \ + (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \ + (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \ + } while(0) + +#define TIME_T_TO_FILETIME(time, filetime_ptr) \ + do { \ + *(uint64_t*) (filetime_ptr) = ((int64_t) (time) * 10000000LL) + \ + 116444736000000000ULL; \ + } while(0) + +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const WCHAR JUNCTION_PREFIX[] = L"\\??\\"; +const WCHAR JUNCTION_PREFIX_LEN = 4; + +const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; +const WCHAR LONG_PATH_PREFIX_LEN = 4; + + +void uv_fs_init() { + _fmode = _O_BINARY; +} + + +INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req, + const char* path, const char* new_path, const int copy_path) { + char* buf; + char* pos; + ssize_t buf_sz = 0, path_len, pathw_len, new_pathw_len; + + /* new_path can only be set if path is also set. */ + assert(new_path == NULL || path != NULL); + + if (path != NULL) { + pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + NULL, + 0); + if (pathw_len == 0) { + return GetLastError(); + } + + buf_sz += pathw_len * sizeof(WCHAR); + } + + if (path != NULL && copy_path) { + path_len = 1 + strlen(path); + buf_sz += path_len; + } + + if (new_path != NULL) { + new_pathw_len = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + NULL, + 0); + if (new_pathw_len == 0) { + return GetLastError(); + } + + buf_sz += new_pathw_len * sizeof(WCHAR); + } + + + if (buf_sz == 0) { + req->pathw = NULL; + req->new_pathw = NULL; + req->path = NULL; + return 0; + } + + buf = (char*) malloc(buf_sz); + if (buf == NULL) { + return ERROR_OUTOFMEMORY; + } + + pos = buf; + + if (path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + (WCHAR*) pos, + pathw_len); + assert(r == pathw_len); + req->pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->pathw = NULL; + } + + if (new_path != NULL) { + DWORD r = MultiByteToWideChar(CP_UTF8, + 0, + new_path, + -1, + (WCHAR*) pos, + new_pathw_len); + assert(r == new_pathw_len); + req->new_pathw = (WCHAR*) pos; + pos += r * sizeof(WCHAR); + } else { + req->new_pathw = NULL; + } + + if (!copy_path) { + req->path = path; + } else if (path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf)); + req->path = pos; + } else { + req->path = NULL; + } + + req->flags |= UV_FS_FREE_PATHS; + + return 0; +} + + + +INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, + uv_fs_type fs_type, const uv_fs_cb cb) { + uv_req_init(loop, (uv_req_t*) req); + + req->type = UV_FS; + req->loop = loop; + req->flags = 0; + req->fs_type = fs_type; + req->result = 0; + req->ptr = NULL; + req->path = NULL; + + if (cb != NULL) { + req->cb = cb; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + } +} + + +INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, + uint64_t* target_len_ptr) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; + WCHAR *w_target; + DWORD w_target_len; + char* target; + int target_len; + DWORD bytes; + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + sizeof buffer, + &bytes, + NULL)) { + return -1; + } + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* Real symlink */ + w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Real symlinks can contain pretty much everything, but the only thing */ + /* we really care about is undoing the implicit conversion to an NT */ + /* namespaced path that CreateSymbolicLink will perform on absolute */ + /* paths. If the path is win32-namespaced then the user must have */ + /* explicitly made it so, and we better just return the unmodified */ + /* reparse data. */ + if (w_target_len >= 4 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\') { + /* Starts with \??\ */ + if (w_target_len >= 6 && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\')) { + /* \??\«drive»:\ */ + w_target += 4; + w_target_len -= 4; + + } else if (w_target_len >= 8 && + (w_target[4] == L'U' || w_target[4] == L'u') && + (w_target[5] == L'N' || w_target[5] == L'n') && + (w_target[6] == L'C' || w_target[6] == L'c') && + w_target[7] == L'\\') { + /* \??\UNC\«server»\«share»\ - make sure the final path looks like */ + /* \\«server»\«share»\ */ + w_target += 6; + w_target[0] = L'\\'; + w_target_len -= 6; + } + } + + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + /* Junction. */ + w_target = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR)); + w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(WCHAR); + + /* Only treat junctions that look like \??\«drive»:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{«guid»}, */ + /* but that's confusing for programs since they wouldn't be able to */ + /* actually understand such a path when returned by uv_readlink(). */ + /* UNC paths are never valid for junctions so we don't care about them. */ + if (!(w_target_len >= 6 && + w_target[0] == L'\\' && + w_target[1] == L'?' && + w_target[2] == L'?' && + w_target[3] == L'\\' && + ((w_target[4] >= L'A' && w_target[4] <= L'Z') || + (w_target[4] >= L'a' && w_target[4] <= L'z')) && + w_target[5] == L':' && + (w_target_len == 6 || w_target[6] == L'\\'))) { + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + /* Remove leading \??\ */ + w_target += 4; + w_target_len -= 4; + + } else { + /* Reparse tag does not indicate a symlink. */ + SetLastError(ERROR_SYMLINK_NOT_SUPPORTED); + return -1; + } + + /* If needed, compute the length of the target. */ + if (target_ptr != NULL || target_len_ptr != NULL) { + /* Compute the length of the target. */ + target_len = WideCharToMultiByte(CP_UTF8, + 0, + w_target, + w_target_len, + NULL, + 0, + NULL, + NULL); + if (target_len == 0) { + return -1; + } + } + + /* If requested, allocate memory and convert to UTF8. */ + if (target_ptr != NULL) { + int r; + target = (char*) malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + r = WideCharToMultiByte(CP_UTF8, + 0, + w_target, + w_target_len, + target, + target_len, + NULL, + NULL); + assert(r == target_len); + target[target_len] = '\0'; + + *target_ptr = target; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + return 0; +} + + +void fs__open(uv_fs_t* req) { + DWORD access; + DWORD share; + DWORD disposition; + DWORD attributes = 0; + HANDLE file; + int fd, current_umask; + int flags = req->file_flags; + + /* Obtain the active umask. umask() never fails and returns the previous */ + /* umask. */ + current_umask = umask(0); + umask(current_umask); + + /* convert flags and mode to CreateFile parameters */ + switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { + case _O_RDONLY: + access = FILE_GENERIC_READ; + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + break; + case _O_WRONLY: + access = FILE_GENERIC_WRITE; + break; + case _O_RDWR: + access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & _O_APPEND) { + access &= ~FILE_WRITE_DATA; + access |= FILE_APPEND_DATA; + attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; + } + + /* + * Here is where we deviate significantly from what CRT's _open() + * does. We indiscriminately use all the sharing modes, to match + * UNIX semantics. In particular, this ensures that the file can + * be deleted even whilst it's open, fixing issue #1449. + */ + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + + switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + case 0: + case _O_EXCL: + disposition = OPEN_EXISTING; + break; + case _O_CREAT: + disposition = OPEN_ALWAYS; + break; + case _O_CREAT | _O_EXCL: + case _O_CREAT | _O_TRUNC | _O_EXCL: + disposition = CREATE_NEW; + break; + case _O_TRUNC: + case _O_TRUNC | _O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case _O_CREAT | _O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & _O_CREAT) { + if (!((req->mode & ~current_umask) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & _O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & _O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + case 0: + break; + case _O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case _O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + + file = CreateFileW(req->pathw, + access, + share, + NULL, + disposition, + attributes, + NULL); + if (file == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && + !(flags & _O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + /* specified, it means the path referred to a directory. */ + SET_REQ_UV_ERROR(req, UV_EISDIR, error); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + return; + } + + fd = _open_osfhandle((intptr_t) file, flags); + if (fd < 0) { + /* The only known failure mode for _open_osfhandle() is EMFILE, in which + * case GetLastError() will return zero. However we'll try to handle other + * errors as well, should they ever occur. + */ + if (errno == EMFILE) + SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES); + else if (GetLastError() != ERROR_SUCCESS) + SET_REQ_WIN32_ERROR(req, GetLastError()); + else + SET_REQ_WIN32_ERROR(req, UV_UNKNOWN); + return; + } + + SET_REQ_RESULT(req, fd); + return; + + einval: + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); +} + +void fs__close(uv_fs_t* req) { + int fd = req->fd; + int result; + + VERIFY_FD(fd, req); + + result = _close(fd); + SET_REQ_RESULT(req, result); +} + + +void fs__read(uv_fs_t* req) { + int fd = req->fd; + size_t length = req->length; + int64_t offset = req->offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + DWORD error; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (length > INT_MAX) { + SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + + offset_.QuadPart = offset; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + if (ReadFile(handle, req->buf, req->length, &bytes, overlapped_ptr)) { + SET_REQ_RESULT(req, bytes); + } else { + error = GetLastError(); + if (error == ERROR_HANDLE_EOF) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, error); + } + } +} + + +void fs__write(uv_fs_t* req) { + int fd = req->fd; + size_t length = req->length; + int64_t offset = req->offset; + HANDLE handle; + OVERLAPPED overlapped, *overlapped_ptr; + LARGE_INTEGER offset_; + DWORD bytes; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (length > INT_MAX) { + SET_REQ_WIN32_ERROR(req, ERROR_INSUFFICIENT_BUFFER); + return; + } + + if (offset != -1) { + memset(&overlapped, 0, sizeof overlapped); + + offset_.QuadPart = offset; + overlapped.Offset = offset_.LowPart; + overlapped.OffsetHigh = offset_.HighPart; + + overlapped_ptr = &overlapped; + } else { + overlapped_ptr = NULL; + } + + if (WriteFile(handle, req->buf, length, &bytes, overlapped_ptr)) { + SET_REQ_RESULT(req, bytes); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } +} + + +void fs__rmdir(uv_fs_t* req) { + int result = _wrmdir(req->pathw); + SET_REQ_RESULT(req, result); +} + + +void fs__unlink(uv_fs_t* req) { + const WCHAR* pathw = req->pathw; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + FILE_DISPOSITION_INFORMATION disposition; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + + handle = CreateFileW(pathw, + FILE_READ_ATTRIBUTES | DELETE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* Do not allow deletion of directories, unless it is a symlink. When */ + /* the path refers to a non-symlink directory, report EPERM as mandated */ + /* by POSIX.1. */ + + /* Check if it is a reparse point. If it's not, it's a normal directory. */ + if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + CloseHandle(handle); + return; + } + + /* Read the reparse point and check if it is a valid symlink. */ + /* If not, don't unlink. */ + if (fs__readlink_handle(handle, NULL, NULL) < 0) { + DWORD error = GetLastError(); + if (error == ERROR_SYMLINK_NOT_SUPPORTED) + error = ERROR_ACCESS_DENIED; + SET_REQ_WIN32_ERROR(req, error); + CloseHandle(handle); + return; + } + } + + /* Try to set the delete flag. */ + disposition.DeleteFile = TRUE; + status = pNtSetInformationFile(handle, + &iosb, + &disposition, + sizeof disposition, + FileDispositionInformation); + if (NT_SUCCESS(status)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } + + CloseHandle(handle); +} + + +void fs__mkdir(uv_fs_t* req) { + /* TODO: use req->mode. */ + int result = _wmkdir(req->pathw); + SET_REQ_RESULT(req, result); +} + + +void fs__readdir(uv_fs_t* req) { + WCHAR* pathw = req->pathw; + size_t len = wcslen(pathw); + int result, size; + WCHAR* buf = NULL, *ptr, *name; + HANDLE dir; + WIN32_FIND_DATAW ent = { 0 }; + size_t buf_char_len = 4096; + WCHAR* path2; + const WCHAR* fmt; + + if (len == 0) { + fmt = L"./*"; + } else if (pathw[len - 1] == L'/' || pathw[len - 1] == L'\\') { + fmt = L"%s*"; + } else { + fmt = L"%s\\*"; + } + + /* Figure out whether path is a file or a directory. */ + if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) { + req->result = UV_ENOTDIR; + req->sys_errno_ = ERROR_SUCCESS; + return; + } + + path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4)); + if (!path2) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + _snwprintf(path2, len + 3, fmt, pathw); + dir = FindFirstFileW(path2, &ent); + free(path2); + + if(dir == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + result = 0; + + do { + name = ent.cFileName; + + if (name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))) { + len = wcslen(name); + + if (!buf) { + buf = (WCHAR*)malloc(buf_char_len * sizeof(WCHAR)); + if (!buf) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + ptr = buf; + } + + while ((ptr - buf) + len + 1 > buf_char_len) { + buf_char_len *= 2; + path2 = buf; + buf = (WCHAR*)realloc(buf, buf_char_len * sizeof(WCHAR)); + if (!buf) { + uv_fatal_error(ERROR_OUTOFMEMORY, "realloc"); + } + + ptr = buf + (ptr - path2); + } + + wcscpy(ptr, name); + ptr += len + 1; + result++; + } + } while(FindNextFileW(dir, &ent)); + + FindClose(dir); + + if (buf) { + /* Convert result to UTF8. */ + size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0); + if (!size) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->ptr = (char*)malloc(size + 1); + if (!req->ptr) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size); + if (!size) { + free(buf); + free(req->ptr); + req->ptr = NULL; + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + free(buf); + + ((char*)req->ptr)[size] = '\0'; + req->flags |= UV_FS_FREE_PTR; + } else { + req->ptr = NULL; + } + + SET_REQ_RESULT(req, result); +} + + +INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { + FILE_ALL_INFORMATION file_info; + FILE_FS_VOLUME_INFORMATION volume_info; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileAllInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + /* Todo: st_mode should probably always be 0666 for everyone. We might also + * want to report 0777 if the file is a .exe or a directory. + * + * Currently it's based on whether the 'readonly' attribute is set, which + * makes little sense because the semantics are so different: the 'read-only' + * flag is just a way for a user to protect against accidental deleteion, and + * serves no security purpose. Windows uses ACLs for that. + * + * Also people now use uv_fs_chmod() to take away the writable bit for good + * reasons. Windows however just makes the file read-only, which makes it + * impossible to delete the file afterwards, since read-only files can't be + * deleted. + * + * IOW it's all just a clusterfuck and we should think of something that + * makes slighty more sense. + * + * And uv_fs_chmod should probably just fail on windows or be a total no-op. + * There's nothing sensible it can do anyway. + */ + statbuf->st_mode = 0; + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + statbuf->st_mode |= S_IFLNK; + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + return -1; + + } else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + statbuf->st_mode |= _S_IFDIR; + statbuf->st_size = 0; + + } else { + statbuf->st_mode |= _S_IFREG; + statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + } + + if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) + statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6); + else + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + + FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime); + FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime); + FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime); + FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime); + + statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; + + /* st_blocks contains the on-disk allocation size in 512-byte units. */ + statbuf->st_blocks = + file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL; + + statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks; + + statbuf->st_dev = volume_info.VolumeSerialNumber; + + /* The st_blksize is supposed to be the 'optimal' number of bytes for reading + * and writing to the disk. That is, for any definition of 'optimal' - it's + * supposed to at least avoid read-update-write behavior when writing to the + * disk. + * + * However nobody knows this and even fewer people actually use this value, + * and in order to fill it out we'd have to make another syscall to query the + * volume for FILE_FS_SECTOR_SIZE_INFORMATION. + * + * Therefore we'll just report a sensible value that's quite commonly okay + * on modern hardware. + */ + statbuf->st_blksize = 2048; + + /* Todo: set st_flags to something meaningful. Also provide a wrapper for + * chattr(2). + */ + statbuf->st_flags = 0; + + /* Windows has nothing sensible to say about these values, so they'll just + * remain empty. + */ + statbuf->st_gid = 0; + statbuf->st_uid = 0; + statbuf->st_rdev = 0; + statbuf->st_gen = 0; + + return 0; +} + + +INLINE static void fs__stat_prepare_path(WCHAR* pathw) { + size_t len = wcslen(pathw); + + /* TODO: ignore namespaced paths. */ + if (len > 1 && pathw[len - 2] != L':' && + (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) { + pathw[len - 1] = '\0'; + } +} + + +INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { + HANDLE handle; + DWORD flags; + + flags = FILE_FLAG_BACKUP_SEMANTICS; + if (do_lstat) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } + + handle = CreateFileW(req->pathw, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + flags, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + DWORD error = GetLastError(); + if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + /* We opened a reparse point but it was not a symlink. Try again. */ + fs__stat_impl(req, 0); + + } else { + /* Stat failed. */ + SET_REQ_WIN32_ERROR(req, GetLastError()); + } + + CloseHandle(handle); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; + CloseHandle(handle); +} + + +static void fs__stat(uv_fs_t* req) { + fs__stat_prepare_path(req->pathw); + fs__stat_impl(req, 0); +} + + +static void fs__lstat(uv_fs_t* req) { + fs__stat_prepare_path(req->pathw); + fs__stat_impl(req, 1); +} + + +static void fs__fstat(uv_fs_t* req) { + int fd = req->fd; + HANDLE handle; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__stat_handle(handle, &req->statbuf) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->ptr = &req->statbuf; + req->result = 0; +} + + +static void fs__rename(uv_fs_t* req) { + if (!MoveFileExW(req->pathw, req->new_pathw, MOVEFILE_REPLACE_EXISTING)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + +INLINE static void fs__sync_impl(uv_fs_t* req) { + int fd = req->fd; + int result; + + VERIFY_FD(fd, req); + + result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } +} + + +static void fs__fsync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__fdatasync(uv_fs_t* req) { + fs__sync_impl(req); +} + + +static void fs__ftruncate(uv_fs_t* req) { + int fd = req->fd; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + eof_info.EndOfFile.QuadPart = req->offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } +} + + +static void fs__sendfile(uv_fs_t* req) { + int fd_in = req->fd, fd_out = req->fd_out; + size_t length = req->length; + int64_t offset = req->offset; + const size_t max_buf_size = 65536; + size_t buf_size = length < max_buf_size ? length : max_buf_size; + int n, result = 0; + int64_t result_offset = 0; + char* buf = (char*) malloc(buf_size); + if (!buf) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (offset != -1) { + result_offset = _lseeki64(fd_in, offset, SEEK_SET); + } + + if (result_offset == -1) { + result = -1; + } else { + while (length > 0) { + n = _read(fd_in, buf, length < buf_size ? length : buf_size); + if (n == 0) { + break; + } else if (n == -1) { + result = -1; + break; + } + + length -= n; + + n = _write(fd_out, buf, n); + if (n == -1) { + result = -1; + break; + } + + result += n; + } + } + + free(buf); + + SET_REQ_RESULT(req, result); +} + + +static void fs__chmod(uv_fs_t* req) { + int result = _wchmod(req->pathw, req->mode); + SET_REQ_RESULT(req, result); +} + + +static void fs__fchmod(uv_fs_t* req) { + int fd = req->fd; + HANDLE handle; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_BASIC_INFORMATION file_info; + + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + nt_status = pNtQueryInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + if (req->mode & _S_IWRITE) { + file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + } else { + file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + } + + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; + } + + SET_REQ_SUCCESS(req); +} + + +INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { + FILETIME filetime_a, filetime_m; + + TIME_T_TO_FILETIME((time_t) atime, &filetime_a); + TIME_T_TO_FILETIME((time_t) mtime, &filetime_m); + + if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + return -1; + } + + return 0; +} + + +static void fs__utime(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->pathw, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__utime_handle(handle, req->atime, req->mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + CloseHandle(handle); + + req->result = 0; +} + + +static void fs__futime(uv_fs_t* req) { + int fd = req->fd; + HANDLE handle; + VERIFY_FD(fd, req); + + handle = uv__get_osfhandle(fd); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); + return; + } + + if (fs__utime_handle(handle, req->atime, req->mtime) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + req->result = 0; +} + + +static void fs__link(uv_fs_t* req) { + DWORD r = CreateHardLinkW(req->new_pathw, req->pathw, NULL); + if (r == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + req->result = 0; + } +} + + +static void fs__create_junction(uv_fs_t* req, const WCHAR* path, + const WCHAR* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + WCHAR* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + // Do a pessimistic calculation of the required buffer size + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(WCHAR) + + 2 * (target_len + 2) * sizeof(WCHAR); + + // Allocate the buffer + buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + // Grab a pointer to the part of the buffer where filenames go + path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + // Copy the substitute (internal) target path + start = path_buf_len; + + wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + // Set the info about the substitute name + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); + + // Insert null terminator + path_buf[path_buf_len++] = L'\0'; + + // Copy the print name of the target path + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + // Set the info about the print name + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR); + + // Insert another null terminator + path_buf[path_buf_len++] = L'\0'; + + // Calculate how much buffer space was actually used + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(WCHAR); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + // Put general info in the data buffer + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + // Create a new directory + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + // Open the directory + handle = CreateFileW(new_path, + GENERIC_ALL, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Create the actual reparse point + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Clean up + CloseHandle(handle); + free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + +static void fs__symlink(uv_fs_t* req) { + WCHAR* pathw = req->pathw; + WCHAR* new_pathw = req->new_pathw; + int flags = req->file_flags; + int result; + + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, pathw, new_pathw); + } else if (pCreateSymbolicLinkW) { + result = pCreateSymbolicLinkW(new_pathw, + pathw, + flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; + if (result == -1) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } else { + SET_REQ_RESULT(req, result); + } + } else { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + } +} + + +static void fs__readlink(uv_fs_t* req) { + HANDLE handle; + + handle = CreateFileW(req->pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); + + CloseHandle(handle); +} + + + +static void fs__chown(uv_fs_t* req) { + req->result = 0; +} + + +static void fs__fchown(uv_fs_t* req) { + req->result = 0; +} + + +static DWORD WINAPI uv_fs_thread_proc(void* parameter) { + uv_fs_t* req = (uv_fs_t*) parameter; + uv_loop_t* loop = req->loop; + + assert(req != NULL); + assert(req->type == UV_FS); + +#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break; + switch (req->fs_type) { + XX(OPEN, open) + XX(CLOSE, close) + XX(READ, read) + XX(WRITE, write) + XX(SENDFILE, sendfile) + XX(STAT, stat) + XX(LSTAT, lstat) + XX(FSTAT, fstat) + XX(FTRUNCATE, ftruncate) + XX(UTIME, utime) + XX(FUTIME, futime) + XX(CHMOD, chmod) + XX(FCHMOD, fchmod) + XX(FSYNC, fsync) + XX(FDATASYNC, fdatasync) + XX(UNLINK, unlink) + XX(RMDIR, rmdir) + XX(MKDIR, mkdir) + XX(RENAME, rename) + XX(READDIR, readdir) + XX(LINK, link) + XX(SYMLINK, symlink) + XX(READLINK, readlink) + XX(CHOWN, chown) + XX(FCHOWN, fchown); + default: + assert(!"bad uv_fs_type"); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + int mode, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_OPEN, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->file_flags = flags; + req->mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__open(req); + return req->result; + } +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_CLOSE, cb); + req->fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__close(req); + return req->result; + } +} + + +int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, + size_t length, int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_READ, cb); + + req->fd = fd; + req->buf = buf; + req->length = length; + req->offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__read(req); + return req->result; + } +} + + +int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, const void* buf, + size_t length, int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + + req->fd = fd; + req->buf = (void*) buf; + req->length = length; + req->offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__write(req); + return req->result; + } +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UNLINK, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__unlink(req); + return req->result; + } +} + + +int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDIR, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdir(req); + return req->result; + } +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RMDIR, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rmdir(req); + return req->result; + } +} + + +int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_READDIR, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__readdir(req); + return req->result; + } +} + + +int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LINK, cb); + + err = fs__capture_path(loop, req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__link(req); + return req->result; + } +} + + +int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, int flags, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb); + + err = fs__capture_path(loop, req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->file_flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__symlink(req); + return req->result; + } +} + + +int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_READLINK, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__readlink(req); + return req->result; + } +} + + +int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chown(req); + return req->result; + } +} + + +int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchown(req); + return req->result; + } +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_STAT, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__stat(req); + return req->result; + } +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__lstat(req); + return req->result; + } +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + req->fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fstat(req); + return req->result; + } +} + + +int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, + const char* new_path, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_RENAME, cb); + + err = fs__capture_path(loop, req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__rename(req); + return req->result; + } +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FSYNC, cb); + req->fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fsync(req); + return req->result; + } +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb); + req->fd = fd; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fdatasync(req); + return req->result; + } +} + + +int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, + int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb); + + req->fd = fd; + req->offset = offset; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__ftruncate(req); + return req->result; + } +} + + + +int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, + uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb); + + req->fd = fd_in; + req->fd_out = fd_out; + req->offset = in_offset; + req->length = length; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__sendfile(req); + return req->result; + } +} + + +int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_CHMOD, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__chmod(req); + return req->result; + } +} + + +int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, + uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb); + + req->fd = fd; + req->mode = mode; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__fchmod(req); + return req->result; + } +} + + +int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, + double mtime, uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_UTIME, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->atime = atime; + req->mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__utime(req); + return req->result; + } +} + + +int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, + double mtime, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_FUTIME, cb); + + req->fd = fd; + req->atime = atime; + req->mtime = mtime; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__futime(req); + return req->result; + } +} + + +void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { + assert(req->cb); + uv__req_unregister(loop, req); + req->cb(req); +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->flags & UV_FS_CLEANEDUP) + return; + + if (req->flags & UV_FS_FREE_PATHS) + free(req->pathw); + + if (req->flags & UV_FS_FREE_PTR) + free(req->ptr); + + req->path = NULL; + req->pathw = NULL; + req->new_pathw = NULL; + req->ptr = NULL; + + req->flags |= UV_FS_CLEANEDUP; +} + diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c new file mode 100644 index 0000000000..fb4ab0a602 --- /dev/null +++ b/src/win/getaddrinfo.c @@ -0,0 +1,344 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + + +/* + * MinGW is missing this + */ +#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + WCHAR* ai_canonname; + struct sockaddr* ai_addr; + struct addrinfoW* ai_next; + } ADDRINFOW, *PADDRINFOW; + + DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node, + const WCHAR* service, + const ADDRINFOW* hints, + PADDRINFOW* result); + + DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); +#endif + + +/* adjust size value to be multiple of 4. Use to keep pointer aligned */ +/* Do we need different versions of this for different architectures? */ +#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) + + +/* getaddrinfo worker thread implementation */ +static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { + uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; + uv_loop_t* loop = req->loop; + int ret; + + assert(req != NULL); + + /* call OS function on this thread */ + ret = GetAddrInfoW(req->node, + req->service, + req->hints, + &req->res); + req->retcode = ret; + + /* post getaddrinfo completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +/* + * Called from uv_run when complete. Call user specified callback + * then free returned addrinfo + * Returned addrinfo strings are converted from UTF-16 to UTF-8. + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { + int addrinfo_len = 0; + int name_len = 0; + size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); + struct addrinfoW* addrinfow_ptr; + struct addrinfo* addrinfo_ptr; + char* alloc_ptr = NULL; + char* cur_ptr = NULL; + int err = 0; + + /* release input parameter memory */ + if (req->alloc != NULL) { + free(req->alloc); + req->alloc = NULL; + } + + if (req->retcode == 0) { + /* convert addrinfoW to addrinfo */ + /* first calculate required length */ + addrinfow_ptr = req->res; + while (addrinfow_ptr != NULL) { + addrinfo_len += addrinfo_struct_len + + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + if (name_len == 0) { + /* FIXME(bnoordhuis) Retain GetLastError(). */ + err = UV_EAI_SYSTEM; + goto complete; + } + addrinfo_len += ALIGNED_SIZE(name_len); + } + addrinfow_ptr = addrinfow_ptr->ai_next; + } + + /* allocate memory for addrinfo results */ + alloc_ptr = (char*)malloc(addrinfo_len); + + /* do conversions */ + if (alloc_ptr != NULL) { + cur_ptr = alloc_ptr; + addrinfow_ptr = req->res; + + while (addrinfow_ptr != NULL) { + /* copy addrinfo struct data */ + assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); + addrinfo_ptr = (struct addrinfo*)cur_ptr; + addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; + addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; + addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; + addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; + addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; + addrinfo_ptr->ai_canonname = NULL; + addrinfo_ptr->ai_addr = NULL; + addrinfo_ptr->ai_next = NULL; + + cur_ptr += addrinfo_struct_len; + + /* copy sockaddr */ + if (addrinfo_ptr->ai_addrlen > 0) { + assert(cur_ptr + addrinfo_ptr->ai_addrlen <= + alloc_ptr + addrinfo_len); + memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); + addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; + cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); + } + + /* convert canonical name to UTF-8 */ + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, + -1, + NULL, + 0); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len); + assert(name_len > 0); + addrinfo_ptr->ai_canonname = cur_ptr; + cur_ptr += ALIGNED_SIZE(name_len); + } + assert(cur_ptr <= alloc_ptr + addrinfo_len); + + /* set next ptr */ + addrinfow_ptr = addrinfow_ptr->ai_next; + if (addrinfow_ptr != NULL) { + addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; + } + } + } else { + err = UV_EAI_MEMORY; + } + } else { + /* GetAddrInfo failed */ + err = uv__getaddrinfo_translate_error(req->retcode); + } + + /* return memory to system */ + if (req->res != NULL) { + FreeAddrInfoW(req->res); + req->res = NULL; + } + +complete: + uv__req_unregister(loop, req); + + /* finally do callback with converted result */ + req->getaddrinfo_cb(req, err, (struct addrinfo*)alloc_ptr); +} + + +void uv_freeaddrinfo(struct addrinfo* ai) { + char* alloc_ptr = (char*)ai; + + /* release copied result memory */ + if (alloc_ptr != NULL) { + free(alloc_ptr); + } +} + + +/* + * Entry point for getaddrinfo + * we convert the UTF-8 strings to UNICODE + * and save the UNICODE string pointers in the req + * We also copy hints so that caller does not need to keep memory until the + * callback. + * return 0 if a callback will be made + * return error code if validation fails + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +int uv_getaddrinfo(uv_loop_t* loop, + uv_getaddrinfo_t* req, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints) { + int nodesize = 0; + int servicesize = 0; + int hintssize = 0; + char* alloc_ptr = NULL; + int err; + + if (req == NULL || getaddrinfo_cb == NULL || + (node == NULL && service == NULL)) { + err = WSAEINVAL; + goto error; + } + + uv_req_init(loop, (uv_req_t*)req); + + req->getaddrinfo_cb = getaddrinfo_cb; + req->res = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR)); + if (nodesize == 0) { + err = GetLastError(); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * + sizeof(WCHAR)); + if (servicesize == 0) { + err = GetLastError(); + goto error; + } + } + if (hints != NULL) { + hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); + } + + /* allocate memory for inputs, and partition it as needed */ + alloc_ptr = (char*)malloc(nodesize + servicesize + hintssize); + if (!alloc_ptr) { + err = WSAENOBUFS; + goto error; + } + + /* save alloc_ptr now so we can free if error */ + req->alloc = (void*)alloc_ptr; + + /* convert node string to UTF16 into allocated memory and save pointer in */ + /* the reques. */ + if (node != NULL) { + req->node = (WCHAR*)alloc_ptr; + if (uv_utf8_to_utf16(node, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += nodesize; + } else { + req->node = NULL; + } + + /* convert service string to UTF16 into allocated memory and save pointer */ + /* in the req. */ + if (service != NULL) { + req->service = (WCHAR*)alloc_ptr; + if (uv_utf8_to_utf16(service, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { + err = GetLastError(); + goto error; + } + alloc_ptr += servicesize; + } else { + req->service = NULL; + } + + /* copy hints to allocated memory and save pointer in req */ + if (hints != NULL) { + req->hints = (struct addrinfoW*)alloc_ptr; + req->hints->ai_family = hints->ai_family; + req->hints->ai_socktype = hints->ai_socktype; + req->hints->ai_protocol = hints->ai_protocol; + req->hints->ai_flags = hints->ai_flags; + req->hints->ai_addrlen = 0; + req->hints->ai_canonname = NULL; + req->hints->ai_addr = NULL; + req->hints->ai_next = NULL; + } else { + req->hints = NULL; + } + + /* Ask thread to run. Treat this as a long operation */ + if (QueueUserWorkItem(&getaddrinfo_thread_proc, + req, + WT_EXECUTELONGFUNCTION) == 0) { + err = GetLastError(); + goto error; + } + + uv__req_register(loop, req); + + return 0; + +error: + if (req != NULL && req->alloc != NULL) { + free(req->alloc); + } + return uv_translate_sys_error(err); +} diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h new file mode 100644 index 0000000000..5776eb7f76 --- /dev/null +++ b/src/win/handle-inl.h @@ -0,0 +1,179 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_HANDLE_INL_H_ +#define UV_WIN_HANDLE_INL_H_ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV__HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + + +#define DECREASE_PENDING_REQ_COUNT(handle) \ + do { \ + assert(handle->reqs_pending > 0); \ + handle->reqs_pending--; \ + \ + if (handle->flags & UV__HANDLE_CLOSING && \ + handle->reqs_pending == 0) { \ + uv_want_endgame(loop, (uv_handle_t*)handle); \ + } \ + } while (0) + + +#define uv__handle_closing(handle) \ + do { \ + assert(!((handle)->flags & UV__HANDLE_CLOSING)); \ + \ + if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \ + ((handle)->flags & UV__HANDLE_REF))) \ + uv__active_handle_add((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV__HANDLE_CLOSING; \ + (handle)->flags &= ~UV__HANDLE_ACTIVE; \ + } while (0) + + +#define uv__handle_close(handle) \ + do { \ + QUEUE_REMOVE(&(handle)->handle_queue); \ + uv__active_handle_rm((uv_handle_t*) (handle)); \ + \ + (handle)->flags |= UV_HANDLE_CLOSED; \ + \ + if ((handle)->close_cb) \ + (handle)->close_cb((uv_handle_t*) (handle)); \ + } while (0) + + +INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { + handle->flags |= UV_HANDLE_ENDGAME_QUEUED; + + handle->endgame_next = loop->endgame_handles; + loop->endgame_handles = handle; + } +} + + +INLINE static void uv_process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv_tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv_pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv_tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv_udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv_timer_endgame(loop, (uv_timer_t*) handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv_loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv_async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + + case UV_PROCESS: + uv_process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + case UV_FS_POLL: + uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + +INLINE static HANDLE uv__get_osfhandle(int fd) +{ + /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */ + /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */ + /* for invalid FDs in release builds (or if you let the assert continue). */ + /* So this wrapper function disables asserts when calling _get_osfhandle. */ + + HANDLE handle; + UV_BEGIN_DISABLE_CRT_ASSERT(); + handle = (HANDLE) _get_osfhandle(fd); + UV_END_DISABLE_CRT_ASSERT(); + return handle; +} + +#endif /* UV_WIN_HANDLE_INL_H_ */ diff --git a/src/win/handle.c b/src/win/handle.c new file mode 100644 index 0000000000..72b49d9790 --- /dev/null +++ b/src/win/handle.c @@ -0,0 +1,154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +uv_handle_type uv_guess_handle(uv_file file) { + HANDLE handle; + DWORD mode; + + if (file < 0) { + return UV_UNKNOWN_HANDLE; + } + + handle = uv__get_osfhandle(file); + + switch (GetFileType(handle)) { + case FILE_TYPE_CHAR: + if (GetConsoleMode(handle, &mode)) { + return UV_TTY; + } else { + return UV_FILE; + } + + case FILE_TYPE_PIPE: + return UV_NAMED_PIPE; + + case FILE_TYPE_DISK: + return UV_FILE; + + default: + return UV_UNKNOWN_HANDLE; + } +} + + +int uv_is_active(const uv_handle_t* handle) { + return (handle->flags & UV__HANDLE_ACTIVE) && + !(handle->flags & UV__HANDLE_CLOSING); +} + + +void uv_close(uv_handle_t* handle, uv_close_cb cb) { + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV__HANDLE_CLOSING) { + assert(0); + return; + } + + handle->close_cb = cb; + + /* Handle-specific close actions */ + switch (handle->type) { + case UV_TCP: + uv_tcp_close(loop, (uv_tcp_t*)handle); + return; + + case UV_NAMED_PIPE: + uv_pipe_close(loop, (uv_pipe_t*) handle); + return; + + case UV_TTY: + uv_tty_close((uv_tty_t*) handle); + return; + + case UV_UDP: + uv_udp_close(loop, (uv_udp_t*) handle); + return; + + case UV_POLL: + uv_poll_close(loop, (uv_poll_t*) handle); + return; + + case UV_TIMER: + uv_timer_stop((uv_timer_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_PREPARE: + uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_CHECK: + uv_check_stop((uv_check_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_IDLE: + uv_idle_stop((uv_idle_t*)handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + case UV_ASYNC: + uv_async_close(loop, (uv_async_t*) handle); + return; + + case UV_SIGNAL: + uv_signal_close(loop, (uv_signal_t*) handle); + return; + + case UV_PROCESS: + uv_process_close(loop, (uv_process_t*) handle); + return; + + case UV_FS_EVENT: + uv_fs_event_close(loop, (uv_fs_event_t*) handle); + return; + + case UV_FS_POLL: + uv__fs_poll_close((uv_fs_poll_t*) handle); + uv__handle_closing(handle); + uv_want_endgame(loop, handle); + return; + + default: + /* Not supported */ + abort(); + } +} + + +int uv_is_closing(const uv_handle_t* handle) { + return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); +} diff --git a/src/win/internal.h b/src/win/internal.h new file mode 100644 index 0000000000..cf6c85846c --- /dev/null +++ b/src/win/internal.h @@ -0,0 +1,379 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_INTERNAL_H_ +#define UV_WIN_INTERNAL_H_ + +#include "uv.h" +#include "../uv-common.h" + +#include "tree.h" +#include "winapi.h" +#include "winsock.h" + +#ifdef _MSC_VER +# define INLINE __inline +#else +# define INLINE inline +#endif + + +#ifdef _DEBUG +extern __declspec( thread ) int uv__crt_assert_enabled; + +#define UV_BEGIN_DISABLE_CRT_ASSERT() \ + { \ + int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \ + uv__crt_assert_enabled = FALSE; + + +#define UV_END_DISABLE_CRT_ASSERT() \ + uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \ + } + +#else +#define UV_BEGIN_DISABLE_CRT_ASSERT() +#define UV_END_DISABLE_CRT_ASSERT() +#endif + +/* + * Handles + * (also see handle-inl.h) + */ + +/* Used by all handles. */ +#define UV_HANDLE_CLOSED 0x00000002 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000004 +#define UV_HANDLE_ACTIVE 0x00000010 + +/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ +/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ +/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */ +/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ +#define UV_HANDLE_READING 0x00000100 +#define UV_HANDLE_BOUND 0x00000200 +#define UV_HANDLE_BIND_ERROR 0x00000400 +#define UV_HANDLE_LISTENING 0x00000800 +#define UV_HANDLE_CONNECTION 0x00001000 +#define UV_HANDLE_CONNECTED 0x00002000 +#define UV_HANDLE_READABLE 0x00008000 +#define UV_HANDLE_WRITABLE 0x00010000 +#define UV_HANDLE_READ_PENDING 0x00020000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 +#define UV_HANDLE_ZERO_READ 0x00080000 +#define UV_HANDLE_EMULATE_IOCP 0x00100000 +#define UV_HANDLE_BLOCKING_WRITES 0x00200000 + +/* Only used by uv_tcp_t handles. */ +#define UV_HANDLE_IPV6 0x01000000 +#define UV_HANDLE_TCP_NODELAY 0x02000000 +#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 +#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 +#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 +#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 + +/* Only used by uv_pipe_t handles. */ +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 +#define UV_HANDLE_PIPESERVER 0x02000000 + +/* Only used by uv_tty_t handles. */ +#define UV_HANDLE_TTY_READABLE 0x01000000 +#define UV_HANDLE_TTY_RAW 0x02000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 + +/* Only used by uv_poll_t handles. */ +#define UV_HANDLE_POLL_SLOW 0x02000000 + + +/* + * Requests: see req-inl.h + */ + + +/* + * Streams: see stream-inl.h + */ + + +/* + * TCP + */ +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req); +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req); +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req); + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); + +int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, + int tcp_connection); + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info); + + +/* + * UDP + */ +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req); + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); + + +/* + * Pipes + */ +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize); + +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); +int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read2_cb read_cb); +int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, + uv_write_cb cb); + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req); +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req); +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req); +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req); +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req); + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + + +/* + * TTY + */ +void uv_console_init(); + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb); +int uv_tty_read_stop(uv_tty_t* handle); +int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); +void uv_tty_close(uv_tty_t* handle); + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req); +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req); +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req); +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req); + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); + + +/* + * Poll watchers + */ +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req); + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); + + +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv_get_poll_timeout(uv_loop_t* loop); +void uv__time_forward(uv_loop_t* loop, uint64_t msecs); +void uv_process_timers(uv_loop_t* loop); + + +/* + * Loop watchers + */ +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); + +void uv_prepare_invoke(uv_loop_t* loop); +void uv_check_invoke(uv_loop_t* loop); +void uv_idle_invoke(uv_loop_t* loop); + +void uv__once_init(); + + +/* + * Async watcher + */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); +void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); + +void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, + uv_req_t* req); + + +/* + * Signal watcher + */ +void uv_signals_init(); +int uv__signal_dispatch(int signum); + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req); + + +/* + * Spawn + */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); +void uv_process_close(uv_loop_t* loop, uv_process_t* handle); +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); + + +/* + * Error + */ +int uv_translate_sys_error(int sys_errno); + + +/* + * Getaddrinfo + */ +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req); + + +/* + * FS + */ +void uv_fs_init(); +void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req); + + +/* + * Threadpool + */ +void uv_process_work_req(uv_loop_t* loop, uv_work_t* req); + + +/* + * FS Event + */ +void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, + uv_fs_event_t* handle); +void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); +void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); + + +/* + * Stat poller. + */ +void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); + + +/* + * Utilities. + */ +void uv__util_init(); + +int uv_parent_pid(); +void uv_fatal_error(const int errorno, const char* syscall); + + +/* + * Process stdio handles. + */ +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr); +void uv__stdio_destroy(BYTE* buffer); +void uv__stdio_noinherit(BYTE* buffer); +int uv__stdio_verify(BYTE* buffer, WORD size); +WORD uv__stdio_size(BYTE* buffer); +HANDLE uv__stdio_handle(BYTE* buffer, int fd); + + +/* + * Winapi and ntapi utility functions + */ +void uv_winapi_init(); + + +/* + * Winsock utility functions + */ +void uv_winsock_init(); + +int uv_ntstatus_to_winsock_error(NTSTATUS status); + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); + +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped); + +/* Whether there are any non-IFS LSPs stacked on TCP */ +extern int uv_tcp_non_ifs_lsp_ipv4; +extern int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +extern struct sockaddr_in uv_addr_ip4_any_; +extern struct sockaddr_in6 uv_addr_ip6_any_; + +#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/loop-watcher.c b/src/win/loop-watcher.c new file mode 100644 index 0000000000..6dbc861edd --- /dev/null +++ b/src/win/loop-watcher.c @@ -0,0 +1,124 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_close(handle); + } +} + + +#define UV_LOOP_WATCHER_DEFINE(name, NAME) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + uv_loop_t* loop = handle->loop; \ + uv_##name##_t* old_head; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (handle->flags & UV_HANDLE_ACTIVE) \ + return 0; \ + \ + if (cb == NULL) \ + return UV_EINVAL; \ + \ + old_head = loop->name##_handles; \ + \ + handle->name##_next = old_head; \ + handle->name##_prev = NULL; \ + \ + if (old_head) { \ + old_head->name##_prev = handle; \ + } \ + \ + loop->name##_handles = handle; \ + \ + handle->name##_cb = cb; \ + handle->flags |= UV_HANDLE_ACTIVE; \ + uv__handle_start(handle); \ + \ + return 0; \ + } \ + \ + \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + uv_loop_t* loop = handle->loop; \ + \ + assert(handle->type == UV_##NAME); \ + \ + if (!(handle->flags & UV_HANDLE_ACTIVE)) \ + return 0; \ + \ + /* Update loop head if needed */ \ + if (loop->name##_handles == handle) { \ + loop->name##_handles = handle->name##_next; \ + } \ + \ + /* Update the iterator-next pointer of needed */ \ + if (loop->next_##name##_handle == handle) { \ + loop->next_##name##_handle = handle->name##_next; \ + } \ + \ + if (handle->name##_prev) { \ + handle->name##_prev->name##_next = handle->name##_next; \ + } \ + if (handle->name##_next) { \ + handle->name##_next->name##_prev = handle->name##_prev; \ + } \ + \ + handle->flags &= ~UV_HANDLE_ACTIVE; \ + uv__handle_stop(handle); \ + \ + return 0; \ + } \ + \ + \ + void uv_##name##_invoke(uv_loop_t* loop) { \ + uv_##name##_t* handle; \ + \ + (loop)->next_##name##_handle = (loop)->name##_handles; \ + \ + while ((loop)->next_##name##_handle != NULL) { \ + handle = (loop)->next_##name##_handle; \ + (loop)->next_##name##_handle = handle->name##_next; \ + \ + handle->name##_cb(handle, 0); \ + } \ + } + +UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) +UV_LOOP_WATCHER_DEFINE(check, CHECK) +UV_LOOP_WATCHER_DEFINE(idle, IDLE) diff --git a/src/win/pipe.c b/src/win/pipe.c new file mode 100644 index 0000000000..f3d3110d31 --- /dev/null +++ b/src/win/pipe.c @@ -0,0 +1,1747 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* A zero-size buffer for use by uv_pipe_read */ +static char uv_zero_[] = ""; + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +/* The timeout that the pipe will wait for the remote end to write data */ +/* when the local ends wants to shut it down. */ +static const int64_t eof_timeout = 50; /* ms */ + +static const int default_pending_pipe_instances = 4; + +/* IPC protocol flags. */ +#define UV_IPC_RAW_DATA 0x0001 +#define UV_IPC_TCP_SERVER 0x0002 +#define UV_IPC_TCP_CONNECTION 0x0004 + +/* IPC frame header. */ +typedef struct { + int flags; + uint64_t raw_data_length; +} uv_ipc_frame_header_t; + +/* IPC frame, which contains an imported TCP socket stream. */ +typedef struct { + uv_ipc_frame_header_t header; + WSAPROTOCOL_INFOW socket_info; +} uv_ipc_frame_uv_stream; + +static void eof_timer_init(uv_pipe_t* pipe); +static void eof_timer_start(uv_pipe_t* pipe); +static void eof_timer_stop(uv_pipe_t* pipe); +static void eof_timer_cb(uv_timer_t* timer, int status); +static void eof_timer_destroy(uv_pipe_t* pipe); +static void eof_timer_close_cb(uv_handle_t* handle); + + +static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { + _snprintf(name, size, "\\\\.\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); +} + + +int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { + uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + + handle->reqs_pending = 0; + handle->handle = INVALID_HANDLE_VALUE; + handle->name = NULL; + handle->ipc_pid = 0; + handle->remaining_ipc_rawdata_bytes = 0; + handle->pending_ipc_info.socket_info = NULL; + handle->pending_ipc_info.tcp_connection = 0; + handle->ipc = ipc; + handle->non_overlapped_writes_tail = NULL; + + uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req); + + return 0; +} + + +static void uv_pipe_connection_init(uv_pipe_t* handle) { + uv_connection_init((uv_stream_t*) handle); + handle->read_req.data = handle; + handle->eof_timer = NULL; +} + + +static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) { + HANDLE pipeHandle; + + /* + * Assume that we have a duplex pipe first, so attempt to + * connect with GENERIC_READ | GENERIC_WRITE. + */ + pipeHandle = CreateFileW(name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + return pipeHandle; + } + + /* + * If the pipe is not duplex CreateFileW fails with + * ERROR_ACCESS_DENIED. In that case try to connect + * as a read-only or write-only. + */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_READ | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_READABLE; + return pipeHandle; + } + } + + if (GetLastError() == ERROR_ACCESS_DENIED) { + pipeHandle = CreateFileW(name, + GENERIC_WRITE | FILE_READ_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + *duplex_flags = UV_HANDLE_WRITABLE; + return pipeHandle; + } + } + + return INVALID_HANDLE_VALUE; +} + + +int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, + char* name, size_t nameSize) { + HANDLE pipeHandle; + int err; + char* ptr = (char*)handle; + + for (;;) { + uv_unique_pipe_name(ptr, name, nameSize); + + pipeHandle = CreateNamedPipeA(name, + access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, + NULL); + + if (pipeHandle != INVALID_HANDLE_VALUE) { + /* No name collisions. We're done. */ + break; + } + + err = GetLastError(); + if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) { + goto error; + } + + /* Pipe name collision. Increment the pointer and try again. */ + ptr++; + } + + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + err = GetLastError(); + goto error; + } + + uv_pipe_connection_init(handle); + handle->handle = pipeHandle; + + return 0; + + error: + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + return err; +} + + +static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle, + HANDLE pipeHandle, DWORD duplex_flags) { + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_MODE_INFORMATION mode_info; + DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; + + if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) { + /* If this returns ERROR_INVALID_PARAMETER we probably opened something */ + /* that is not a pipe. */ + if (GetLastError() == ERROR_INVALID_PARAMETER) { + SetLastError(WSAENOTSOCK); + } + return -1; + } + + /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */ + nt_status = pNtQueryInformationFile(pipeHandle, + &io_status, + &mode_info, + sizeof(mode_info), + FileModeInformation); + if (nt_status != STATUS_SUCCESS) { + return -1; + } + + if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || + mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { + /* Non-overlapped pipe. */ + handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; + } else { + /* Overlapped pipe. Try to associate with IOCP. */ + if (CreateIoCompletionPort(pipeHandle, + loop->iocp, + (ULONG_PTR)handle, + 0) == NULL) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } + } + + handle->handle = pipeHandle; + handle->flags |= duplex_flags; + + return 0; +} + + +static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_shutdown_t* req; + + req = (uv_shutdown_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + FlushFileBuffers(handle->handle); + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { + int err; + DWORD result; + uv_shutdown_t* req; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_PIPE_LOCAL_INFORMATION pipe_info; + + if ((handle->flags & UV_HANDLE_CONNECTION) && + handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + req = handle->shutdown_req; + + /* Clear the shutdown_req field so we don't go here again. */ + handle->shutdown_req = NULL; + + if (handle->flags & UV__HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + + /* Already closing. Cancel the shutdown. */ + if (req->cb) { + req->cb(req, UV_ECANCELED); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + /* Try to avoid flushing the pipe buffer in the thread pool. */ + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &pipe_info, + sizeof pipe_info, + FilePipeLocalInformation); + + if (nt_status != STATUS_SUCCESS) { + /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = pRtlNtStatusToDosError(nt_status); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { + /* Short-circuit, no need to call FlushFileBuffers. */ + uv_insert_pending_req(loop, (uv_req_t*) req); + return; + } + + /* Run FlushFileBuffers in the thread pool. */ + result = QueueUserWorkItem(pipe_shutdown_thread_proc, + req, + WT_EXECUTELONGFUNCTION); + if (result) { + return; + + } else { + /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ + if (req->cb) { + err = GetLastError(); + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (handle->flags & UV_HANDLE_CONNECTION) { + if (handle->pending_ipc_info.socket_info) { + free(handle->pending_ipc_info.socket_info); + handle->pending_ipc_info.socket_info = NULL; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + assert(handle->accept_reqs); + free(handle->accept_reqs); + handle->accept_reqs = NULL; + } + + uv__handle_close(handle); + } +} + + +void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { + handle->pending_instances = count; + handle->flags |= UV_HANDLE_PIPESERVER; +} + + +/* Creates a pipe server. */ +int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + uv_loop_t* loop = handle->loop; + int i, err, nameSize; + uv_pipe_accept_t* req; + + if (handle->flags & UV_HANDLE_BOUND) { + return UV_EINVAL; + } + + if (!name) { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + handle->pending_instances = default_pending_pipe_instances; + } + + handle->accept_reqs = (uv_pipe_accept_t*) + malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances); + if (!handle->accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + for (i = 0; i < handle->pending_instances; i++) { + req = &handle->accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->data = handle; + req->pipeHandle = INVALID_HANDLE_VALUE; + req->next_pending = NULL; + } + + /* Convert name to UTF16. */ + nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + return uv_translate_sys_error(GetLastError()); + } + + /* + * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. + * If this fails then there's already a pipe server for the given pipe name. + */ + handle->accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (handle->accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ + } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { + err = WSAEACCES; /* Translates to UV_EACCES. */ + } + goto error; + } + + if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle, 0)) { + err = GetLastError(); + goto error; + } + + handle->pending_accepts = NULL; + handle->flags |= UV_HANDLE_PIPESERVER; + handle->flags |= UV_HANDLE_BOUND; + + return 0; + +error: + if (handle->name) { + free(handle->name); + handle->name = NULL; + } + + if (handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->accept_reqs[0].pipeHandle); + handle->accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE; + } + + return uv_translate_sys_error(err); +} + + +static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { + uv_loop_t* loop; + uv_pipe_t* handle; + uv_connect_t* req; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + req = (uv_connect_t*) parameter; + assert(req); + handle = (uv_pipe_t*) req->handle; + assert(handle); + loop = handle->loop; + assert(loop); + + /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ + /* We wait for the pipe to become available with WaitNamedPipe. */ + while (WaitNamedPipeW(handle->name, 30000)) { + /* The pipe is now available, try to connect. */ + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle != INVALID_HANDLE_VALUE) { + break; + } + + SwitchToThread(); + } + + if (pipeHandle != INVALID_HANDLE_VALUE && + !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, + const char* name, uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + int err, nameSize; + HANDLE pipeHandle = INVALID_HANDLE_VALUE; + DWORD duplex_flags; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Convert name to UTF16. */ + nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + err = GetLastError(); + goto error; + } + + pipeHandle = open_named_pipe(handle->name, &duplex_flags); + if (pipeHandle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_PIPE_BUSY) { + /* Wait for the server to make a pipe instance available. */ + if (!QueueUserWorkItem(&pipe_connect_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + err = GetLastError(); + goto error; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + + return; + } + + err = GetLastError(); + goto error; + } + + assert(pipeHandle != INVALID_HANDLE_VALUE); + + if (uv_set_pipe_handle(loop, + (uv_pipe_t*) req->handle, + pipeHandle, + duplex_flags)) { + err = GetLastError(); + goto error; + } + + SET_REQ_SUCCESS(req); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; + +error: + if (handle->name) { + free(handle->name); + handle->name = NULL; + } + + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + } + + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, err); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + return; +} + + +/* Cleans up uv_pipe_t (server or connection) and all resources associated */ +/* with it. */ +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { + int i; + HANDLE pipeHandle; + + if (handle->name) { + free(handle->name); + handle->name = NULL; + } + + if (handle->flags & UV_HANDLE_PIPESERVER) { + for (i = 0; i < handle->pending_instances; i++) { + pipeHandle = handle->accept_reqs[i].pipeHandle; + if (pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(pipeHandle); + handle->accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE; + } + } + } + + if (handle->flags & UV_HANDLE_CONNECTION) { + handle->flags &= ~UV_HANDLE_WRITABLE; + eof_timer_destroy(handle); + } + + if ((handle->flags & UV_HANDLE_CONNECTION) + && handle->handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->handle); + handle->handle = INVALID_HANDLE_VALUE; + } +} + + +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); +} + + +static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, + uv_pipe_accept_t* req, BOOL firstInstance) { + assert(handle->flags & UV_HANDLE_LISTENING); + + if (!firstInstance) { + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + + req->pipeHandle = CreateNamedPipeW(handle->name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); + + if (req->pipeHandle == INVALID_HANDLE_VALUE) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + if (uv_set_pipe_handle(loop, handle, req->pipeHandle, 0)) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + } + + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + + /* Prepare the overlapped structure. */ + memset(&(req->overlapped), 0, sizeof(req->overlapped)); + + if (!ConnectNamedPipe(req->pipeHandle, &req->overlapped) && + GetLastError() != ERROR_IO_PENDING) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SET_REQ_SUCCESS(req); + } else { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + } + uv_insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; + } + + handle->reqs_pending++; +} + + +int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { + uv_loop_t* loop = server->loop; + uv_pipe_t* pipe_client; + uv_pipe_accept_t* req; + + if (server->ipc) { + if (!server->pending_ipc_info.socket_info) { + /* No valid pending sockets. */ + return WSAEWOULDBLOCK; + } + + return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, + server->pending_ipc_info.tcp_connection); + } else { + pipe_client = (uv_pipe_t*)client; + + /* Find a connection instance that has been connected, but not yet */ + /* accepted. */ + req = server->pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + /* Initialize the client handle and copy the pipeHandle to the client */ + uv_pipe_connection_init(pipe_client); + pipe_client->handle = req->pipeHandle; + pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + + /* Prepare the req to pick up a new connection */ + server->pending_accepts = req->next_pending; + req->next_pending = NULL; + req->pipeHandle = INVALID_HANDLE_VALUE; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, server, req, FALSE); + } + } + + return 0; +} + + +/* Starts listening for connections for the given pipe. */ +int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + int i; + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return WSAEINVAL; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { + return ERROR_NOT_SUPPORTED; + } + + handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->connection_cb = cb; + + /* First pipe handle should have already been created in uv_pipe_bind */ + assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); + + for (i = 0; i < handle->pending_instances; i++) { + uv_pipe_queue_accept(loop, handle, &handle->accept_reqs[i], i == 0); + } + + return 0; +} + + +static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_read_t* req = (uv_read_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->data; + uv_loop_t* loop = handle->loop; + + assert(req != NULL); + assert(req->type == UV_READ); + assert(handle->type == UV_NAMED_PIPE); + + result = ReadFile(handle->handle, + &uv_zero_, + 0, + &bytes, + NULL); + + if (!result) { + SET_REQ_ERROR(req, GetLastError()); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { + int result; + DWORD bytes; + uv_write_t* req = (uv_write_t*) parameter; + uv_pipe_t* handle = (uv_pipe_t*) req->handle; + uv_loop_t* loop = handle->loop; + + assert(req != NULL); + assert(req->type == UV_WRITE); + assert(handle->type == UV_NAMED_PIPE); + assert(req->write_buffer.base); + + result = WriteFile(handle->handle, + req->write_buffer.base, + req->write_buffer.len, + &bytes, + NULL); + + if (!result) { + SET_REQ_ERROR(req, GetLastError()); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) { + uv_read_t* req; + uv_tcp_t* handle; + + req = (uv_read_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { + uv_read_t* req; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } else { + memset(&req->overlapped, 0, sizeof(req->overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + } + + /* Do 0-read */ + result = ReadFile(handle->handle, + &uv_zero_, + 0, + NULL, + &req->overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (!req->event_handle) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + if (req->wait_handle == INVALID_HANDLE_VALUE) { + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->overlapped.hEvent, post_completion_read_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + goto error; + } + } + } + } + + /* Start the eof timer if there is one */ + eof_timer_start(handle); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + return; + +error: + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb, uv_read2_cb read2_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->read2_cb = read2_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_pipe_queue_read(loop, handle); + + return 0; +} + + +int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + return uv_pipe_read_start_impl(handle, alloc_cb, read_cb, NULL); +} + + +int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, + uv_read2_cb read_cb) { + return uv_pipe_read_start_impl(handle, alloc_cb, NULL, read_cb); +} + + +static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle, + uv_write_t* req) { + req->next_req = NULL; + if (handle->non_overlapped_writes_tail) { + req->next_req = + handle->non_overlapped_writes_tail->next_req; + handle->non_overlapped_writes_tail->next_req = (uv_req_t*)req; + handle->non_overlapped_writes_tail = req; + } else { + req->next_req = (uv_req_t*)req; + handle->non_overlapped_writes_tail = req; + } +} + + +static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) { + uv_write_t* req; + + if (handle->non_overlapped_writes_tail) { + req = (uv_write_t*)handle->non_overlapped_writes_tail->next_req; + + if (req == handle->non_overlapped_writes_tail) { + handle->non_overlapped_writes_tail = NULL; + } else { + handle->non_overlapped_writes_tail->next_req = + req->next_req; + } + + return req; + } else { + /* queue empty */ + return NULL; + } +} + + +static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { + uv_write_t* req = uv_remove_non_overlapped_write_req(handle); + if (req) { + if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc, + req, + WT_EXECUTELONGFUNCTION)) { + uv_fatal_error(GetLastError(), "QueueUserWorkItem"); + } + } +} + + +static int uv_pipe_write_impl(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int err; + int result; + uv_tcp_t* tcp_send_handle; + uv_write_t* ipc_header_req; + uv_ipc_frame_uv_stream ipc_frame; + + if (nbufs != 1 && (nbufs != 0 || !send_handle)) { + return ERROR_NOT_SUPPORTED; + } + + /* Only TCP handles are supported for sharing. */ + if (send_handle && ((send_handle->type != UV_TCP) || + (!(send_handle->flags & UV_HANDLE_BOUND) && + !(send_handle->flags & UV_HANDLE_CONNECTION)))) { + return ERROR_NOT_SUPPORTED; + } + + assert(handle->handle != INVALID_HANDLE_VALUE); + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + req->ipc_header = 0; + req->event_handle = NULL; + req->wait_handle = INVALID_HANDLE_VALUE; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + if (handle->ipc) { + assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + ipc_frame.header.flags = 0; + + /* Use the IPC framing protocol. */ + if (send_handle) { + tcp_send_handle = (uv_tcp_t*)send_handle; + + err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid, + &ipc_frame.socket_info); + if (err) { + return err; + } + ipc_frame.header.flags |= UV_IPC_TCP_SERVER; + + if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { + ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION; + } + } + + if (nbufs == 1) { + ipc_frame.header.flags |= UV_IPC_RAW_DATA; + ipc_frame.header.raw_data_length = bufs[0].len; + } + + /* + * Use the provided req if we're only doing a single write. + * If we're doing multiple writes, use ipc_header_write_req to do + * the first write, and then use the provided req for the second write. + */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + ipc_header_req = req; + } else { + /* + * Try to use the preallocated write req if it's available. + * Otherwise allocate a new one. + */ + if (handle->ipc_header_write_req.type != UV_WRITE) { + ipc_header_req = (uv_write_t*)&handle->ipc_header_write_req; + } else { + ipc_header_req = (uv_write_t*)malloc(sizeof(uv_write_t)); + if (!ipc_header_req) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + } + + uv_req_init(loop, (uv_req_t*) ipc_header_req); + ipc_header_req->type = UV_WRITE; + ipc_header_req->handle = (uv_stream_t*) handle; + ipc_header_req->cb = NULL; + ipc_header_req->ipc_header = 1; + } + + /* Write the header or the whole frame. */ + memset(&ipc_header_req->overlapped, 0, sizeof(ipc_header_req->overlapped)); + + /* Using overlapped IO, but wait for completion before returning. + This write is blocking because ipc_frame is on stack. */ + ipc_header_req->overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!ipc_header_req->overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + &ipc_frame, + ipc_frame.header.flags & UV_IPC_TCP_SERVER ? + sizeof(ipc_frame) : sizeof(ipc_frame.header), + NULL, + &ipc_header_req->overlapped); + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(ipc_header_req->overlapped.hEvent); + return err; + } + + if (!result) { + /* Request not completed immediately. Wait for it.*/ + if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(ipc_header_req->overlapped.hEvent); + return err; + } + } + ipc_header_req->queued_bytes = 0; + CloseHandle(ipc_header_req->overlapped.hEvent); + ipc_header_req->overlapped.hEvent = NULL; + + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); + handle->reqs_pending++; + handle->write_reqs_pending++; + + /* If we don't have any raw data to write - we're done. */ + if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { + return 0; + } + } + + if ((handle->flags & + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) == + (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) { + DWORD bytes; + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + &bytes, + NULL); + + if (!result) { + return err; + } else { + /* Request completed immediately. */ + req->queued_bytes = 0; + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->write_reqs_pending++; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + req->write_buffer = bufs[0]; + uv_insert_non_overlapped_write_req(handle, req); + if (handle->write_reqs_pending == 0) { + uv_queue_non_overlapped_write(handle); + } + + /* Request queued by the kernel. */ + req->queued_bytes = uv_count_bufs(bufs, nbufs); + handle->write_queue_size += req->queued_bytes; + } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { + /* Using overlapped IO, but wait for completion before returning */ + req->overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); + if (!req->overlapped.hEvent) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + err = GetLastError(); + CloseHandle(req->overlapped.hEvent); + return err; + } + + if (result) { + /* Request completed immediately. */ + req->queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) != + WAIT_OBJECT_0) { + err = GetLastError(); + CloseHandle(ipc_header_req->overlapped.hEvent); + return uv_translate_sys_error(err); + } + } + CloseHandle(req->overlapped.hEvent); + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->write_reqs_pending++; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } else { + result = WriteFile(handle->handle, + bufs[0].base, + bufs[0].len, + NULL, + &req->overlapped); + + if (!result && GetLastError() != ERROR_IO_PENDING) { + return GetLastError(); + } + + if (result) { + /* Request completed immediately. */ + req->queued_bytes = 0; + } else { + /* Request queued by the kernel. */ + req->queued_bytes = uv_count_bufs(bufs, nbufs); + handle->write_queue_size += req->queued_bytes; + } + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->overlapped.hEvent, post_completion_write_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + return GetLastError(); + } + } + } + + REGISTER_HANDLE_REQ(loop, handle, req); + handle->reqs_pending++; + handle->write_reqs_pending++; + + return 0; +} + + +int uv_pipe_write(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb); +} + + +int uv_pipe_write2(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + if (!handle->ipc) { + return WSAEINVAL; + } + + return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb); +} + + +static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + handle->flags &= ~UV_HANDLE_READABLE; + uv_read_stop((uv_stream_t*) handle); + + if (handle->read2_cb) { + handle->read2_cb(handle, UV_EOF, &uv_null_buf_, UV_UNKNOWN_HANDLE); + } else { + handle->read_cb((uv_stream_t*) handle, UV_EOF, &uv_null_buf_); + } +} + + +static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, + uv_buf_t buf) { + /* If there is an eof timer running, we don't need it any more, */ + /* so discard it. */ + eof_timer_destroy(handle); + + uv_read_stop((uv_stream_t*) handle); + + if (handle->read2_cb) { + handle->read2_cb(handle, + uv_translate_sys_error(error), + &buf, + UV_UNKNOWN_HANDLE); + } else { + handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf); + } +} + + +static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, + int error, uv_buf_t buf) { + if (error == ERROR_BROKEN_PIPE) { + uv_pipe_read_eof(loop, handle, buf); + } else { + uv_pipe_read_error(loop, handle, error, buf); + } +} + + +void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* req) { + DWORD bytes, avail; + uv_buf_t buf; + uv_ipc_frame_uv_stream ipc_frame; + + assert(handle->type == UV_NAMED_PIPE); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + eof_timer_stop(handle); + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the 0-read. */ + if (handle->flags & UV_HANDLE_READING) { + uv_pipe_read_error_or_eof(loop, + handle, + GET_REQ_ERROR(req), + uv_null_buf_); + } + } else { + /* Do non-blocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + if (!PeekNamedPipe(handle->handle, + NULL, + 0, + NULL, + &avail, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + break; + } + + if (avail == 0) { + /* There is nothing to read after all. */ + break; + } + + if (handle->ipc) { + /* Use the IPC framing protocol to read the incoming data. */ + if (handle->remaining_ipc_rawdata_bytes == 0) { + /* We're reading a new frame. First, read the header. */ + assert(avail >= sizeof(ipc_frame.header)); + + if (!ReadFile(handle->handle, + &ipc_frame.header, + sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame.header)); + assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA | + UV_IPC_TCP_CONNECTION)); + + if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { + assert(avail - sizeof(ipc_frame.header) >= + sizeof(ipc_frame.socket_info)); + + /* Read the TCP socket info. */ + if (!ReadFile(handle->handle, + &ipc_frame.socket_info, + sizeof(ipc_frame) - sizeof(ipc_frame.header), + &bytes, + NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), + uv_null_buf_); + break; + } + + assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header)); + + /* Store the pending socket info. */ + assert(!handle->pending_ipc_info.socket_info); + handle->pending_ipc_info.socket_info = + (WSAPROTOCOL_INFOW*)malloc(sizeof(*(handle->pending_ipc_info.socket_info))); + if (!handle->pending_ipc_info.socket_info) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + *(handle->pending_ipc_info.socket_info) = ipc_frame.socket_info; + handle->pending_ipc_info.tcp_connection = + ipc_frame.header.flags & UV_IPC_TCP_CONNECTION; + } + + if (ipc_frame.header.flags & UV_IPC_RAW_DATA) { + handle->remaining_ipc_rawdata_bytes = + ipc_frame.header.raw_data_length; + continue; + } + } else { + avail = min(avail, (DWORD)handle->remaining_ipc_rawdata_bytes); + } + } + + handle->alloc_cb((uv_handle_t*) handle, avail, &buf); + if (buf.len == 0) { + if (handle->read2_cb) { + handle->read2_cb(handle, UV_ENOBUFS, &buf, UV_UNKNOWN_HANDLE); + } else if (handle->read_cb) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + } + break; + } + assert(buf.base != NULL); + + if (ReadFile(handle->handle, + buf.base, + buf.len, + &bytes, + NULL)) { + /* Successful read */ + if (handle->ipc) { + assert(handle->remaining_ipc_rawdata_bytes >= bytes); + handle->remaining_ipc_rawdata_bytes = + handle->remaining_ipc_rawdata_bytes - bytes; + if (handle->read2_cb) { + handle->read2_cb(handle, bytes, &buf, + handle->pending_ipc_info.socket_info ? UV_TCP : UV_UNKNOWN_HANDLE); + } else if (handle->read_cb) { + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + } + + if (handle->pending_ipc_info.socket_info) { + free(handle->pending_ipc_info.socket_info); + handle->pending_ipc_info.socket_info = NULL; + } + } else { + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + } + + /* Read again only if bytes == buf.len */ + if (bytes <= buf.len) { + break; + } + } else { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + break; + } + } + + /* Post another 0-read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_pipe_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + assert(handle->write_queue_size >= req->queued_bytes); + handle->write_queue_size -= req->queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + + if (req->ipc_header) { + if (req == &handle->ipc_header_write_req) { + req->type = UV_UNKNOWN_REQ; + } else { + free(req); + } + } else { + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + } + + handle->write_reqs_pending--; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE && + handle->non_overlapped_writes_tail) { + assert(handle->write_reqs_pending > 0); + uv_queue_non_overlapped_write(handle); + } + + if (handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_req_t* raw_req) { + uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; + + assert(handle->type == UV_NAMED_PIPE); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ + assert(req->pipeHandle == INVALID_HANDLE_VALUE); + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (REQ_SUCCESS(req)) { + assert(req->pipeHandle != INVALID_HANDLE_VALUE); + req->next_pending = handle->pending_accepts; + handle->pending_accepts = req; + + if (handle->connection_cb) { + handle->connection_cb((uv_stream_t*)handle, 0); + } + } else { + if (req->pipeHandle != INVALID_HANDLE_VALUE) { + CloseHandle(req->pipeHandle); + req->pipeHandle = INVALID_HANDLE_VALUE; + } + if (!(handle->flags & UV__HANDLE_CLOSING)) { + uv_pipe_queue_accept(loop, handle, req, FALSE); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (REQ_SUCCESS(req)) { + uv_pipe_connection_init(handle); + } else { + err = GET_REQ_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, + uv_shutdown_t* req) { + assert(handle->type == UV_NAMED_PIPE); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_READABLE) { + /* Initialize and optionally start the eof timer. Only do this if the */ + /* pipe is readable and we haven't seen EOF come in ourselves. */ + eof_timer_init(handle); + + /* If reading start the timer right now. */ + /* Otherwise uv_pipe_queue_read will start it. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + eof_timer_start(handle); + } + + } else { + /* This pipe is not readable. We can just close it to let the other end */ + /* know that we're done writing. */ + CloseHandle(handle->handle); + handle->handle = INVALID_HANDLE_VALUE; + } + + if (req->cb) { + req->cb(req, 0); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +static void eof_timer_init(uv_pipe_t* pipe) { + int r; + + assert(pipe->eof_timer == NULL); + assert(pipe->flags & UV_HANDLE_CONNECTION); + + pipe->eof_timer = (uv_timer_t*) malloc(sizeof *pipe->eof_timer); + + r = uv_timer_init(pipe->loop, pipe->eof_timer); + assert(r == 0); /* timers can't fail */ + pipe->eof_timer->data = pipe; + uv_unref((uv_handle_t*) pipe->eof_timer); +} + + +static void eof_timer_start(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->eof_timer != NULL) { + uv_timer_start(pipe->eof_timer, eof_timer_cb, eof_timeout, 0); + } +} + + +static void eof_timer_stop(uv_pipe_t* pipe) { + assert(pipe->flags & UV_HANDLE_CONNECTION); + + if (pipe->eof_timer != NULL) { + uv_timer_stop(pipe->eof_timer); + } +} + + +static void eof_timer_cb(uv_timer_t* timer, int status) { + uv_pipe_t* pipe = (uv_pipe_t*) timer->data; + uv_loop_t* loop = timer->loop; + + assert(status == 0); /* timers can't fail */ + assert(pipe->type == UV_NAMED_PIPE); + + /* This should always be true, since we start the timer only */ + /* in uv_pipe_queue_read after successfully calling ReadFile, */ + /* or in uv_process_pipe_shutdown_req if a read is pending, */ + /* and we always immediately stop the timer in */ + /* uv_process_pipe_read_req. */ + assert(pipe->flags & UV_HANDLE_READ_PENDING); + + /* If there are many packets coming off the iocp then the timer callback */ + /* may be called before the read request is coming off the queue. */ + /* Therefore we check here if the read request has completed but will */ + /* be processed later. */ + if ((pipe->flags & UV_HANDLE_READ_PENDING) && + HasOverlappedIoCompleted(&pipe->read_req.overlapped)) { + return; + } + + /* Force both ends off the pipe. */ + CloseHandle(pipe->handle); + pipe->handle = INVALID_HANDLE_VALUE; + + /* Stop reading, so the pending read that is going to fail will */ + /* not be reported to the user. */ + uv_read_stop((uv_stream_t*) pipe); + + /* Report the eof and update flags. This will get reported even if the */ + /* user stopped reading in the meantime. TODO: is that okay? */ + uv_pipe_read_eof(loop, pipe, uv_null_buf_); +} + + +static void eof_timer_destroy(uv_pipe_t* pipe) { + assert(pipe->flags && UV_HANDLE_CONNECTION); + + if (pipe->eof_timer) { + uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb); + pipe->eof_timer = NULL; + } +} + + +static void eof_timer_close_cb(uv_handle_t* handle) { + assert(handle->type == UV_TIMER); + free(handle); +} + + +int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { + HANDLE os_handle = uv__get_osfhandle(file); + + if (os_handle == INVALID_HANDLE_VALUE || + uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) { + return UV_EINVAL; + } + + uv_pipe_connection_init(pipe); + pipe->handle = os_handle; + pipe->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + + if (pipe->ipc) { + assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); + pipe->ipc_pid = uv_parent_pid(); + assert(pipe->ipc_pid != -1); + } + return 0; +} diff --git a/src/win/poll.c b/src/win/poll.c new file mode 100644 index 0000000000..75351afd75 --- /dev/null +++ b/src/win/poll.c @@ -0,0 +1,617 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { + {0xe70f1aa0, 0xab8b, 0x11cf, + {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}, + {0xf9eab0c0, 0x26d4, 0x11d0, + {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, + {0x9fc48064, 0x7298, 0x43e4, + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} +}; + +typedef struct uv_single_fd_set_s { + unsigned int fd_count; + SOCKET fd_array[1]; +} uv_single_fd_set_t; + + +static OVERLAPPED overlapped_dummy_; +static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_overlapped_dummy(void) { + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + if (event == NULL) + uv_fatal_error(GetLastError(), "CreateEvent"); + + memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_); + overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1); +} + + +static OVERLAPPED* uv__get_overlapped_dummy() { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + +static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + AFD_POLL_INFO* afd_poll_info; + DWORD result; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + /* Setting Exclusive to TRUE makes the other poll request return if there */ + /* is any. */ + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = 0; + + if (handle->events & UV_READABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } + if (handle->events & UV_WRITABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; + } + + memset(&req->overlapped, 0, sizeof req->overlapped); + + result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + &req->overlapped); + if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + } +} + + +static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + AFD_POLL_INFO afd_poll_info; + DWORD result; + + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + uv__get_overlapped_dummy()); + + if (result == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + return WSAGetLastError(); + } + } + + return 0; +} + + +static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + AFD_POLL_INFO* afd_poll_info; + + if (req == &handle->poll_req_1) { + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + /* Report an error unless the select was just interrupted. */ + if (!REQ_SUCCESS(req)) { + DWORD error = GET_REQ_SOCK_ERROR(req); + if (error != WSAEINTR && handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(error), 0); + } + + } else if (afd_poll_info->NumberOfHandles >= 1) { + unsigned char events = 0; + + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { + events |= UV_READABLE; + } + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | + AFD_POLL_CONNECT_FAIL)) != 0) { + events |= UV_WRITABLE; + } + + events &= handle->events & ~mask_events; + + if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* Stop polling. */ + handle->events = 0; + uv__handle_stop(handle); + } + + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return 0; + } else { + /* Cancel outstanding poll requests by executing another, unique poll */ + /* request that forces the outstanding ones to return. */ + return uv__fast_poll_cancel_poll_req(loop, handle); + } +} + + +static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, + WSAPROTOCOL_INFOW* protocol_info) { + SOCKET sock = 0; + + sock = WSASocketW(protocol_info->iAddressFamily, + protocol_info->iSocketType, + protocol_info->iProtocol, + protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + return INVALID_SOCKET; + } + + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + goto error; + }; + + if (CreateIoCompletionPort((HANDLE) sock, + iocp, + (ULONG_PTR) sock, + 0) == NULL) { + goto error; + } + + return sock; + + error: + closesocket(sock); + return INVALID_SOCKET; +} + + +static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, + WSAPROTOCOL_INFOW* protocol_info) { + int index, i; + SOCKET peer_socket; + + index = -1; + for (i = 0; i < ARRAY_SIZE(uv_msafd_provider_ids); i++) { + if (memcmp((void*) &protocol_info->ProviderId, + (void*) &uv_msafd_provider_ids[i], + sizeof protocol_info->ProviderId) == 0) { + index = i; + } + } + + /* Check if the protocol uses an msafd socket. */ + if (index < 0) { + return INVALID_SOCKET; + } + + /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ + /* try again if the peer socket creation failed earlier for the same */ + /* protocol. */ + peer_socket = loop->poll_peer_sockets[index]; + if (peer_socket == 0) { + peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); + loop->poll_peer_sockets[index] = peer_socket; + } + + return peer_socket; +} + + +static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { + uv_req_t* req = (uv_req_t*) arg; + uv_poll_t* handle = (uv_poll_t*) req->data; + unsigned char reported_events; + int r; + uv_single_fd_set_t rfds, wfds, efds; + struct timeval timeout; + + assert(handle->type == UV_POLL); + assert(req->type == UV_POLL_REQ); + + if (handle->events & UV_READABLE) { + rfds.fd_count = 1; + rfds.fd_array[0] = handle->socket; + } else { + rfds.fd_count = 0; + } + + if (handle->events & UV_WRITABLE) { + wfds.fd_count = 1; + wfds.fd_array[0] = handle->socket; + efds.fd_count = 1; + efds.fd_array[0] = handle->socket; + } else { + wfds.fd_count = 0; + efds.fd_count = 0; + } + + /* Make the select() time out after 3 minutes. If select() hangs because */ + /* the user closed the socket, we will at least not hang indefinitely. */ + timeout.tv_sec = 3 * 60; + timeout.tv_usec = 0; + + r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout); + if (r == SOCKET_ERROR) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError()); + POST_COMPLETION_FOR_REQ(handle->loop, req); + return 0; + } + + reported_events = 0; + + if (r > 0) { + if (rfds.fd_count > 0) { + assert(rfds.fd_count == 1); + assert(rfds.fd_array[0] == handle->socket); + reported_events |= UV_READABLE; + } + + if (wfds.fd_count > 0) { + assert(wfds.fd_count == 1); + assert(wfds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } else if (efds.fd_count > 0) { + assert(efds.fd_count == 1); + assert(efds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } + } + + SET_REQ_SUCCESS(req); + req->overlapped.InternalHigh = (DWORD) reported_events; + POST_COMPLETION_FOR_REQ(handle->loop, req); + + return 0; +} + + +static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + if (!QueueUserWorkItem(uv__slow_poll_thread_proc, + (void*) req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending, reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, req); + } +} + + + +static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + int err; + + if (req == &handle->poll_req_1) { + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + if (!REQ_SUCCESS(req)) { + /* Error. */ + if (handle->events != 0) { + err = GET_REQ_ERROR(req); + handle->events = 0; /* Stop the watcher */ + handle->poll_cb(handle, uv_translate_sys_error(err), 0); + } + } else { + /* Got some events. */ + int events = req->overlapped.InternalHigh & handle->events & ~mask_events; + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV__HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & + ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_closing(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + return 0; +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd)); +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + WSAPROTOCOL_INFOW protocol_info; + int len; + SOCKET peer_socket, base_socket; + DWORD bytes; + + /* Try to obtain a base handle for the socket. This increases this chances */ + /* that we find an AFD handle and are able to use the fast poll mechanism. */ + /* This will always fail on windows XP/2k3, since they don't support the */ + /* SIO_BASE_HANDLE ioctl. */ +#ifndef NDEBUG + base_socket = INVALID_SOCKET; +#endif + + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &base_socket, + sizeof base_socket, + &bytes, + NULL, + NULL) == 0) { + assert(base_socket != 0 && base_socket != INVALID_SOCKET); + socket = base_socket; + } + + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + handle->socket = socket; + handle->events = 0; + + /* Obtain protocol information about the socket. */ + len = sizeof protocol_info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &len) != 0) { + return WSAGetLastError(); + } + + /* Get the peer socket that is needed to enable fast poll. If the returned */ + /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ + /* to use slow mode. */ + peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); + + if (peer_socket != INVALID_SOCKET) { + /* Initialize fast poll specific fields. */ + handle->peer_socket = peer_socket; + } else { + /* Initialize slow poll specific fields. */ + handle->flags |= UV_HANDLE_POLL_SLOW; + } + + /* Intialize 2 poll reqs. */ + handle->submitted_events_1 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); + handle->poll_req_1.type = UV_POLL_REQ; + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); + handle->poll_req_2.type = UV_POLL_REQ; + handle->poll_req_2.data = handle; + + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, events); + } else { + err = uv__slow_poll_set(handle->loop, handle, events); + } + + if (err) { + return uv_translate_sys_error(err); + } + + handle->poll_cb = cb; + + return 0; +} + + +int uv_poll_stop(uv_poll_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + err = uv__fast_poll_set(handle->loop, handle, 0); + } else { + err = uv__slow_poll_set(handle->loop, handle, 0); + } + + return uv_translate_sys_error(err); +} + + +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_process_poll_req(loop, handle, req); + } else { + uv__slow_poll_process_poll_req(loop, handle, req); + } +} + + +int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + return uv__fast_poll_close(loop, handle); + } else { + return uv__slow_poll_close(loop, handle); + } +} + + +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->submitted_events_1 == 0); + assert(handle->submitted_events_2 == 0); + + uv__handle_close(handle); +} diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c new file mode 100644 index 0000000000..5757764bfd --- /dev/null +++ b/src/win/process-stdio.c @@ -0,0 +1,510 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" + + +/* + * The `child_stdio_buffer` buffer has the following layout: + * int number_of_fds + * unsigned char crt_flags[number_of_fds] + * HANDLE os_handle[number_of_fds] + */ +#define CHILD_STDIO_SIZE(count) \ + (sizeof(int) + \ + sizeof(unsigned char) * (count) + \ + sizeof(uintptr_t) * (count)) + +#define CHILD_STDIO_COUNT(buffer) \ + *((unsigned int*) (buffer)) + +#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ + *((unsigned char*) (buffer) + sizeof(int) + fd) + +#define CHILD_STDIO_HANDLE(buffer, fd) \ + *((HANDLE*) ((unsigned char*) (buffer) + \ + sizeof(int) + \ + sizeof(unsigned char) * \ + CHILD_STDIO_COUNT((buffer)) + \ + sizeof(HANDLE) * (fd))) + + +/* CRT file descriptor mode flags */ +#define FOPEN 0x01 +#define FEOFLAG 0x02 +#define FCRLF 0x04 +#define FPIPE 0x08 +#define FNOINHERIT 0x10 +#define FAPPEND 0x20 +#define FDEV 0x40 +#define FTEXT 0x80 + + +/* + * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited + * the parent process. Don't check for errors - the stdio handles may not be + * valid, or may be closed already. There is no guarantee that this function + * does a perfect job. + */ +void uv_disable_stdio_inheritance(void) { + HANDLE handle; + STARTUPINFOW si; + + /* Make the windows stdio handles non-inheritable. */ + handle = GetStdHandle(STD_INPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + handle = GetStdHandle(STD_ERROR_HANDLE); + if (handle != NULL && handle != INVALID_HANDLE_VALUE) + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + + /* Make inherited CRT FDs non-inheritable. */ + GetStartupInfoW(&si); + if (uv__stdio_verify(si.lpReserved2, si.cbReserved2)) + uv__stdio_noinherit(si.lpReserved2); +} + + +static int uv__create_stdio_pipe_pair(uv_loop_t* loop, + uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { + char pipe_name[64]; + SECURITY_ATTRIBUTES sa; + DWORD server_access = 0; + DWORD client_access = 0; + HANDLE child_pipe = INVALID_HANDLE_VALUE; + int err; + + if (flags & UV_READABLE_PIPE) { + /* The server needs inbound access too, otherwise CreateNamedPipe() */ + /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */ + /* probe the state of the write buffer when we're trying to shutdown */ + /* the pipe. */ + server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; + client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + } + if (flags & UV_WRITABLE_PIPE) { + server_access |= PIPE_ACCESS_INBOUND; + client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + } + + /* Create server pipe handle. */ + err = uv_stdio_pipe_server(loop, + server_pipe, + server_access, + pipe_name, + sizeof(pipe_name)); + if (err) + goto error; + + /* Create child pipe handle. */ + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + child_pipe = CreateFileA(pipe_name, + client_access, + 0, + &sa, + OPEN_EXISTING, + server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, + NULL); + if (child_pipe == INVALID_HANDLE_VALUE) { + err = GetLastError(); + goto error; + } + +#ifndef NDEBUG + /* Validate that the pipe was opened in the right mode. */ + { + DWORD mode; + BOOL r = GetNamedPipeHandleState(child_pipe, + &mode, + NULL, + NULL, + NULL, + NULL, + 0); + assert(r == TRUE); + assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); + } +#endif + + /* Do a blocking ConnectNamedPipe. This should not block because we have */ + /* both ends of the pipe created. */ + if (!ConnectNamedPipe(server_pipe->handle, NULL)) { + if (GetLastError() != ERROR_PIPE_CONNECTED) { + err = GetLastError(); + goto error; + } + } + + /* The server end is now readable and/or writable. */ + if (flags & UV_READABLE_PIPE) + server_pipe->flags |= UV_HANDLE_WRITABLE; + if (flags & UV_WRITABLE_PIPE) + server_pipe->flags |= UV_HANDLE_READABLE; + + *child_pipe_ptr = child_pipe; + return 0; + + error: + if (server_pipe->handle != INVALID_HANDLE_VALUE) { + uv_pipe_cleanup(loop, server_pipe); + } + + if (child_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(child_pipe); + } + + return err; +} + + +static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { + HANDLE current_process; + + + /* _get_osfhandle will sometimes return -2 in case of an error. This seems */ + /* to happen when fd <= 2 and the process' corresponding stdio handle is */ + /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */ + /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */ + /* use the duplicate. Therefore we filter out known-invalid handles here. */ + if (handle == INVALID_HANDLE_VALUE || + handle == NULL || + handle == (HANDLE) -2) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + current_process = GetCurrentProcess(); + + if (!DuplicateHandle(current_process, + handle, + current_process, + dup, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) { + *dup = INVALID_HANDLE_VALUE; + return GetLastError(); + } + + return 0; +} + + +static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { + HANDLE handle; + + if (fd == -1) { + *dup = INVALID_HANDLE_VALUE; + return ERROR_INVALID_HANDLE; + } + + handle = uv__get_osfhandle(fd); + return uv__duplicate_handle(loop, handle, dup); +} + + +int uv__create_nul_handle(HANDLE* handle_ptr, + DWORD access) { + HANDLE handle; + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof sa; + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + handle = CreateFileW(L"NUL", + access, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + 0, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + return GetLastError(); + } + + *handle_ptr = handle; + return 0; +} + + +int uv__stdio_create(uv_loop_t* loop, + const uv_process_options_t* options, + BYTE** buffer_ptr) { + BYTE* buffer; + int count, i; + int err; + + count = options->stdio_count; + + if (count < 0 || count > 255) { + /* Only support FDs 0-255 */ + return ERROR_NOT_SUPPORTED; + } else if (count < 3) { + /* There should always be at least 3 stdio handles. */ + count = 3; + } + + /* Allocate the child stdio buffer */ + buffer = (BYTE*) malloc(CHILD_STDIO_SIZE(count)); + if (buffer == NULL) { + return ERROR_OUTOFMEMORY; + } + + /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ + /* clean up on failure. */ + CHILD_STDIO_COUNT(buffer) = count; + for (i = 0; i < count; i++) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + } + + for (i = 0; i < count; i++) { + uv_stdio_container_t fdopt; + if (i < options->stdio_count) { + fdopt = options->stdio[i]; + } else { + fdopt.flags = UV_IGNORE; + } + + switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | + UV_INHERIT_STREAM)) { + case UV_IGNORE: + /* Starting a process with no stdin/stout/stderr can confuse it. */ + /* So no matter what the user specified, we make sure the first */ + /* three FDs are always open in their typical modes, e.g. stdin */ + /* be readable and stdout/err should be writable. For FDs > 2, don't */ + /* do anything - all handles in the stdio buffer are initialized with */ + /* INVALID_HANDLE_VALUE, which should be okay. */ + if (i <= 2) { + DWORD access = (i == 0) ? FILE_GENERIC_READ : + FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; + + err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i), + access); + if (err) + goto error; + + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + } + break; + + case UV_CREATE_PIPE: { + /* Create a pair of two connected pipe ends; one end is turned into */ + /* an uv_pipe_t for use by the parent. The other one is given to */ + /* the child. */ + uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; + HANDLE child_pipe; + + /* Create a new, connected pipe pair. stdio[i].stream should point */ + /* to an uninitialized, but not connected pipe handle. */ + assert(fdopt.data.stream->type == UV_NAMED_PIPE); + assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); + assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); + + err = uv__create_stdio_pipe_pair(loop, + parent_pipe, + &child_pipe, + fdopt.flags); + if (err) + goto error; + + CHILD_STDIO_HANDLE(buffer, i) = child_pipe; + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + break; + } + + case UV_INHERIT_FD: { + /* Inherit a raw FD. */ + HANDLE child_handle; + + /* Make an inheritable duplicate of the handle. */ + err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); + if (err) { + /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */ + /* error. */ + if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { + CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; + CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + break; + } + goto error; + } + + /* Figure out what the type is. */ + switch (GetFileType(child_handle)) { + case FILE_TYPE_DISK: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN; + break; + + case FILE_TYPE_PIPE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + + case FILE_TYPE_CHAR: + case FILE_TYPE_REMOTE: + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + case FILE_TYPE_UNKNOWN: + if (GetLastError() != 0) { + err = GetLastError(); + CloseHandle(child_handle); + goto error; + } + CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; + break; + + default: + assert(0); + } + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + break; + } + + case UV_INHERIT_STREAM: { + /* Use an existing stream as the stdio handle for the child. */ + HANDLE stream_handle, child_handle; + unsigned char crt_flags; + uv_stream_t* stream = fdopt.data.stream; + + /* Leech the handle out of the stream. */ + if (stream->type == UV_TTY) { + stream_handle = ((uv_tty_t*) stream)->handle; + crt_flags = FOPEN | FDEV; + } else if (stream->type == UV_NAMED_PIPE && + stream->flags & UV_HANDLE_CONNECTED) { + stream_handle = ((uv_pipe_t*) stream)->handle; + crt_flags = FOPEN | FPIPE; + } else { + stream_handle = INVALID_HANDLE_VALUE; + crt_flags = 0; + } + + if (stream_handle == NULL || + stream_handle == INVALID_HANDLE_VALUE) { + /* The handle is already closed, or not yet created, or the */ + /* stream type is not supported. */ + err = ERROR_NOT_SUPPORTED; + goto error; + } + + /* Make an inheritable copy of the handle. */ + if (uv__duplicate_handle(loop, + stream_handle, + &child_handle) < 0) { + goto error; + } + + CHILD_STDIO_HANDLE(buffer, i) = child_handle; + CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; + break; + } + + default: + assert(0); + } + } + + *buffer_ptr = buffer; + return 0; + + error: + uv__stdio_destroy(buffer); + return err; +} + + +void uv__stdio_destroy(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + } + + free(buffer); +} + + +void uv__stdio_noinherit(BYTE* buffer) { + int i, count; + + count = CHILD_STDIO_COUNT(buffer); + for (i = 0; i < count; i++) { + HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + if (handle != INVALID_HANDLE_VALUE) { + SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); + } + } +} + + +int uv__stdio_verify(BYTE* buffer, WORD size) { + unsigned int count; + + /* Check the buffer pointer. */ + if (buffer == NULL) + return 0; + + /* Verify that the buffer is at least big enough to hold the count. */ + if (size < CHILD_STDIO_SIZE(0)) + return 0; + + /* Verify if the count is within range. */ + count = CHILD_STDIO_COUNT(buffer); + if (count > 256) + return 0; + + /* Verify that the buffer size is big enough to hold info for N FDs. */ + if (size < CHILD_STDIO_SIZE(count)) + return 0; + + return 1; +} + + +WORD uv__stdio_size(BYTE* buffer) { + return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))); +} + + +HANDLE uv__stdio_handle(BYTE* buffer, int fd) { + return CHILD_STDIO_HANDLE(buffer, fd); +} diff --git a/src/win/process.c b/src/win/process.c new file mode 100644 index 0000000000..813e522f75 --- /dev/null +++ b/src/win/process.c @@ -0,0 +1,1120 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +#define SIGKILL 9 + + +typedef struct env_var { + const char* narrow; + const WCHAR* wide; + size_t len; /* including null or '=' */ + DWORD value_len; + int supplied; +} env_var_t; + +#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } + + +static HANDLE uv_global_job_handle_; +static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_global_job_handle(void) { + /* Create a job object and set it up to kill all contained processes when + * it's closed. Since this handle is made non-inheritable and we're not + * giving it to anyone, we're the only process holding a reference to it. + * That means that if this process exits it is closed and all the processes + * it contains are killed. All processes created with uv_spawn that are not + * spawned with the UV_PROCESS_DETACHED flag are assigned to this job. + * + * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the + * processes that we explicitly add are affected, and *their* subprocesses + * are not. This ensures that our child processes are not limited in their + * ability to use job control on Windows versions that don't deal with + * nested jobs (prior to Windows 8 / Server 2012). It also lets our child + * processes created detached processes without explicitly breaking away + * from job control (which uv_spawn doesn't, either). + */ + SECURITY_ATTRIBUTES attr; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + + memset(&attr, 0, sizeof attr); + attr.bInheritHandle = FALSE; + + memset(&info, 0, sizeof info); + info.BasicLimitInformation.LimitFlags = + JOB_OBJECT_LIMIT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + + uv_global_job_handle_ = CreateJobObjectW(&attr, NULL); + if (uv_global_job_handle_ == NULL) + uv_fatal_error(GetLastError(), "CreateJobObjectW"); + + if (!SetInformationJobObject(uv_global_job_handle_, + JobObjectExtendedLimitInformation, + &info, + sizeof info)) + uv_fatal_error(GetLastError(), "SetInformationJobObject"); +} + + +static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { + int ws_len, r; + WCHAR* ws; + + ws_len = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + NULL, + 0); + if (ws_len <= 0) { + return GetLastError(); + } + + ws = (WCHAR*) malloc(ws_len * sizeof(WCHAR)); + if (ws == NULL) { + return ERROR_OUTOFMEMORY; + } + + r = MultiByteToWideChar(CP_UTF8, + 0, + s, + -1, + ws, + ws_len); + assert(r == ws_len); + + *ws_ptr = ws; + return 0; +} + + +static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); + handle->exit_cb = NULL; + handle->pid = 0; + handle->exit_signal = 0; + handle->wait_handle = INVALID_HANDLE_VALUE; + handle->process_handle = INVALID_HANDLE_VALUE; + handle->child_stdio_buffer = NULL; + handle->exit_cb_pending = 0; + + uv_req_init(loop, (uv_req_t*)&handle->exit_req); + handle->exit_req.type = UV_PROCESS_EXIT; + handle->exit_req.data = handle; +} + + +/* + * Path search functions + */ + +/* + * Helper function for search_path + */ +static WCHAR* search_path_join_test(const WCHAR* dir, + size_t dir_len, + const WCHAR* name, + size_t name_len, + const WCHAR* ext, + size_t ext_len, + const WCHAR* cwd, + size_t cwd_len) { + WCHAR *result, *result_pos; + DWORD attrs; + + if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { + /* It's a full path without drive letter, use cwd's drive letter only */ + cwd_len = 2; + } else if (dir_len >= 2 && dir[1] == L':' && + (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) { + /* It's a relative path with drive letter (ext.g. D:../some/file) + * Replace drive letter in dir by full cwd if it points to the same drive, + * otherwise use the dir only. + */ + if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) { + cwd_len = 0; + } else { + dir += 2; + dir_len -= 2; + } + } else if (dir_len > 2 && dir[1] == L':') { + /* It's an absolute path with drive letter + * Don't use the cwd at all + */ + cwd_len = 0; + } + + /* Allocate buffer for output */ + result = result_pos = (WCHAR*)malloc(sizeof(WCHAR) * + (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1)); + + /* Copy cwd */ + wcsncpy(result_pos, cwd, cwd_len); + result_pos += cwd_len; + + /* Add a path separator if cwd didn't end with one */ + if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy dir */ + wcsncpy(result_pos, dir, dir_len); + result_pos += dir_len; + + /* Add a separator if the dir didn't end with one */ + if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) { + result_pos[0] = L'\\'; + result_pos++; + } + + /* Copy filename */ + wcsncpy(result_pos, name, name_len); + result_pos += name_len; + + if (ext_len) { + /* Add a dot if the filename didn't end with one */ + if (name_len && result_pos[-1] != '.') { + result_pos[0] = L'.'; + result_pos++; + } + + /* Copy extension */ + wcsncpy(result_pos, ext, ext_len); + result_pos += ext_len; + } + + /* Null terminator */ + result_pos[0] = L'\0'; + + attrs = GetFileAttributesW(result); + + if (attrs != INVALID_FILE_ATTRIBUTES && + !(attrs & FILE_ATTRIBUTE_DIRECTORY)) { + return result; + } + + free(result); + return NULL; +} + + +/* + * Helper function for search_path + */ +static WCHAR* path_search_walk_ext(const WCHAR *dir, + size_t dir_len, + const WCHAR *name, + size_t name_len, + WCHAR *cwd, + size_t cwd_len, + int name_has_ext) { + WCHAR* result; + + /* If the name itself has a nonempty extension, try this extension first */ + if (name_has_ext) { + result = search_path_join_test(dir, dir_len, + name, name_len, + L"", 0, + cwd, cwd_len); + if (result != NULL) { + return result; + } + } + + /* Try .com extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"com", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + /* Try .exe extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"exe", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } + + return NULL; +} + + +/* + * search_path searches the system path for an executable filename - + * the windows API doesn't provide this as a standalone function nor as an + * option to CreateProcess. + * + * It tries to return an absolute filename. + * + * Furthermore, it tries to follow the semantics that cmd.exe, with this + * exception that PATHEXT environment variable isn't used. Since CreateProcess + * can start only .com and .exe files, only those extensions are tried. This + * behavior equals that of msvcrt's spawn functions. + * + * - Do not search the path if the filename already contains a path (either + * relative or absolute). + * + * - If there's really only a filename, check the current directory for file, + * then search all path directories. + * + * - If filename specified has *any* extension, search for the file with the + * specified extension first. + * + * - If the literal filename is not found in a directory, try *appending* + * (not replacing) .com first and then .exe. + * + * - The path variable may contain relative paths; relative paths are relative + * to the cwd. + * + * - Directories in path may or may not end with a trailing backslash. + * + * - CMD does not trim leading/trailing whitespace from path/pathex entries + * nor from the environment variables as a whole. + * + * - When cmd.exe cannot read a directory, it will just skip it and go on + * searching. However, unlike posix-y systems, it will happily try to run a + * file that is not readable/executable; if the spawn fails it will not + * continue searching. + * + * TODO: correctly interpret UNC paths + */ +static WCHAR* search_path(const WCHAR *file, + WCHAR *cwd, + const WCHAR *path) { + int file_has_dir; + WCHAR* result = NULL; + WCHAR *file_name_start; + WCHAR *dot; + const WCHAR *dir_start, *dir_end, *dir_path; + size_t dir_len; + int name_has_ext; + + size_t file_len = wcslen(file); + size_t cwd_len = wcslen(cwd); + + /* If the caller supplies an empty filename, + * we're not gonna return c:\windows\.exe -- GFY! + */ + if (file_len == 0 + || (file_len == 1 && file[0] == L'.')) { + return NULL; + } + + /* Find the start of the filename so we can split the directory from the */ + /* name. */ + for (file_name_start = (WCHAR*)file + file_len; + file_name_start > file + && file_name_start[-1] != L'\\' + && file_name_start[-1] != L'/' + && file_name_start[-1] != L':'; + file_name_start--); + + file_has_dir = file_name_start != file; + + /* Check if the filename includes an extension */ + dot = wcschr(file_name_start, L'.'); + name_has_ext = (dot != NULL && dot[1] != L'\0'); + + if (file_has_dir) { + /* The file has a path inside, don't use path */ + result = path_search_walk_ext( + file, file_name_start - file, + file_name_start, file_len - (file_name_start - file), + cwd, cwd_len, + name_has_ext); + + } else { + dir_end = path; + + /* The file is really only a name; look in cwd first, then scan path */ + result = path_search_walk_ext(L"", 0, + file, file_len, + cwd, cwd_len, + name_has_ext); + + while (result == NULL) { + if (*dir_end == L'\0') { + break; + } + + /* Skip the separator that dir_end now points to */ + if (dir_end != path) { + dir_end++; + } + + /* Next slice starts just after where the previous one ended */ + dir_start = dir_end; + + /* Slice until the next ; or \0 is found */ + dir_end = wcschr(dir_start, L';'); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + + /* If the slice is zero-length, don't bother */ + if (dir_end - dir_start == 0) { + continue; + } + + dir_path = dir_start; + dir_len = dir_end - dir_start; + + /* Adjust if the path is quoted. */ + if (dir_path[0] == '"' || dir_path[0] == '\'') { + ++dir_path; + --dir_len; + } + + if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') { + --dir_len; + } + + result = path_search_walk_ext(dir_path, dir_len, + file, file_len, + cwd, cwd_len, + name_has_ext); + } + } + + return result; +} + + +/* + * Quotes command line arguments + * Returns a pointer to the end (next char to be written) of the buffer + */ +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { + size_t len = wcslen(source); + size_t i; + int quote_hit; + WCHAR* start; + + /* + * Check if the string must be quoted; + * if unnecessary, don't do it, it may only confuse older programs. + */ + if (len == 0) { + return target; + } + + if (NULL == wcspbrk(source, L" \t\"")) { + /* No quotation needed */ + wcsncpy(target, source, len); + target += len; + return target; + } + + if (NULL == wcspbrk(source, L"\"\\")) { + /* + * No embedded double quotes or backlashes, so I can just wrap + * quote marks around the whole thing. + */ + *(target++) = L'"'; + wcsncpy(target, source, len); + target += len; + *(target++) = L'"'; + return target; + } + + /* + * Expected input/output: + * input : hello"world + * output: "hello\"world" + * input : hello""world + * output: "hello\"\"world" + * input : hello\world + * output: hello\world + * input : hello\\world + * output: hello\\world + * input : hello\"world + * output: "hello\\\"world" + * input : hello\\"world + * output: "hello\\\\\"world" + * input : hello world\ + * output: "hello world\" + */ + + *(target++) = L'"'; + start = target; + quote_hit = 1; + + for (i = len; i > 0; --i) { + *(target++) = source[i - 1]; + + if (quote_hit && source[i - 1] == L'\\') { + *(target++) = L'\\'; + } else if(source[i - 1] == L'"') { + quote_hit = 1; + *(target++) = L'\\'; + } else { + quote_hit = 0; + } + } + target[0] = L'\0'; + wcsrev(start); + *(target++) = L'"'; + return target; +} + + +int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { + char** arg; + WCHAR* dst = NULL; + WCHAR* temp_buffer = NULL; + size_t dst_len = 0; + size_t temp_buffer_len = 0; + WCHAR* pos; + int arg_count = 0; + int err = 0; + + /* Count the required size. */ + for (arg = args; *arg; arg++) { + DWORD arg_len; + + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + NULL, + 0); + if (arg_len == 0) { + return GetLastError(); + } + + dst_len += arg_len; + + if (arg_len > temp_buffer_len) + temp_buffer_len = arg_len; + + arg_count++; + } + + /* Adjust for potential quotes. Also assume the worst-case scenario */ + /* that every character needs escaping, so we need twice as much space. */ + dst_len = dst_len * 2 + arg_count * 2; + + /* Allocate buffer for the final command line. */ + dst = (WCHAR*) malloc(dst_len * sizeof(WCHAR)); + if (dst == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + /* Allocate temporary working buffer. */ + temp_buffer = (WCHAR*) malloc(temp_buffer_len * sizeof(WCHAR)); + if (temp_buffer == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + pos = dst; + for (arg = args; *arg; arg++) { + DWORD arg_len; + + /* Convert argument to wide char. */ + arg_len = MultiByteToWideChar(CP_UTF8, + 0, + *arg, + -1, + temp_buffer, + (int) (dst + dst_len - pos)); + if (arg_len == 0) { + err = GetLastError(); + goto error; + } + + if (verbatim_arguments) { + /* Copy verbatim. */ + wcscpy(pos, temp_buffer); + pos += arg_len - 1; + } else { + /* Quote/escape, if needed. */ + pos = quote_cmd_arg(temp_buffer, pos); + } + + *pos++ = *(arg + 1) ? L' ' : L'\0'; + } + + free(temp_buffer); + + *dst_ptr = dst; + return 0; + +error: + free(dst); + free(temp_buffer); + return err; +} + + +/* + * If we learn that people are passing in huge environment blocks + * then we should probably qsort() the array and then bsearch() + * to see if it contains this variable. But there are ownership + * issues associated with that solution; this is the caller's + * char**, and modifying it is rude. + */ +static void check_required_vars_contains_var(env_var_t* required, int count, + const char* var) { + int i; + for (i = 0; i < count; ++i) { + if (_strnicmp(required[i].narrow, var, required[i].len) == 0) { + required[i].supplied = 1; + return; + } + } +} + + +/* + * The way windows takes environment variables is different than what C does; + * Windows wants a contiguous block of null-terminated strings, terminated + * with an additional null. + * + * Windows has a few "essential" environment variables. winsock will fail + * to initialize if SYSTEMROOT is not defined; some APIs make reference to + * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that + * these get defined if the input environment block does not contain any + * values for them. + */ +int make_program_env(char* env_block[], WCHAR** dst_ptr) { + WCHAR* dst; + WCHAR* ptr; + char** env; + size_t env_len = 1; /* room for closing null */ + int len; + int i; + DWORD var_size; + + env_var_t required_vars[] = { + E_V("SYSTEMROOT"), + E_V("SYSTEMDRIVE"), + E_V("TEMP"), + }; + + for (env = env_block; *env; env++) { + int len; + check_required_vars_contains_var(required_vars, + ARRAY_SIZE(required_vars), + *env); + + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + NULL, + 0); + if (len <= 0) { + return GetLastError(); + } + + env_len += len; + } + + for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { + if (!required_vars[i].supplied) { + env_len += required_vars[i].len; + var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); + if (var_size == 0) { + return GetLastError(); + } + required_vars[i].value_len = var_size; + env_len += var_size; + } + } + + dst = malloc(env_len * sizeof(WCHAR)); + if (!dst) { + return ERROR_OUTOFMEMORY; + } + + ptr = dst; + + for (env = env_block; *env; env++, ptr += len) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + ptr, + (int) (env_len - (ptr - dst))); + if (len <= 0) { + free(dst); + return GetLastError(); + } + } + + for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { + if (!required_vars[i].supplied) { + wcscpy(ptr, required_vars[i].wide); + ptr += required_vars[i].len - 1; + *ptr++ = L'='; + var_size = GetEnvironmentVariableW(required_vars[i].wide, + ptr, + required_vars[i].value_len); + if (var_size == 0) { + uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); + } + ptr += required_vars[i].value_len; + } + } + + /* Terminate with an extra NULL. */ + *ptr = L'\0'; + + *dst_ptr = dst; + return 0; +} + + +/* + * Called on Windows thread-pool thread to indicate that + * a child process has exited. + */ +static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { + uv_process_t* process = (uv_process_t*) data; + uv_loop_t* loop = process->loop; + + assert(didTimeout == FALSE); + assert(process); + assert(!process->exit_cb_pending); + + process->exit_cb_pending = 1; + + /* Post completed */ + POST_COMPLETION_FOR_REQ(loop, &process->exit_req); +} + + +/* Called on main thread after a child process has exited. */ +void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { + int64_t exit_code; + DWORD status; + + assert(handle->exit_cb_pending); + handle->exit_cb_pending = 0; + + /* If we're closing, don't call the exit callback. Just schedule a close */ + /* callback now. */ + if (handle->flags & UV__HANDLE_CLOSING) { + uv_want_endgame(loop, (uv_handle_t*) handle); + return; + } + + /* Unregister from process notification. */ + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->wait_handle); + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + + if (GetExitCodeProcess(handle->process_handle, &status)) { + exit_code = status; + } else { + /* Unable to to obtain the exit code. This should never happen. */ + exit_code = uv_translate_sys_error(GetLastError()); + } + + /* Fire the exit callback. */ + if (handle->exit_cb) { + handle->exit_cb(handle, exit_code, handle->exit_signal); + } +} + + +void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_closing(handle); + + if (handle->wait_handle != INVALID_HANDLE_VALUE) { + /* This blocks until either the wait was cancelled, or the callback has */ + /* completed. */ + BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); + if (!r) { + /* This should never happen, and if it happens, we can't recover... */ + uv_fatal_error(GetLastError(), "UnregisterWaitEx"); + } + + handle->wait_handle = INVALID_HANDLE_VALUE; + } + + if (!handle->exit_cb_pending) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } +} + + +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + assert(!handle->exit_cb_pending); + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + uv__handle_close(handle); +} + + +int uv_spawn(uv_loop_t* loop, + uv_process_t* process, + const uv_process_options_t* options) { + int i; + int err = 0; + WCHAR* path = NULL; + BOOL result; + WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, + *env = NULL, *cwd = NULL; + STARTUPINFOW startup; + PROCESS_INFORMATION info; + DWORD process_flags; + + if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { + return UV_ENOTSUP; + } + + if (options->file == NULL || + options->args == NULL) { + return UV_EINVAL; + } + + assert(options->file != NULL); + assert(!(options->flags & ~(UV_PROCESS_DETACHED | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); + + uv_process_init(loop, process); + process->exit_cb = options->exit_cb; + + err = uv_utf8_to_utf16_alloc(options->file, &application); + if (err) + goto done; + + err = make_program_args( + options->args, + options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, + &arguments); + if (err) + goto done; + + if (options->env) { + err = make_program_env(options->env, &env); + if (err) + goto done; + } + + if (options->cwd) { + /* Explicit cwd */ + err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); + if (err) + goto done; + + } else { + /* Inherit cwd */ + DWORD cwd_len, r; + + cwd_len = GetCurrentDirectoryW(0, NULL); + if (!cwd_len) { + err = GetLastError(); + goto done; + } + + cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR)); + if (cwd == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + + r = GetCurrentDirectoryW(cwd_len, cwd); + if (r == 0 || r >= cwd_len) { + err = GetLastError(); + goto done; + } + } + + /* Get PATH environment variable. */ + { + DWORD path_len, r; + + path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); + if (path_len == 0) { + err = GetLastError(); + goto done; + } + + path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); + if (path == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + + r = GetEnvironmentVariableW(L"PATH", path, path_len); + if (r == 0 || r >= path_len) { + err = GetLastError(); + goto done; + } + } + + err = uv__stdio_create(loop, options, &process->child_stdio_buffer); + if (err) + goto done; + + application_path = search_path(application, + cwd, + path); + if (application_path == NULL) { + /* Not found. */ + err = ERROR_FILE_NOT_FOUND; + goto done; + } + + startup.cb = sizeof(startup); + startup.lpReserved = NULL; + startup.lpDesktop = NULL; + startup.lpTitle = NULL; + startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + + startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); + startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; + + startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); + startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); + startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); + + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Use SW_HIDE to avoid any potential process window. */ + startup.wShowWindow = SW_HIDE; + } else { + startup.wShowWindow = SW_SHOWDEFAULT; + } + + process_flags = CREATE_UNICODE_ENVIRONMENT; + + if (options->flags & UV_PROCESS_DETACHED) { + /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That + * means that libuv might not let you create a fully deamonized process + * when run under job control. However the type of job control that libuv + * itself creates doesn't trickle down to subprocesses so they can still + * daemonize. + * + * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the + * CreateProcess call fail if we're under job control that doesn't allow + * breakaway. + */ + process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; + } + + if (!CreateProcessW(application_path, + arguments, + NULL, + NULL, + 1, + process_flags, + env, + cwd, + &startup, + &info)) { + /* CreateProcessW failed. */ + err = GetLastError(); + goto done; + } + + /* Spawn succeeded */ + /* Beyond this point, failure is reported asynchronously. */ + + process->process_handle = info.hProcess; + process->pid = info.dwProcessId; + + /* If the process isn't spawned as detached, assign to the global job */ + /* object so windows will kill it when the parent process dies. */ + if (!(options->flags & UV_PROCESS_DETACHED)) { + uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); + + if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { + /* AssignProcessToJobObject might fail if this process is under job + * control and the job doesn't have the + * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version + * that doesn't support nested jobs. + * + * When that happens we just swallow the error and continue without + * establishing a kill-child-on-parent-exit relationship, otherwise + * there would be no way for libuv applications run under job control + * to spawn processes at all. + */ + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) + uv_fatal_error(err, "AssignProcessToJobObject"); + } + } + + /* Set IPC pid to all IPC pipes. */ + for (i = 0; i < options->stdio_count; i++) { + const uv_stdio_container_t* fdopt = &options->stdio[i]; + if (fdopt->flags & UV_CREATE_PIPE && + fdopt->data.stream->type == UV_NAMED_PIPE && + ((uv_pipe_t*) fdopt->data.stream)->ipc) { + ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId; + } + } + + /* Setup notifications for when the child process exits. */ + result = RegisterWaitForSingleObject(&process->wait_handle, + process->process_handle, exit_wait_callback, (void*)process, INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!result) { + uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); + } + + CloseHandle(info.hThread); + + assert(!err); + + /* Make the handle active. It will remain active until the exit callback */ + /* iis made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + + /* Cleanup, whether we succeeded or failed. */ + done: + free(application); + free(application_path); + free(arguments); + free(cwd); + free(env); + free(path); + + if (process->child_stdio_buffer != NULL) { + /* Clean up child stdio handles. */ + uv__stdio_destroy(process->child_stdio_buffer); + process->child_stdio_buffer = NULL; + } + + return uv_translate_sys_error(err); +} + + +static int uv__kill(HANDLE process_handle, int signum) { + switch (signum) { + case SIGTERM: + case SIGKILL: + case SIGINT: { + /* Unconditionally terminate the process. On Windows, killed processes */ + /* normally return 1. */ + DWORD status; + int err; + + if (TerminateProcess(process_handle, 1)) + return 0; + + /* If the process already exited before TerminateProcess was called, */ + /* TerminateProcess will fail with ERROR_ACESS_DENIED. */ + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED && + GetExitCodeProcess(process_handle, &status) && + status != STILL_ACTIVE) { + return UV_ESRCH; + } + + return uv_translate_sys_error(err); + } + + case 0: { + /* Health check: is the process still alive? */ + DWORD status; + + if (!GetExitCodeProcess(process_handle, &status)) + return uv_translate_sys_error(GetLastError()); + + if (status != STILL_ACTIVE) + return UV_ESRCH; + + return 0; + } + + default: + /* Unsupported signal. */ + return UV_ENOSYS; + } +} + + +int uv_process_kill(uv_process_t* process, int signum) { + int err; + + if (process->process_handle == INVALID_HANDLE_VALUE) { + return UV_EINVAL; + } + + err = uv__kill(process->process_handle, signum); + if (err) { + return err; /* err is already translated. */ + } + + process->exit_signal = signum; + + return 0; +} + + +int uv_kill(int pid, int signum) { + int err; + HANDLE process_handle = OpenProcess(PROCESS_TERMINATE | + PROCESS_QUERY_INFORMATION, FALSE, pid); + + if (process_handle == NULL) { + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER) { + return UV_ESRCH; + } else { + return uv_translate_sys_error(err); + } + } + + err = uv__kill(process_handle, signum); + CloseHandle(process_handle); + + return err; /* err is already translated. */ +} diff --git a/src/win/req-inl.h b/src/win/req-inl.h new file mode 100644 index 0000000000..353fe90b6d --- /dev/null +++ b/src/win/req-inl.h @@ -0,0 +1,224 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" + + +#define SET_REQ_STATUS(req, status) \ + (req)->overlapped.Internal = (ULONG_PTR) (status) + +#define SET_REQ_ERROR(req, error) \ + SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) + +#define SET_REQ_SUCCESS(req) \ + SET_REQ_STATUS((req), STATUS_SUCCESS) + +#define GET_REQ_STATUS(req) \ + ((NTSTATUS) (req)->overlapped.Internal) + +#define REQ_SUCCESS(req) \ + (NT_SUCCESS(GET_REQ_STATUS((req)))) + +#define GET_REQ_ERROR(req) \ + (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) + +#define GET_REQ_SOCK_ERROR(req) \ + (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) + + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ + ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) + +#define UV_SUCCEEDED_WITH_IOCP(result) \ + ((result) || (GetLastError() == ERROR_IO_PENDING)) + + +#define POST_COMPLETION_FOR_REQ(loop, req) \ + if (!PostQueuedCompletionStatus((loop)->iocp, \ + 0, \ + 0, \ + &((req)->overlapped))) { \ + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ + } + + +INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) { + req->type = UV_UNKNOWN_REQ; + SET_REQ_SUCCESS(req); +} + + +INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { + return CONTAINING_RECORD(overlapped, uv_req_t, overlapped); +} + + +INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} + + +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv_process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv_process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv_process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +INLINE static void uv_process_reqs(uv_loop_t* loop) { + uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) { + return; + } + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + /* Tcp shutdown requests don't come here. */ + assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); + uv_process_pipe_shutdown_req( + loop, + (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, + (uv_shutdown_t*) req); + break; + + case UV_UDP_RECV: + uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv_process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_SIGNAL_REQ: + uv_process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_GETADDRINFO: + uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); + break; + + case UV_PROCESS_EXIT: + uv_process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_FS: + uv_process_fs_req(loop, (uv_fs_t*) req); + break; + + case UV_WORK: + uv_process_work_req(loop, (uv_work_t*) req); + break; + + case UV_FS_EVENT_REQ: + uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } +} + +#endif /* UV_WIN_REQ_INL_H_ */ diff --git a/src/win/req.c b/src/win/req.c new file mode 100644 index 0000000000..111cc5e289 --- /dev/null +++ b/src/win/req.c @@ -0,0 +1,25 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" diff --git a/src/win/signal.c b/src/win/signal.c new file mode 100644 index 0000000000..9dc5fccc29 --- /dev/null +++ b/src/win/signal.c @@ -0,0 +1,352 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +RB_HEAD(uv_signal_tree_s, uv_signal_s); + +static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); +static ssize_t volatile uv__signal_control_handler_refs = 0; +static CRITICAL_SECTION uv__signal_lock; + + +void uv_signals_init() { + InitializeCriticalSection(&uv__signal_lock); +} + + +static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + /* Compare signums first so all watchers with the same signnum end up */ + /* adjacent. */ + if (w1->signum < w2->signum) return -1; + if (w1->signum > w2->signum) return 1; + + /* Sort by loop pointer, so we can easily look up the first item after */ + /* { .signum = x, .loop = NULL } */ + if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; + if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; + + if ((uintptr_t) w1 < (uintptr_t) w2) return -1; + if ((uintptr_t) w1 > (uintptr_t) w2) return 1; + + return 0; +} + + +RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare); + + +/* + * Dispatches signal {signum} to all active uv_signal_t watchers in all loops. + * Returns 1 if the signal was dispatched to any watcher, or 0 if there were + * no active signal watchers observing this signal. + */ +int uv__signal_dispatch(int signum) { + uv_signal_t lookup; + uv_signal_t* handle; + int dispatched = 0; + + EnterCriticalSection(&uv__signal_lock); + + lookup.signum = signum; + lookup.loop = NULL; + + for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); + handle != NULL && handle->signum == signum; + handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { + unsigned long previous = InterlockedExchange(&handle->pending_signum, signum); + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + } + + LeaveCriticalSection(&uv__signal_lock); + + return dispatched; +} + + +static BOOL WINAPI uv__signal_control_handler(DWORD type) { + switch (type) { + case CTRL_C_EVENT: + return uv__signal_dispatch(SIGINT); + + case CTRL_BREAK_EVENT: + return uv__signal_dispatch(SIGBREAK); + + case CTRL_CLOSE_EVENT: + if (uv__signal_dispatch(SIGHUP)) { + /* Windows will terminate the process after the control handler */ + /* returns. After that it will just terminate our process. Therefore */ + /* block the signal handler so the main loop has some time to pick */ + /* up the signal and do something for a few seconds. */ + Sleep(INFINITE); + return TRUE; + } + return FALSE; + + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + /* These signals are only sent to services. Services have their own */ + /* notification mechanism, so there's no point in handling these. */ + + default: + /* We don't handle these. */ + return FALSE; + } +} + + +static int uv__signal_register_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + + /* If the console control handler has already been hooked, just add a */ + /* reference. */ + if (uv__signal_control_handler_refs > 0) + return 0; + + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + return GetLastError(); + + uv__signal_control_handler_refs++; + + return 0; +} + + +static void uv__signal_unregister_control_handler() { + /* When this function is called, the uv__signal_lock must be held. */ + BOOL r; + + /* Don't unregister if the number of console control handlers exceeds one. */ + /* Just remove a reference in that case. */ + if (uv__signal_control_handler_refs > 1) { + uv__signal_control_handler_refs--; + return; + } + + assert(uv__signal_control_handler_refs == 1); + + r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); + /* This should never fail; if it does it is probably a bug in libuv. */ + assert(r); + + uv__signal_control_handler_refs--; +} + + +static int uv__signal_register(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + return uv__signal_register_control_handler(); + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to register anything. */ + return 0; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Signal is never raised. */ + return 0; + + default: + /* Invalid signal. */ + return ERROR_INVALID_PARAMETER; + } +} + + +static void uv__signal_unregister(int signum) { + switch (signum) { + case SIGINT: + case SIGBREAK: + case SIGHUP: + uv__signal_unregister_control_handler(); + return; + + case SIGWINCH: + /* SIGWINCH is generated in tty.c. No need to unregister anything. */ + return; + + case SIGILL: + case SIGABRT_COMPAT: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGABRT: + /* Nothing is registered for this signal. */ + return; + + default: + /* Libuv bug. */ + assert(0 && "Invalid signum"); + return; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv_req_t* req; + + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + req = &handle->signal_req; + uv_req_init(loop, req); + req->type = UV_SIGNAL_REQ; + req->data = handle; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + + /* If the watcher wasn't started, this is a no-op. */ + if (handle->signum == 0) + return 0; + + EnterCriticalSection(&uv__signal_lock); + + uv__signal_unregister(handle->signum); + + removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); + assert(removed_handle == handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signum = 0; + uv__handle_stop(handle); + + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + int err; + + /* If the user supplies signum == 0, then return an error already. If the */ + /* signum is otherwise invalid then uv__signal_register will find out */ + /* eventually. */ + if (signum == 0) { + return UV_EINVAL; + } + + /* Short circuit: if the signal watcher is already watching {signum} don't */ + /* go through the process of deregistering and registering the handler. */ + /* Additionally, this avoids pending signals getting lost in the (small) */ + /* time frame that handle->signum == 0. */ + if (signum == handle->signum) { + handle->signal_cb = signal_cb; + return 0; + } + + /* If the signal handler was already active, stop it first. */ + if (handle->signum != 0) { + int r = uv_signal_stop(handle); + /* uv_signal_stop is infallible. */ + assert(r == 0); + } + + EnterCriticalSection(&uv__signal_lock); + + err = uv__signal_register(signum); + if (err) { + /* Uh-oh, didn't work. */ + LeaveCriticalSection(&uv__signal_lock); + return uv_translate_sys_error(err); + } + + handle->signum = signum; + RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); + + LeaveCriticalSection(&uv__signal_lock); + + handle->signal_cb = signal_cb; + uv__handle_start(handle); + + return 0; +} + + +void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, + uv_req_t* req) { + unsigned long dispatched_signum; + + assert(handle->type == UV_SIGNAL); + assert(req->type == UV_SIGNAL_REQ); + + dispatched_signum = InterlockedExchange(&handle->pending_signum, 0); + assert(dispatched_signum != 0); + + /* Check if the pending signal equals the signum that we are watching for. */ + /* These can get out of sync when the handler is stopped and restarted */ + /* while the signal_req is pending. */ + if (dispatched_signum == handle->signum) + handle->signal_cb(handle, dispatched_signum); + + if (handle->flags & UV__HANDLE_CLOSING) { + /* When it is closing, it must be stopped at this point. */ + assert(handle->signum == 0); + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { + uv_signal_stop(handle); + uv__handle_closing(handle); + + if (handle->pending_signum == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { + assert(handle->flags & UV__HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->signum == 0); + assert(handle->pending_signum == 0); + + handle->flags |= UV_HANDLE_CLOSED; + + uv__handle_close(handle); +} diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h new file mode 100644 index 0000000000..e4bf086368 --- /dev/null +++ b/src/win/stream-inl.h @@ -0,0 +1,67 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +INLINE static void uv_stream_init(uv_loop_t* loop, + uv_stream_t* handle, + uv_handle_type type) { + uv__handle_init(loop, (uv_handle_t*) handle, type); + handle->write_queue_size = 0; + handle->activecnt = 0; +} + + +INLINE static void uv_connection_init(uv_stream_t* handle) { + handle->flags |= UV_HANDLE_CONNECTION; + handle->write_reqs_pending = 0; + + uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.type = UV_READ; + handle->read_req.data = handle; + + handle->shutdown_req = NULL; +} + + +INLINE static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { + unsigned int i; + size_t bytes; + + bytes = 0; + for (i = 0; i < nbufs; i++) + bytes += (size_t) bufs[i].len; + + return bytes; +} + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/src/win/stream.c b/src/win/stream.c new file mode 100644 index 0000000000..2eaa74e766 --- /dev/null +++ b/src/win/stream.c @@ -0,0 +1,253 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "req-inl.h" + + +int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (stream->type) { + case UV_TCP: + err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_accept(uv_stream_t* server, uv_stream_t* client) { + int err; + + err = ERROR_INVALID_PARAMETER; + switch (server->type) { + case UV_TCP: + err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); + break; + case UV_NAMED_PIPE: + err = uv_pipe_accept((uv_pipe_t*)server, client); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + int err; + + if (handle->flags & UV_HANDLE_READING) { + return UV_EALREADY; + } + + if (!(handle->flags & UV_HANDLE_READABLE)) { + return UV_ENOTCONN; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); + break; + case UV_TTY: + err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, + uv_read2_cb read_cb) { + int err; + + if (handle->flags & UV_HANDLE_READING) { + return UV_EALREADY; + } + + if (!(handle->flags & UV_HANDLE_READABLE)) { + return UV_ENOTCONN; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_NAMED_PIPE: + err = uv_pipe_read2_start((uv_pipe_t*)handle, alloc_cb, read_cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_read_stop(uv_stream_t* handle) { + int err; + + if (!(handle->flags & UV_HANDLE_READING)) + return 0; + + err = 0; + if (handle->type == UV_TTY) { + err = uv_tty_read_stop((uv_tty_t*) handle); + } else { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + } + + return uv_translate_sys_error(err); +} + + +int uv_write(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_TCP: + err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); + break; + case UV_NAMED_PIPE: + err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb); + break; + case UV_TTY: + err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_write2(uv_write_t* req, + uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + err = ERROR_INVALID_PARAMETER; + switch (handle->type) { + case UV_NAMED_PIPE: + err = uv_pipe_write2(loop, + req, + (uv_pipe_t*) handle, + bufs, + nbufs, + send_handle, + cb); + break; + default: + assert(0); + } + + return uv_translate_sys_error(err); +} + + +int uv_try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs) { + /* NOTE: Won't work with overlapped writes */ + return UV_ENOSYS; +} + + +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_SHUTDOWN; + req->handle = handle; + req->cb = cb; + + handle->flags &= ~UV_HANDLE_WRITABLE; + handle->shutdown_req = req; + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + uv_want_endgame(loop, (uv_handle_t*)handle); + + return 0; +} + + +int uv_is_readable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_READABLE); +} + + +int uv_is_writable(const uv_stream_t* handle) { + return !!(handle->flags & UV_HANDLE_WRITABLE); +} + + +int uv_stream_set_blocking(uv_stream_t* handle, int blocking) { + if (blocking != 0) + handle->flags |= UV_HANDLE_BLOCKING_WRITES; + else + handle->flags &= ~UV_HANDLE_BLOCKING_WRITES; + + return 0; +} diff --git a/src/win/tcp.c b/src/win/tcp.c new file mode 100644 index 0000000000..8fa2146a06 --- /dev/null +++ b/src/win/tcp.c @@ -0,0 +1,1417 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active tcp streams for which to preallocate tcp read buffers. + * (Due to node slab allocator performing poorly under this pattern, + * the optimization is temporarily disabled (threshold=0). This will be + * revisited once node allocator is improved.) + */ +const unsigned int uv_active_tcp_streams_threshold = 0; + +/* + * Number of simultaneous pending AcceptEx calls. + */ +const unsigned int uv_simultaneous_server_accepts = 32; + +/* A zero-size buffer for use by uv_tcp_read */ +static char uv_zero_[] = ""; + +static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_NODELAY, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + return 0; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { + if (setsockopt(socket, + SOL_SOCKET, + SO_KEEPALIVE, + (const char*)&enable, + sizeof enable) == -1) { + return WSAGetLastError(); + } + + if (enable && setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { + return WSAGetLastError(); + } + + return 0; +} + + +static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, + SOCKET socket, int family, int imported) { + DWORD yes = 1; + int non_ifs_lsp; + int err; + + assert(handle->socket == INVALID_SOCKET); + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + if (imported) { + handle->flags |= UV_HANDLE_EMULATE_IOCP; + } else { + return GetLastError(); + } + } + + if (family == AF_INET6) { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6; + } else { + non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; + } + + if (pSetFileCompletionNotificationModes && + !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { + if (pSetFileCompletionNotificationModes((HANDLE) socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + + if (handle->flags & UV_HANDLE_TCP_NODELAY) { + err = uv__tcp_nodelay(handle, socket, 1); + if (err) + return err; + } + + /* TODO: Use stored delay. */ + if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { + err = uv__tcp_keepalive(handle, socket, 1, 60); + if (err) + return err; + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { + uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP); + + handle->accept_reqs = NULL; + handle->pending_accepts = NULL; + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->func_acceptex = NULL; + handle->func_connectex = NULL; + handle->processed_accepts = 0; + + return 0; +} + + +void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { + int err; + unsigned int i; + uv_tcp_accept_t* req; + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + + err = 0; + if (handle->flags & UV__HANDLE_CLOSING) { + err = ERROR_OPERATION_ABORTED; + } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { + err = WSAGetLastError(); + } + + if (handle->shutdown_req->cb) { + handle->shutdown_req->cb(handle->shutdown_req, + uv_translate_sys_error(err)); + } + + handle->shutdown_req = NULL; + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { + closesocket(handle->socket); + handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->accept_reqs) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + req = &handle->accept_reqs[i]; + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; + } + } + } + + free(handle->accept_reqs); + handle->accept_reqs = NULL; + } + + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } + } + + uv__handle_close(handle); + loop->active_tcp_streams--; + } +} + + +static int uv_tcp_try_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + DWORD err; + int r; + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock = socket(addr->sa_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + err = GetLastError(); + closesocket(sock); + return err; + } + + err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); + if (err) { + closesocket(sock); + return err; + } + } + +#ifdef IPV6_V6ONLY + if (addr->sa_family == AF_INET6) { + int on; + + on = (flags & UV_TCP_IPV6ONLY) != 0; + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on); + } +#endif + + r = bind(handle->socket, addr, addrlen); + + if (r == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err == WSAEADDRINUSE) { + /* Some errors are not to be reported until connect() or listen() */ + handle->bind_error = err; + handle->flags |= UV_HANDLE_BIND_ERROR; + } else { + return err; + } + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { + uv_req_t* req; + uv_tcp_t* handle; + + req = (uv_req_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->data; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + +static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { + uv_loop_t* loop = handle->loop; + BOOL success; + DWORD bytes; + SOCKET accept_socket; + short family; + + assert(handle->flags & UV_HANDLE_LISTENING); + assert(req->accept_socket == INVALID_SOCKET); + + /* choose family and extension function */ + if (handle->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + /* Open a socket for the accepted connection. */ + accept_socket = socket(family, SOCK_STREAM, 0); + if (accept_socket == INVALID_SOCKET) { + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + closesocket(accept_socket); + return; + } + + /* Prepare the overlapped structure. */ + memset(&(req->overlapped), 0, sizeof(req->overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + success = handle->func_acceptex(handle->socket, + accept_socket, + (void*)req->accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &req->overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + return; + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + /* Destroy the preallocated client socket. */ + closesocket(accept_socket); + /* Destroy the event handle */ + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + CloseHandle(req->overlapped.hEvent); + req->event_handle = NULL; + } + } +} + + +static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { + uv_read_t* req; + uv_buf_t buf; + int result; + DWORD bytes, flags; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->read_req; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->read_buffer); + if (handle->read_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->read_buffer); + return; + } + assert(handle->read_buffer.base != NULL); + buf = handle->read_buffer; + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + buf.base = (char*) &uv_zero_; + buf.len = 0; + } + + /* Prepare the overlapped structure. */ + memset(&(req->overlapped), 0, sizeof(req->overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + assert(req->event_handle); + req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + } + + flags = 0; + result = WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + &req->overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + req->wait_handle == INVALID_HANDLE_VALUE && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + handle->reqs_pending++; + } +} + + +int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { + uv_loop_t* loop = handle->loop; + unsigned int i, simultaneous_accepts; + uv_tcp_accept_t* req; + int err; + + assert(backlog > 0); + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + return WSAEISCONN; + } + + if (handle->flags & UV_HANDLE_BIND_ERROR) { + return handle->bind_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_tcp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + } + + if (!handle->func_acceptex) { + if (!uv_get_acceptex_function(handle->socket, &handle->func_acceptex)) { + return WSAEAFNOSUPPORT; + } + } + + if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + listen(handle->socket, backlog) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_LISTENING; + handle->connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 + : uv_simultaneous_server_accepts; + + if(!handle->accept_reqs) { + handle->accept_reqs = (uv_tcp_accept_t*) + malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); + if (!handle->accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + for (i = 0; i < simultaneous_accepts; i++) { + req = &handle->accept_reqs[i]; + uv_req_init(loop, (uv_req_t*)req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + + req->wait_handle = INVALID_HANDLE_VALUE; + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } else { + req->event_handle = NULL; + } + + uv_tcp_queue_accept(handle, req); + } + + /* Initialize other unused requests too, because uv_tcp_endgame */ + /* doesn't know how how many requests were intialized, so it will */ + /* try to clean up {uv_simultaneous_server_accepts} requests. */ + for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { + req = &handle->accept_reqs[i]; + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + req->wait_handle = INVALID_HANDLE_VALUE; + } + } + + return 0; +} + + +int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { + uv_loop_t* loop = server->loop; + int err = 0; + int family; + + uv_tcp_accept_t* req = server->pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + return WSAEWOULDBLOCK; + } + + if (req->accept_socket == INVALID_SOCKET) { + return WSAENOTCONN; + } + + if (server->flags & UV_HANDLE_IPV6) { + family = AF_INET6; + } else { + family = AF_INET; + } + + err = uv_tcp_set_socket(client->loop, + client, + req->accept_socket, + family, + 0); + if (err) { + closesocket(req->accept_socket); + } else { + uv_connection_init((uv_stream_t*) client); + /* AcceptEx() implicitly binds the accepted socket. */ + client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + /* Prepare the req to pick up a new connection */ + server->pending_accepts = req->next_pending; + req->next_pending = NULL; + req->accept_socket = INVALID_SOCKET; + + if (!(server->flags & UV__HANDLE_CLOSING)) { + /* Check if we're in a middle of changing the number of pending accepts. */ + if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { + uv_tcp_queue_accept(server, req); + } else { + /* We better be switching to a single pending accept. */ + assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); + + server->processed_accepts++; + + if (server->processed_accepts >= uv_simultaneous_server_accepts) { + server->processed_accepts = 0; + /* + * All previously queued accept requests are now processed. + * We now switch to queueing just a single accept. + */ + uv_tcp_queue_accept(server, &server->accept_reqs[0]); + server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + } + } + } + + loop->active_tcp_streams++; + + return err; +} + + +int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_READING; + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !handle->read_req.event_handle) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!handle->read_req.event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + uv_tcp_queue_read(loop, handle); + } + + return 0; +} + + +static int uv_tcp_try_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + uv_loop_t* loop = handle->loop; + const struct sockaddr* bind_addr; + BOOL success; + DWORD bytes; + int err; + + if (handle->flags & UV_HANDLE_BIND_ERROR) { + return handle->bind_error; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); + if (err) + return err; + } + + if (!handle->func_connectex) { + if (!uv_get_connectex_function(handle->socket, &handle->func_connectex)) { + return WSAEAFNOSUPPORT; + } + } + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_CONNECT; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + success = handle->func_connectex(handle->socket, + addr, + addrlen, + NULL, + 0, + &bytes, + &req->overlapped); + + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + return WSAGetLastError(); + } + + return 0; +} + + +int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, + int* namelen) { + int result; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return UV_EINVAL; + } + + if (handle->flags & UV_HANDLE_BIND_ERROR) { + return uv_translate_sys_error(handle->bind_error); + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, + int* namelen) { + int result; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return UV_EINVAL; + } + + if (handle->flags & UV_HANDLE_BIND_ERROR) { + return uv_translate_sys_error(handle->bind_error); + } + + result = getpeername(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_tcp_write(uv_loop_t* loop, + uv_write_t* req, + uv_tcp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + int result; + DWORD bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + /* Prepare the overlapped structure. */ + memset(&(req->overlapped), 0, sizeof(req->overlapped)); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + req->event_handle = CreateEvent(NULL, 0, 0, NULL); + if (!req->event_handle) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + req->wait_handle = INVALID_HANDLE_VALUE; + } + + result = WSASend(handle->socket, + (WSABUF*) bufs, + nbufs, + &bytes, + 0, + &req->overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->queued_bytes = 0; + handle->reqs_pending++; + handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*) req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->queued_bytes = uv_count_bufs(bufs, nbufs); + handle->reqs_pending++; + handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + handle->write_queue_size += req->queued_bytes; + if (handle->flags & UV_HANDLE_EMULATE_IOCP && + !RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_write_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + } else { + /* Send failed due to an error. */ + return WSAGetLastError(); + } + + return 0; +} + + +void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* req) { + DWORD bytes, flags, err; + uv_buf_t buf; + + assert(handle->type == UV_TCP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the read. */ + if ((handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_ZERO_READ)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->read_buffer; + + err = GET_REQ_SOCK_ERROR(req); + + if (err == WSAECONNABORTED) { + /* + * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. + */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + } else { + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* The read was done with a non-zero buffer length. */ + if (req->overlapped.InternalHigh > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, + req->overlapped.InternalHigh, + &handle->read_buffer); + /* Read again only if bytes == buf.len */ + if (req->overlapped.InternalHigh < handle->read_buffer.len) { + goto done; + } + } else { + /* Connection closed */ + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + handle->flags &= ~UV_HANDLE_READABLE; + + buf.base = 0; + buf.len = 0; + handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->read_buffer); + goto done; + } + } + + /* Do nonblocking reads until the buffer is empty */ + while (handle->flags & UV_HANDLE_READING) { + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + break; + } + assert(buf.base != NULL); + + flags = 0; + if (WSARecv(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + NULL, + NULL) != SOCKET_ERROR) { + if (bytes > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, bytes, &buf); + /* Read again only if bytes == buf.len */ + if (bytes < buf.len) { + break; + } + } else { + /* Connection closed */ + handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE); + DECREASE_ACTIVE_COUNT(loop, handle); + + handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf); + break; + } + } else { + err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK) { + /* Read buffer was completely empty, report a 0-byte read. */ + handle->read_cb((uv_stream_t*)handle, 0, &buf); + } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + + if (err == WSAECONNABORTED) { + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ + err = WSAECONNRESET; + } + + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(err), + &buf); + } + break; + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tcp_queue_read(loop, handle); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_write_t* req) { + int err; + + assert(handle->type == UV_TCP); + + assert(handle->write_queue_size >= req->queued_bytes); + handle->write_queue_size -= req->queued_bytes; + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + } + if (req->event_handle) { + CloseHandle(req->event_handle); + } + } + + if (req->cb) { + err = GET_REQ_SOCK_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + + handle->write_reqs_pending--; + if (handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_req_t* raw_req) { + uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; + int err; + + assert(handle->type == UV_TCP); + + /* If handle->accepted_socket is not a valid socket, then */ + /* uv_queue_accept must have failed. This is a serious error. We stop */ + /* accepting connections and report this error to the connection */ + /* callback. */ + if (req->accept_socket == INVALID_SOCKET) { + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (handle->connection_cb) { + err = GET_REQ_SOCK_ERROR(req); + handle->connection_cb((uv_stream_t*)handle, + uv_translate_sys_error(err)); + } + } + } else if (REQ_SUCCESS(req) && + setsockopt(req->accept_socket, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char*)&handle->socket, + sizeof(handle->socket)) == 0) { + req->next_pending = handle->pending_accepts; + handle->pending_accepts = req; + + /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ + if (handle->connection_cb) { + handle->connection_cb((uv_stream_t*)handle, 0); + } + } else { + /* Error related to accepted socket is ignored because the server */ + /* socket may still be healthy. If the server socket is broken */ + /* uv_queue_accept will detect it. */ + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + if (handle->flags & UV_HANDLE_LISTENING) { + uv_tcp_queue_accept(handle, req); + } + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, + uv_connect_t* req) { + int err; + + assert(handle->type == UV_TCP); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + err = 0; + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + loop->active_tcp_streams++; + } else { + err = WSAGetLastError(); + } + } else { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, + int tcp_connection) { + int err; + + SOCKET socket = WSASocketW(AF_INET, + SOCK_STREAM, + IPPROTO_IP, + socket_protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + + if (socket == INVALID_SOCKET) { + return WSAGetLastError(); + } + + if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) { + err = GetLastError(); + closesocket(socket); + return err; + } + + err = uv_tcp_set_socket(tcp->loop, + tcp, + socket, + socket_protocol_info->iAddressFamily, + 1); + if (err) { + closesocket(socket); + return err; + } + + if (tcp_connection) { + uv_connection_init((uv_stream_t*)tcp); + tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + + tcp->flags |= UV_HANDLE_BOUND; + tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + tcp->loop->active_tcp_streams++; + return 0; +} + + +int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_nodelay(handle, handle->socket, enable); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_NODELAY; + } else { + handle->flags &= ~UV_HANDLE_TCP_NODELAY; + } + + return 0; +} + + +int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { + int err; + + if (handle->socket != INVALID_SOCKET) { + err = uv__tcp_keepalive(handle, handle->socket, enable, delay); + if (err) + return err; + } + + if (enable) { + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; + } else { + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; + } + + /* TODO: Store delay if handle->socket isn't created yet. */ + + return 0; +} + + +int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, + LPWSAPROTOCOL_INFOW protocol_info) { + if (!(handle->flags & UV_HANDLE_CONNECTION)) { + /* + * We're about to share the socket with another process. Because + * this is a listening socket, we assume that the other process will + * be accepting connections on it. So, before sharing the socket + * with another process, we call listen here in the parent process. + */ + + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + return ERROR_INVALID_PARAMETER; + } + + /* Report any deferred bind errors now. */ + if (handle->flags & UV_HANDLE_BIND_ERROR) { + return handle->bind_error; + } + + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + return WSAGetLastError(); + } + } + } + + if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + return 0; +} + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (handle->flags & UV_HANDLE_CONNECTION) { + return UV_EINVAL; + } + + /* Check if we're already in the desired mode. */ + if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) || + (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { + return 0; + } + + /* Don't allow switching from single pending accept to many. */ + if (enable) { + return UV_ENOTSUP; + } + + /* Check if we're in a middle of changing the number of pending accepts. */ + if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) { + return 0; + } + + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + + /* Flip the changing flag if we have already queued multiple accepts. */ + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + } + + return 0; +} + + +static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { + SOCKET socket = tcp->socket; + int non_ifs_lsp; + + /* Check if we have any non-IFS LSPs stacked on top of TCP */ + non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : + uv_tcp_non_ifs_lsp_ipv4; + + /* If there are non-ifs LSPs then try to obtain a base handle for the */ + /* socket. This will always fail on Windows XP/3k. */ + if (non_ifs_lsp) { + DWORD bytes; + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &socket, + sizeof socket, + &bytes, + NULL, + NULL) != 0) { + /* Failed. We can't do CancelIo. */ + return -1; + } + } + + assert(socket != 0 && socket != INVALID_SOCKET); + + if (!CancelIo((HANDLE) socket)) { + return GetLastError(); + } + + /* It worked. */ + return 0; +} + + +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { + int close_socket = 1; + + if (tcp->flags & UV_HANDLE_READ_PENDING) { + /* In order for winsock to do a graceful close there must not be any */ + /* any pending reads, or the socket must be shut down for writing */ + if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { + /* Just do shutdown on non-shared sockets, which ensures graceful close. */ + shutdown(tcp->socket, SD_SEND); + + } else if (uv_tcp_try_cancel_io(tcp) == 0) { + /* In case of a shared socket, we try to cancel all outstanding I/O, */ + /* If that works, don't close the socket yet - wait for the read req to */ + /* return and close the socket in uv_tcp_endgame. */ + close_socket = 0; + + } else { + /* When cancelling isn't possible - which could happen when an LSP is */ + /* present on an old Windows version, we will have to close the socket */ + /* with a read pending. That is not nice because trailing sent bytes */ + /* may not make it to the other side. */ + } + + } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && + tcp->accept_reqs != NULL) { + /* Under normal circumstances closesocket() will ensure that all pending */ + /* accept reqs are canceled. However, when the socket is shared the */ + /* presence of another reference to the socket in another process will */ + /* keep the accept reqs going, so we have to ensure that these are */ + /* canceled. */ + if (uv_tcp_try_cancel_io(tcp) != 0) { + /* When cancellation is not possible, there is another option: we can */ + /* close the incoming sockets, which will also cancel the accept */ + /* operations. However this is not cool because we might inadvertedly */ + /* close a socket that just accepted a new connection, which will */ + /* cause the connection to be aborted. */ + unsigned int i; + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + uv_tcp_accept_t* req = &tcp->accept_reqs[i]; + if (req->accept_socket != INVALID_SOCKET && + !HasOverlappedIoCompleted(&req->overlapped)) { + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; + } + } + } + } + + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (close_socket) { + closesocket(tcp->socket); + tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; + } + + tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(tcp); + + if (tcp->reqs_pending == 0) { + uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); + } +} + + +int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_tcp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily, + 1); + if (err) { + return uv_translate_sys_error(err); + } + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_tcp_try_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__tcp_connect(uv_connect_t* req, + uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + uv_connect_cb cb) { + int err; + + err = uv_tcp_try_connect(req, handle, addr, addrlen, cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} diff --git a/src/win/thread.c b/src/win/thread.c new file mode 100644 index 0000000000..5178f8f9ab --- /dev/null +++ b/src/win/thread.c @@ -0,0 +1,716 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + +#define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL) +#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) + +#ifdef _MSC_VER /* msvc */ +# define inline __inline +# define NOINLINE __declspec (noinline) +#else /* gcc */ +# define inline inline +# define NOINLINE __attribute__ ((noinline)) +#endif + + +inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock); + +inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock); + + +inline static int uv_cond_fallback_init(uv_cond_t* cond); +inline static void uv_cond_fallback_destroy(uv_cond_t* cond); +inline static void uv_cond_fallback_signal(uv_cond_t* cond); +inline static void uv_cond_fallback_broadcast(uv_cond_t* cond); +inline static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex); +inline static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + +inline static int uv_cond_condvar_init(uv_cond_t* cond); +inline static void uv_cond_condvar_destroy(uv_cond_t* cond); +inline static void uv_cond_condvar_signal(uv_cond_t* cond); +inline static void uv_cond_condvar_broadcast(uv_cond_t* cond); +inline static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex); +inline static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout); + + +static NOINLINE void uv__once_inner(uv_once_t* guard, + void (*callback)(void)) { + DWORD result; + HANDLE existing_event, created_event; + + created_event = CreateEvent(NULL, 1, 0, NULL); + if (created_event == 0) { + /* Could fail in a low-memory situation? */ + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + existing_event = InterlockedCompareExchangePointer(&guard->event, + created_event, + NULL); + + if (existing_event == NULL) { + /* We won the race */ + callback(); + + result = SetEvent(created_event); + assert(result); + guard->ran = 1; + + } else { + /* We lost the race. Destroy the event we created and wait for the */ + /* existing one todv become signaled. */ + CloseHandle(created_event); + result = WaitForSingleObject(existing_event, INFINITE); + assert(result == WAIT_OBJECT_0); + } +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + /* Fast case - avoid WaitForSingleObject. */ + if (guard->ran) { + return; + } + + uv__once_inner(guard, callback); +} + + +int uv_thread_join(uv_thread_t *tid) { + if (WaitForSingleObject(*tid, INFINITE)) + return uv_translate_sys_error(GetLastError()); + else { + CloseHandle(*tid); + *tid = 0; + return 0; + } +} + + +int uv_mutex_init(uv_mutex_t* mutex) { + InitializeCriticalSection(mutex); + return 0; +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + DeleteCriticalSection(mutex); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + EnterCriticalSection(mutex); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + if (TryEnterCriticalSection(mutex)) + return 0; + else + return UV_EAGAIN; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + LeaveCriticalSection(mutex); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + uv__once_init(); + + if (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_init(rwlock); + else + return uv__rwlock_fallback_init(rwlock); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_destroy(rwlock); + else + uv__rwlock_fallback_destroy(rwlock); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_rdlock(rwlock); + else + uv__rwlock_fallback_rdlock(rwlock); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_tryrdlock(rwlock); + else + return uv__rwlock_fallback_tryrdlock(rwlock); +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_rdunlock(rwlock); + else + uv__rwlock_fallback_rdunlock(rwlock); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_wrlock(rwlock); + else + uv__rwlock_fallback_wrlock(rwlock); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_trywrlock(rwlock); + else + return uv__rwlock_fallback_trywrlock(rwlock); +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_wrunlock(rwlock); + else + uv__rwlock_fallback_wrunlock(rwlock); +} + + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + *sem = CreateSemaphore(NULL, value, INT_MAX, NULL); + if (*sem == NULL) + return uv_translate_sys_error(GetLastError()); + else + return 0; +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (!CloseHandle(*sem)) + abort(); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (!ReleaseSemaphore(*sem, 1, NULL)) + abort(); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0) + abort(); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + DWORD r = WaitForSingleObject(*sem, 0); + + if (r == WAIT_OBJECT_0) + return 0; + + if (r == WAIT_TIMEOUT) + return UV_EAGAIN; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) { + pInitializeSRWLock(&rwlock->srwlock_); + return 0; +} + + +inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock) { + (void) rwlock; +} + + +inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock) { + pAcquireSRWLockShared(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared(&rwlock->srwlock_)) + return 0; + else + return UV_EBUSY; /* TODO(bnoordhuis) EAGAIN when owned by this thread. */ +} + + +inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock) { + pReleaseSRWLockShared(&rwlock->srwlock_); +} + + +inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock) { + pAcquireSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_)) + return 0; + else + return UV_EBUSY; /* TODO(bnoordhuis) EAGAIN when owned by this thread. */ +} + + +inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) { + pReleaseSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) { + int err; + + err = uv_mutex_init(&rwlock->fallback_.read_mutex_); + if (err) + return err; + + err = uv_mutex_init(&rwlock->fallback_.write_mutex_); + if (err) { + uv_mutex_destroy(&rwlock->fallback_.read_mutex_); + return err; + } + + rwlock->fallback_.num_readers_ = 0; + + return 0; +} + + +inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) { + uv_mutex_destroy(&rwlock->fallback_.read_mutex_); + uv_mutex_destroy(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.read_mutex_); + + if (++rwlock->fallback_.num_readers_ == 1) + uv_mutex_lock(&rwlock->fallback_.write_mutex_); + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); +} + + +inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) { + int err; + + err = uv_mutex_trylock(&rwlock->fallback_.read_mutex_); + if (err) + goto out; + + err = 0; + if (rwlock->fallback_.num_readers_ == 0) + err = uv_mutex_trylock(&rwlock->fallback_.write_mutex_); + + if (err == 0) + rwlock->fallback_.num_readers_++; + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); + +out: + return err; +} + + +inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.read_mutex_); + + if (--rwlock->fallback_.num_readers_ == 0) + uv_mutex_unlock(&rwlock->fallback_.write_mutex_); + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); +} + + +inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.write_mutex_); +} + + +inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) { + return uv_mutex_trylock(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) { + uv_mutex_unlock(&rwlock->fallback_.write_mutex_); +} + + + +/* This condition variable implementation is based on the SetEvent solution + * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * We could not use the SignalObjectAndWait solution (section 3.4) because + * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and + * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. + */ + +inline static int uv_cond_fallback_init(uv_cond_t* cond) { + int err; + + /* Initialize the count to 0. */ + cond->fallback.waiters_count = 0; + + InitializeCriticalSection(&cond->fallback.waiters_count_lock); + + /* Create an auto-reset event. */ + cond->fallback.signal_event = CreateEvent(NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + if (!cond->fallback.signal_event) { + err = GetLastError(); + goto error2; + } + + /* Create a manual-reset event. */ + cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */ + TRUE, /* manual-reset */ + FALSE, /* non-signaled */ + NULL); /* unnamed */ + if (!cond->fallback.broadcast_event) { + err = GetLastError(); + goto error; + } + + return 0; + +error: + CloseHandle(cond->fallback.signal_event); +error2: + DeleteCriticalSection(&cond->fallback.waiters_count_lock); + return uv_translate_sys_error(err); +} + + +inline static int uv_cond_condvar_init(uv_cond_t* cond) { + pInitializeConditionVariable(&cond->cond_var); + return 0; +} + + +int uv_cond_init(uv_cond_t* cond) { + uv__once_init(); + + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_init(cond); + else + return uv_cond_fallback_init(cond); +} + + +inline static void uv_cond_fallback_destroy(uv_cond_t* cond) { + if (!CloseHandle(cond->fallback.broadcast_event)) + abort(); + if (!CloseHandle(cond->fallback.signal_event)) + abort(); + DeleteCriticalSection(&cond->fallback.waiters_count_lock); +} + + +inline static void uv_cond_condvar_destroy(uv_cond_t* cond) { + /* nothing to do */ +} + + +void uv_cond_destroy(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_destroy(cond); + else + uv_cond_fallback_destroy(cond); +} + + +inline static void uv_cond_fallback_signal(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.signal_event); +} + + +inline static void uv_cond_condvar_signal(uv_cond_t* cond) { + pWakeConditionVariable(&cond->cond_var); +} + + +void uv_cond_signal(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_signal(cond); + else + uv_cond_fallback_signal(cond); +} + + +inline static void uv_cond_fallback_broadcast(uv_cond_t* cond) { + int have_waiters; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + have_waiters = cond->fallback.waiters_count > 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + if (have_waiters) + SetEvent(cond->fallback.broadcast_event); +} + + +inline static void uv_cond_condvar_broadcast(uv_cond_t* cond) { + pWakeAllConditionVariable(&cond->cond_var); +} + + +void uv_cond_broadcast(uv_cond_t* cond) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_broadcast(cond); + else + uv_cond_fallback_broadcast(cond); +} + + +inline int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex, + DWORD dwMilliseconds) { + DWORD result; + int last_waiter; + HANDLE handles[2] = { + cond->fallback.signal_event, + cond->fallback.broadcast_event + }; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count++; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* It's ok to release the here since Win32 manual-reset events */ + /* maintain state when used with . This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to being */ + /* called or being called. */ + result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds); + + EnterCriticalSection(&cond->fallback.waiters_count_lock); + cond->fallback.waiters_count--; + last_waiter = result == WAIT_OBJECT_0 + 1 + && cond->fallback.waiters_count == 0; + LeaveCriticalSection(&cond->fallback.waiters_count_lock); + + /* Some thread called . */ + if (last_waiter) { + /* We're the last waiter to be notified or to stop waiting, so reset the */ + /* the manual-reset event. */ + ResetEvent(cond->fallback.broadcast_event); + } + + /* Reacquire the . */ + uv_mutex_lock(mutex); + + if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1) + return 0; + + if (result == WAIT_TIMEOUT) + return UV_ETIMEDOUT; + + abort(); + return -1; /* Satisfy the compiler. */ +} + + +inline static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (uv_cond_wait_helper(cond, mutex, INFINITE)) + abort(); +} + + +inline static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) + abort(); +} + + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + if (HAVE_CONDVAR_API()) + uv_cond_condvar_wait(cond, mutex); + else + uv_cond_fallback_wait(cond, mutex); +} + + +inline static int uv_cond_fallback_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6)); +} + + +inline static int uv_cond_condvar_timedwait(uv_cond_t* cond, + uv_mutex_t* mutex, uint64_t timeout) { + if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return UV_ETIMEDOUT; +} + + +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, + uint64_t timeout) { + if (HAVE_CONDVAR_API()) + return uv_cond_condvar_timedwait(cond, mutex, timeout); + else + return uv_cond_fallback_timedwait(cond, mutex, timeout); +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + int err; + + barrier->n = count; + barrier->count = 0; + + err = uv_mutex_init(&barrier->mutex); + if (err) + return err; + + err = uv_sem_init(&barrier->turnstile1, 0); + if (err) + goto error2; + + err = uv_sem_init(&barrier->turnstile2, 1); + if (err) + goto error; + + return 0; + +error: + uv_sem_destroy(&barrier->turnstile1); +error2: + uv_mutex_destroy(&barrier->mutex); + return err; + +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + uv_sem_destroy(&barrier->turnstile2); + uv_sem_destroy(&barrier->turnstile1); + uv_mutex_destroy(&barrier->mutex); +} + + +void uv_barrier_wait(uv_barrier_t* barrier) { + uv_mutex_lock(&barrier->mutex); + if (++barrier->count == barrier->n) { + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile1); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile1); + + uv_mutex_lock(&barrier->mutex); + if (--barrier->count == 0) { + uv_sem_wait(&barrier->turnstile1); + uv_sem_post(&barrier->turnstile2); + } + uv_mutex_unlock(&barrier->mutex); + + uv_sem_wait(&barrier->turnstile2); + uv_sem_post(&barrier->turnstile2); +} + + +int uv_key_create(uv_key_t* key) { + key->tls_index = TlsAlloc(); + if (key->tls_index == TLS_OUT_OF_INDEXES) + return UV_ENOMEM; + return 0; +} + + +void uv_key_delete(uv_key_t* key) { + if (TlsFree(key->tls_index) == FALSE) + abort(); + key->tls_index = TLS_OUT_OF_INDEXES; +} + + +void* uv_key_get(uv_key_t* key) { + void* value; + + value = TlsGetValue(key->tls_index); + if (value == NULL) + if (GetLastError() != ERROR_SUCCESS) + abort(); + + return value; +} + + +void uv_key_set(uv_key_t* key, void* value) { + if (TlsSetValue(key->tls_index, value) == FALSE) + abort(); +} diff --git a/src/win/threadpool.c b/src/win/threadpool.c new file mode 100644 index 0000000000..9539844c66 --- /dev/null +++ b/src/win/threadpool.c @@ -0,0 +1,81 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + + +static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req, + uv_work_cb work_cb, uv_after_work_cb after_work_cb) { + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WORK; + req->loop = loop; + req->work_cb = work_cb; + req->after_work_cb = after_work_cb; + memset(&req->overlapped, 0, sizeof(req->overlapped)); +} + + +static DWORD WINAPI uv_work_thread_proc(void* parameter) { + uv_work_t* req = (uv_work_t*)parameter; + uv_loop_t* loop = req->loop; + + assert(req != NULL); + assert(req->type == UV_WORK); + assert(req->work_cb); + + req->work_cb(req); + + POST_COMPLETION_FOR_REQ(loop, req); + + return 0; +} + + +int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, + uv_after_work_cb after_work_cb) { + if (work_cb == NULL) + return UV_EINVAL; + + uv_work_req_init(loop, req, work_cb, after_work_cb); + + if (!QueueUserWorkItem(&uv_work_thread_proc, req, WT_EXECUTELONGFUNCTION)) { + return uv_translate_sys_error(GetLastError()); + } + + uv__req_register(loop, req); + return 0; +} + + +int uv_cancel(uv_req_t* req) { + return UV_ENOSYS; +} + + +void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) { + uv__req_unregister(loop, req); + if(req->after_work_cb) + req->after_work_cb(req, 0); +} diff --git a/src/win/timer.c b/src/win/timer.c new file mode 100644 index 0000000000..6c53ea37e0 --- /dev/null +++ b/src/win/timer.c @@ -0,0 +1,254 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "tree.h" +#include "handle-inl.h" + + +void uv_update_time(uv_loop_t* loop) { + DWORD ticks; + ULARGE_INTEGER time; + + ticks = GetTickCount(); + + time.QuadPart = loop->time; + + /* GetTickCount() can conceivably wrap around, so when the current tick */ + /* count is lower than the last tick count, we'll assume it has wrapped. */ + /* uv_poll must make sure that the timer can never overflow more than */ + /* once between two subsequent uv_update_time calls. */ + time.LowPart = ticks; + if (ticks < loop->last_tick_count) + time.HighPart++; + + /* Remember the last tick count. */ + loop->last_tick_count = ticks; + + /* The GetTickCount() resolution isn't too good. Sometimes it'll happen */ + /* that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has */ + /* waited for a couple of ms but this is not reflected in the GetTickCount */ + /* result yet. Therefore whenever GetQueuedCompletionStatus times out */ + /* we'll add the number of ms that it has waited to the current loop time. */ + /* When that happened the loop time might be a little ms farther than what */ + /* we've just computed, and we shouldn't update the loop time. */ + if (loop->time < time.QuadPart) + loop->time = time.QuadPart; +} + + +void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { + loop->time += msecs; +} + + +static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { + if (a->due < b->due) + return -1; + if (a->due > b->due) + return 1; + /* + * compare start_id when both has the same due. start_id is + * allocated with loop->timer_counter in uv_timer_start(). + */ + if (a->start_id < b->start_id) + return -1; + if (a->start_id > b->start_id) + return 1; + return 0; +} + + +RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); + + +int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER); + handle->timer_cb = NULL; + handle->repeat = 0; + + return 0; +} + + +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { + uint64_t clamped_timeout; + + clamped_timeout = loop_time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + return clamped_timeout; +} + + +int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, + uint64_t repeat) { + uv_loop_t* loop = handle->loop; + uv_timer_t* old; + + if (handle->flags & UV_HANDLE_ACTIVE) { + RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); + } + + handle->timer_cb = timer_cb; + handle->due = get_clamped_due_time(loop->time, timeout); + handle->repeat = repeat; + handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); + + /* start_id is the second index to be compared in uv__timer_cmp() */ + handle->start_id = handle->loop->timer_counter++; + + old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle); + assert(old == NULL); + + return 0; +} + + +int uv_timer_stop(uv_timer_t* handle) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_ACTIVE)) + return 0; + + RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); + + handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); + + return 0; +} + + +int uv_timer_again(uv_timer_t* handle) { + uv_loop_t* loop = handle->loop; + + /* If timer_cb is NULL that means that the timer was never started. */ + if (!handle->timer_cb) { + return UV_EINVAL; + } + + if (handle->flags & UV_HANDLE_ACTIVE) { + RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); + handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); + } + + if (handle->repeat) { + handle->due = get_clamped_due_time(loop->time, handle->repeat); + + if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { + uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); + } + + handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); + } + + return 0; +} + + +void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { + assert(handle->type == UV_TIMER); + handle->repeat = repeat; +} + + +uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { + assert(handle->type == UV_TIMER); + return handle->repeat; +} + + +DWORD uv_get_poll_timeout(uv_loop_t* loop) { + uv_timer_t* timer; + int64_t delta; + + /* Check if there are any running timers */ + timer = RB_MIN(uv_timer_tree_s, &loop->timers); + if (timer) { + uv_update_time(loop); + + delta = timer->due - loop->time; + if (delta >= UINT_MAX >> 1) { + /* A timeout value of UINT_MAX means infinite, so that's no good. But */ + /* more importantly, there's always the risk that GetTickCount wraps. */ + /* uv_update_time can detect this, but we must make sure that the */ + /* tick counter never overflows twice between two subsequent */ + /* uv_update_time calls. We do this by never sleeping more than half */ + /* the time it takes to wrap the counter - which is huge overkill, */ + /* but hey, it's not so bad to wake up every 25 days. */ + return UINT_MAX >> 1; + } else if (delta < 0) { + /* Negative timeout values are not allowed */ + return 0; + } else { + return (DWORD)delta; + } + } else { + /* No timers */ + return INFINITE; + } +} + + +void uv_process_timers(uv_loop_t* loop) { + uv_timer_t* timer; + + /* Call timer callbacks */ + for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); + timer != NULL && timer->due <= loop->time; + timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { + RB_REMOVE(uv_timer_tree_s, &loop->timers, timer); + + if (timer->repeat != 0) { + /* If it is a repeating timer, reschedule with repeat timeout. */ + timer->due = get_clamped_due_time(timer->due, timer->repeat); + if (timer->due < loop->time) { + timer->due = loop->time; + } + if (RB_INSERT(uv_timer_tree_s, &loop->timers, timer) != NULL) { + uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); + } + } else { + /* If non-repeating, mark the timer as inactive. */ + timer->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(timer); + } + + timer->timer_cb((uv_timer_t*) timer, 0); + } +} diff --git a/src/win/tty.c b/src/win/tty.c new file mode 100644 index 0000000000..8855af350e --- /dev/null +++ b/src/win/tty.c @@ -0,0 +1,1873 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +#define UNICODE_REPLACEMENT_CHARACTER (0xfffd) + +#define ANSI_NORMAL 0x00 +#define ANSI_ESCAPE_SEEN 0x02 +#define ANSI_CSI 0x04 +#define ANSI_ST_CONTROL 0x08 +#define ANSI_IGNORE 0x10 +#define ANSI_IN_ARG 0x20 +#define ANSI_IN_STRING 0x40 +#define ANSI_BACKSLASH_SEEN 0x80 + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); + + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + + +/* + * The console virtual window. + * + * Normally cursor movement in windows is relative to the console screen buffer, + * e.g. the application is allowed to overwrite the 'history'. This is very + * inconvenient, it makes absolute cursor movement pretty useless. There is + * also the concept of 'client rect' which is defined by the actual size of + * the console window and the scroll position of the screen buffer, but it's + * very volatile because it changes when the user scrolls. + * + * To make cursor movement behave sensibly we define a virtual window to which + * cursor movement is confined. The virtual window is always as wide as the + * console screen buffer, but it's height is defined by the size of the + * console window. The top of the virtual window aligns with the position + * of the caret when the first stdout/err handle is created, unless that would + * mean that it would extend beyond the bottom of the screen buffer - in that + * that case it's located as far down as possible. + * + * When the user writes a long text or many newlines, such that the output + * reaches beyond the bottom of the virtual window, the virtual window is + * shifted downwards, but not resized. + * + * Since all tty i/o happens on the same console, this window is shared + * between all stdout/stderr handles. + */ + +static int uv_tty_virtual_offset = -1; +static int uv_tty_virtual_height = -1; +static int uv_tty_virtual_width = -1; + +static CRITICAL_SECTION uv_tty_output_lock; + +static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; + + +void uv_console_init() { + InitializeCriticalSection(&uv_tty_output_lock); +} + + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + + handle = (HANDLE) _get_osfhandle(fd); + if (handle == INVALID_HANDLE_VALUE) { + return UV_EBADF; + } + + if (!readable) { + /* Obtain the screen buffer info with the output handle. */ + if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Obtain the the tty_output_lock because the virtual window state is */ + /* shared between all uv_tty_t handles. */ + EnterCriticalSection(&uv_tty_output_lock); + + /* Store the global tty output handle. This handle is used by TTY read */ + /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ + /* is received. */ + uv_tty_output_handle = handle; + + uv_tty_update_virtual_window(&screen_buffer_info); + + LeaveCriticalSection(&uv_tty_output_lock); + } + + + uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); + uv_connection_init((uv_stream_t*) tty); + + tty->handle = handle; + tty->reqs_pending = 0; + tty->flags |= UV_HANDLE_BOUND; + + if (readable) { + /* Initialize TTY input specific fields. */ + tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; + tty->read_line_handle = NULL; + tty->read_line_buffer = uv_null_buf_; + tty->read_raw_wait = NULL; + + /* Init keycode-to-vt100 mapper state. */ + tty->last_key_len = 0; + tty->last_key_offset = 0; + tty->last_utf16_high_surrogate = 0; + memset(&tty->last_input_record, 0, sizeof tty->last_input_record); + } else { + /* TTY output specific fields. */ + tty->flags |= UV_HANDLE_WRITABLE; + + /* Init utf8-to-utf16 conversion state. */ + tty->utf8_bytes_left = 0; + tty->utf8_codepoint = 0; + + /* Initialize eol conversion state */ + tty->previous_eol = 0; + + /* Init ANSI parser state. */ + tty->ansi_parser_state = ANSI_NORMAL; + } + + return 0; +} + + +int uv_tty_set_mode(uv_tty_t* tty, int mode) { + DWORD flags; + unsigned char was_reading; + uv_alloc_cb alloc_cb; + uv_read_cb read_cb; + int err; + + if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { + return UV_EINVAL; + } + + if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + return 0; + } + + if (mode) { + /* Raw input */ + flags = ENABLE_WINDOW_INPUT; + } else { + /* Line-buffered mode. */ + flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + } + + if (!SetConsoleMode(tty->handle, flags)) { + return uv_translate_sys_error(GetLastError()); + } + + /* If currently reading, stop, and restart reading. */ + if (tty->flags & UV_HANDLE_READING) { + was_reading = 1; + alloc_cb = tty->alloc_cb; + read_cb = tty->read_cb; + + if (was_reading) { + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); + } + } + } else { + was_reading = 0; + } + + /* Update flag. */ + tty->flags &= ~UV_HANDLE_TTY_RAW; + tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + + /* If we just stopped reading, restart. */ + if (was_reading) { + err = uv_tty_read_start(tty, alloc_cb, read_cb); + if (err) { + return uv_translate_sys_error(err); + } + } + + return 0; +} + + +int uv_is_tty(uv_file file) { + DWORD result; + return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (!GetConsoleScreenBufferInfo(tty->handle, &info)) { + return uv_translate_sys_error(GetLastError()); + } + + EnterCriticalSection(&uv_tty_output_lock); + uv_tty_update_virtual_window(&info); + LeaveCriticalSection(&uv_tty_output_lock); + + *width = uv_tty_virtual_width; + *height = uv_tty_virtual_height; + + return 0; +} + + +static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + + assert(data); + assert(!didTimeout); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + UnregisterWait(handle->read_raw_wait); + handle->read_raw_wait = NULL; + + SET_REQ_SUCCESS(req); + POST_COMPLETION_FOR_REQ(loop, req); +} + + +static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + handle->read_line_buffer = uv_null_buf_; + + req = &handle->read_req; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + r = RegisterWaitForSingleObject(&handle->read_raw_wait, + handle->handle, + uv_tty_post_raw_read, + (void*) req, + INFINITE, + WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); + if (!r) { + handle->read_raw_wait = NULL; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static DWORD CALLBACK uv_tty_line_read_thread(void* data) { + uv_loop_t* loop; + uv_tty_t* handle; + uv_req_t* req; + DWORD bytes, read_bytes; + + assert(data); + + req = (uv_req_t*) data; + handle = (uv_tty_t*) req->data; + loop = handle->loop; + + assert(handle->read_line_buffer.base != NULL); + assert(handle->read_line_buffer.len > 0); + + /* ReadConsole can't handle big buffers. */ + if (handle->read_line_buffer.len < 8192) { + bytes = handle->read_line_buffer.len; + } else { + bytes = 8192; + } + + /* Todo: Unicode */ + if (ReadConsoleA(handle->read_line_handle, + (void*) handle->read_line_buffer.base, + bytes, + &read_bytes, + NULL)) { + SET_REQ_SUCCESS(req); + req->overlapped.InternalHigh = read_bytes; + } else { + SET_REQ_ERROR(req, GetLastError()); + } + + POST_COMPLETION_FOR_REQ(loop, req); + return 0; +} + + +static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { + uv_read_t* req; + BOOL r; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); + + req = &handle->read_req; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->read_line_buffer); + if (handle->read_line_buffer.len == 0) { + handle->read_cb((uv_stream_t*) handle, + UV_ENOBUFS, + &handle->read_line_buffer); + return; + } + assert(handle->read_line_buffer.base != NULL); + + /* Duplicate the console handle, so if we want to cancel the read, we can */ + /* just close this handle duplicate. */ + if (handle->read_line_handle == NULL) { + HANDLE this_process = GetCurrentProcess(); + r = DuplicateHandle(this_process, + handle->handle, + this_process, + &handle->read_line_handle, + 0, + 0, + DUPLICATE_SAME_ACCESS); + if (!r) { + handle->read_line_handle = NULL; + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + goto out; + } + } + + r = QueueUserWorkItem(uv_tty_line_read_thread, + (void*) req, + WT_EXECUTELONGFUNCTION); + if (!r) { + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, (uv_req_t*)req); + } + + out: + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; +} + + +static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { + if (handle->flags & UV_HANDLE_TTY_RAW) { + uv_tty_queue_read_raw(loop, handle); + } else { + uv_tty_queue_read_line(loop, handle); + } +} + + +static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, + size_t* len) { +#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \ + case (vk): \ + if (shift && ctrl) { \ + *len = sizeof shift_ctrl_str; \ + return "\033" shift_ctrl_str; \ + } else if (shift) { \ + *len = sizeof shift_str ; \ + return "\033" shift_str; \ + } else if (ctrl) { \ + *len = sizeof ctrl_str; \ + return "\033" ctrl_str; \ + } else { \ + *len = sizeof normal_str; \ + return "\033" normal_str; \ + } + + switch (code) { + /* These mappings are the same as Cygwin's. Unmodified and alt-modified */ + /* keypad keys comply with linux console, modifiers comply with xterm */ + /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */ + /* f6..f12 with and without modifiers comply with rxvt. */ + VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~") + VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~") + VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B") + VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~") + VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D") + VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G") + VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C") + VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A") + VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~") + VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~") + VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~") + VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" ) + VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" ) + VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" ) + VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" ) + VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" ) + VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" ) + VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" ) + VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" ) + VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" ) + VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" ) + VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" ) + VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" ) + + default: + *len = 0; + return NULL; + } +#undef VK_CASE +} + + +void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + /* Shortcut for handle->last_input_record.Event.KeyEvent. */ +#define KEV handle->last_input_record.Event.KeyEvent + + DWORD records_left, records_read; + uv_buf_t buf; + off_t buf_used; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!(handle->flags & UV_HANDLE_READING) || + !(handle->flags & UV_HANDLE_TTY_RAW)) { + goto out; + } + + if (!REQ_SUCCESS(req)) { + /* An error occurred while waiting for the event. */ + if ((handle->flags & UV_HANDLE_READING)) { + handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &uv_null_buf_); + } + goto out; + } + + /* Fetch the number of events */ + if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*)handle, + uv_translate_sys_error(GetLastError()), + &uv_null_buf_); + goto out; + } + + /* Windows sends a lot of events that we're not interested in, so buf */ + /* will be allocated on demand, when there's actually something to emit. */ + buf = uv_null_buf_; + buf_used = 0; + + while ((records_left > 0 || handle->last_key_len > 0) && + (handle->flags & UV_HANDLE_READING)) { + if (handle->last_key_len == 0) { + /* Read the next input record */ + if (!ReadConsoleInputW(handle->handle, + &handle->last_input_record, + 1, + &records_read)) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + records_left--; + + /* If the window was resized, recompute the virtual window size. This */ + /* will trigger a SIGWINCH signal if the window size changed in an */ + /* way that matters to libuv. */ + if (handle->last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { + CONSOLE_SCREEN_BUFFER_INFO info; + + EnterCriticalSection(&uv_tty_output_lock); + + if (uv_tty_output_handle != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { + uv_tty_update_virtual_window(&info); + } + + LeaveCriticalSection(&uv_tty_output_lock); + + continue; + } + + /* Ignore other events that are not key or resize events. */ + if (handle->last_input_record.EventType != KEY_EVENT) { + continue; + } + + /* Ignore keyup events, unless the left alt key was held and a valid */ + /* unicode character was emitted. */ + if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || + KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { + continue; + } + + /* Ignore keypresses to numpad number keys if the left alt is held */ + /* because the user is composing a character, or windows simulating */ + /* this. */ + if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && + !(KEV.dwControlKeyState & ENHANCED_KEY) && + (KEV.wVirtualKeyCode == VK_INSERT || + KEV.wVirtualKeyCode == VK_END || + KEV.wVirtualKeyCode == VK_DOWN || + KEV.wVirtualKeyCode == VK_NEXT || + KEV.wVirtualKeyCode == VK_LEFT || + KEV.wVirtualKeyCode == VK_CLEAR || + KEV.wVirtualKeyCode == VK_RIGHT || + KEV.wVirtualKeyCode == VK_HOME || + KEV.wVirtualKeyCode == VK_UP || + KEV.wVirtualKeyCode == VK_PRIOR || + KEV.wVirtualKeyCode == VK_NUMPAD0 || + KEV.wVirtualKeyCode == VK_NUMPAD1 || + KEV.wVirtualKeyCode == VK_NUMPAD2 || + KEV.wVirtualKeyCode == VK_NUMPAD3 || + KEV.wVirtualKeyCode == VK_NUMPAD4 || + KEV.wVirtualKeyCode == VK_NUMPAD5 || + KEV.wVirtualKeyCode == VK_NUMPAD6 || + KEV.wVirtualKeyCode == VK_NUMPAD7 || + KEV.wVirtualKeyCode == VK_NUMPAD8 || + KEV.wVirtualKeyCode == VK_NUMPAD9)) { + continue; + } + + if (KEV.uChar.UnicodeChar != 0) { + int prefix_len, char_len; + + /* Character key pressed */ + if (KEV.uChar.UnicodeChar >= 0xD800 && + KEV.uChar.UnicodeChar < 0xDC00) { + /* UTF-16 high surrogate */ + handle->last_utf16_high_surrogate = KEV.uChar.UnicodeChar; + continue; + } + + /* Prefix with \u033 if alt was held, but alt was not used as part */ + /* a compose sequence. */ + if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) + && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { + handle->last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + if (KEV.uChar.UnicodeChar >= 0xDC00 && + KEV.uChar.UnicodeChar < 0xE000) { + /* UTF-16 surrogate pair */ + WCHAR utf16_buffer[2] = { handle->last_utf16_high_surrogate, + KEV.uChar.UnicodeChar}; + char_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + 2, + &handle->last_key[prefix_len], + sizeof handle->last_key, + NULL, + NULL); + } else { + /* Single UTF-16 character */ + char_len = WideCharToMultiByte(CP_UTF8, + 0, + &KEV.uChar.UnicodeChar, + 1, + &handle->last_key[prefix_len], + sizeof handle->last_key, + NULL, + NULL); + } + + /* Whatever happened, the last character wasn't a high surrogate. */ + handle->last_utf16_high_surrogate = 0; + + /* If the utf16 character(s) couldn't be converted something must */ + /* be wrong. */ + if (!char_len) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GetLastError()), + &buf); + goto out; + } + + handle->last_key_len = (unsigned char) (prefix_len + char_len); + handle->last_key_offset = 0; + continue; + + } else { + /* Function key pressed */ + const char* vt100; + size_t prefix_len, vt100_len; + + vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode, + !!(KEV.dwControlKeyState & SHIFT_PRESSED), + !!(KEV.dwControlKeyState & ( + LEFT_CTRL_PRESSED | + RIGHT_CTRL_PRESSED)), + &vt100_len); + + /* If we were unable to map to a vt100 sequence, just ignore. */ + if (!vt100) { + continue; + } + + /* Prefix with \x033 when the alt key was held. */ + if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { + handle->last_key[0] = '\033'; + prefix_len = 1; + } else { + prefix_len = 0; + } + + /* Copy the vt100 sequence to the handle buffer. */ + assert(prefix_len + vt100_len < sizeof handle->last_key); + memcpy(&handle->last_key[prefix_len], vt100, vt100_len); + + handle->last_key_len = (unsigned char) (prefix_len + vt100_len); + handle->last_key_offset = 0; + continue; + } + } else { + /* Copy any bytes left from the last keypress to the user buffer. */ + if (handle->last_key_offset < handle->last_key_len) { + /* Allocate a buffer if needed */ + if (buf_used == 0) { + handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); + if (buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + goto out; + } + assert(buf.base != NULL); + } + + buf.base[buf_used++] = handle->last_key[handle->last_key_offset++]; + + /* If the buffer is full, emit it */ + if (buf_used == buf.len) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + buf = uv_null_buf_; + buf_used = 0; + } + + continue; + } + + /* Apply dwRepeat from the last input record. */ + if (--KEV.wRepeatCount > 0) { + handle->last_key_offset = 0; + continue; + } + + handle->last_key_len = 0; + continue; + } + } + + /* Send the buffer back to the user */ + if (buf_used > 0) { + handle->read_cb((uv_stream_t*) handle, buf_used, &buf); + } + + out: + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); + +#undef KEV +} + + + +void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + uv_buf_t buf; + + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + buf = handle->read_line_buffer; + + handle->flags &= ~UV_HANDLE_READ_PENDING; + handle->read_line_buffer = uv_null_buf_; + + if (!REQ_SUCCESS(req)) { + /* Read was not successful */ + if ((handle->flags & UV_HANDLE_READING) && + handle->read_line_handle != NULL) { + /* Real error */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb((uv_stream_t*) handle, + uv_translate_sys_error(GET_REQ_ERROR(req)), + &buf); + } else { + /* The read was cancelled, or whatever we don't care */ + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } + + } else { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } + + /* Wait for more input events. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_tty_queue_read(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* req) { + assert(handle->type == UV_TTY); + assert(handle->flags & UV_HANDLE_TTY_READABLE); + + /* If the read_line_buffer member is zero, it must have been an raw read. */ + /* Otherwise it was a line-buffered read. */ + /* FIXME: This is quite obscure. Use a flag or something. */ + if (handle->read_line_buffer.len == 0) { + uv_process_tty_read_raw_req(loop, handle, req); + } else { + uv_process_tty_read_line_req(loop, handle, req); + } +} + + +int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_TTY_READABLE)) { + return ERROR_INVALID_PARAMETER; + } + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + handle->read_cb = read_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* read request pending. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + return 0; + } + + /* Maybe the user stopped reading half-way while processing key events. */ + /* Short-circuit if this could be the case. */ + if (handle->last_key_len > 0) { + SET_REQ_SUCCESS(&handle->read_req); + uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); + return 0; + } + + uv_tty_queue_read(loop, handle); + + return 0; +} + + +int uv_tty_read_stop(uv_tty_t* handle) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + /* Cancel raw read */ + if ((handle->flags & UV_HANDLE_READ_PENDING) && + (handle->flags & UV_HANDLE_TTY_RAW)) { + /* Write some bullshit event to force the console wait to return. */ + INPUT_RECORD record; + DWORD written; + memset(&record, 0, sizeof record); + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { + return GetLastError(); + } + } + + /* Cancel line-buffered read */ + if (handle->read_line_handle != NULL) { + /* Closing this handle will cancel the ReadConsole operation */ + CloseHandle(handle->read_line_handle); + handle->read_line_handle = NULL; + } + + + return 0; +} + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { + int old_virtual_width = uv_tty_virtual_width; + int old_virtual_height = uv_tty_virtual_height; + + uv_tty_virtual_width = info->dwSize.X; + uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; + + /* Recompute virtual window offset row. */ + if (uv_tty_virtual_offset == -1) { + uv_tty_virtual_offset = info->dwCursorPosition.Y; + } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - + uv_tty_virtual_height + 1) { + /* If suddenly find the cursor outside of the virtual window, it must */ + /* have somehow scrolled. Update the virtual window offset. */ + uv_tty_virtual_offset = info->dwCursorPosition.Y - + uv_tty_virtual_height + 1; + } + if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) { + uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height; + } + if (uv_tty_virtual_offset < 0) { + uv_tty_virtual_offset = 0; + } + + /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */ + /* if this was the first time the virtual window size was computed. */ + if (old_virtual_width != -1 && old_virtual_height != -1 && + (uv_tty_virtual_width != old_virtual_width || + uv_tty_virtual_height != old_virtual_height)) { + uv__signal_dispatch(SIGWINCH); + } +} + + +static COORD uv_tty_make_real_coord(uv_tty_t* handle, + CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, + unsigned char y_relative) { + COORD result; + + uv_tty_update_virtual_window(info); + + /* Adjust y position */ + if (y_relative) { + y = info->dwCursorPosition.Y + y; + } else { + y = uv_tty_virtual_offset + y; + } + /* Clip y to virtual client rectangle */ + if (y < uv_tty_virtual_offset) { + y = uv_tty_virtual_offset; + } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) { + y = uv_tty_virtual_offset + uv_tty_virtual_height - 1; + } + + /* Adjust x */ + if (x_relative) { + x = info->dwCursorPosition.X + x; + } + /* Clip x */ + if (x < 0) { + x = 0; + } else if (x >= uv_tty_virtual_width) { + x = uv_tty_virtual_width - 1; + } + + result.X = (unsigned short) x; + result.Y = (unsigned short) y; + return result; +} + + +static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, + DWORD* error) { + DWORD written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!WriteConsoleW(handle->handle, + (void*) buffer, + length, + &written, + NULL)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, + int y, unsigned char y_relative, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD pos; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + } + + pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); + + if (!SetConsoleCursorPosition(handle->handle, pos)) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + + +static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { + const COORD origin = {0, 0}; + const WORD char_attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + CONSOLE_SCREEN_BUFFER_INFO info; + DWORD count, written; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + /* Reset original text attributes. */ + if (!SetConsoleTextAttribute(handle->handle, char_attrs)) { + *error = GetLastError(); + return -1; + } + + /* Move the cursor position to (0, 0). */ + if (!SetConsoleCursorPosition(handle->handle, origin)) { + *error = GetLastError(); + return -1; + } + + /* Clear the screen buffer. */ + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + count = info.dwSize.X * info.dwSize.Y; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + origin, + &written) && + FillConsoleOutputAttribute(handle->handle, + char_attrs, + written, + origin, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + /* Move the virtual window up to the top. */ + uv_tty_virtual_offset = 0; + uv_tty_update_virtual_window(&info); + + return 0; +} + + +static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + COORD start, end; + DWORD count, written; + + int x1, x2, y1, y2; + int x1r, x2r, y1r, y2r; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (dir == 0) { + /* Clear from current position */ + x1 = 0; + x1r = 1; + } else { + /* Clear from column 0 */ + x1 = 0; + x1r = 0; + } + + if (dir == 1) { + /* Clear to current position */ + x2 = 0; + x2r = 1; + } else { + /* Clear to end of row. We pretend the console is 65536 characters wide, */ + /* uv_tty_make_real_coord will clip it to the actual console width. */ + x2 = 0xffff; + x2r = 0; + } + + if (!entire_screen) { + /* Stay on our own row */ + y1 = y2 = 0; + y1r = y2r = 1; + } else { + /* Apply columns direction to row */ + y1 = x1; + y1r = x1r; + y2 = x2; + y2r = x2r; + } + + retry: + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); + end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); + count = (end.Y * info.dwSize.X + end.X) - + (start.Y * info.dwSize.X + start.X) + 1; + + if (!(FillConsoleOutputCharacterW(handle->handle, + L'\x20', + count, + start, + &written) && + FillConsoleOutputAttribute(handle->handle, + info.wAttributes, + written, + start, + &written))) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + /* The console may be resized - retry */ + goto retry; + } else { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + + +static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { + unsigned short argc = handle->ansi_csi_argc; + unsigned short* argv = handle->ansi_csi_argv; + int i; + CONSOLE_SCREEN_BUFFER_INFO info; + + char fg_color = -1, bg_color = -1; + char fg_bright = -1, bg_bright = -1; + + if (argc == 0) { + /* Reset mode */ + fg_color = 7; + bg_color = 0; + fg_bright = 0; + bg_bright = 0; + } + + for (i = 0; i < argc; i++) { + short arg = argv[i]; + + if (arg == 0) { + /* Reset mode */ + fg_color = 7; + bg_color = 0; + fg_bright = 0; + bg_bright = 0; + + } else if (arg == 1) { + /* Foreground bright on */ + fg_bright = 1; + + } else if (arg == 2) { + /* Both bright off */ + fg_bright = 0; + bg_bright = 0; + + } else if (arg == 5) { + /* Background bright on */ + bg_bright = 1; + + } else if (arg == 21 || arg == 22) { + /* Foreground bright off */ + fg_bright = 0; + + } else if (arg == 25) { + /* Background bright off */ + bg_bright = 0; + + } else if (arg >= 30 && arg <= 37) { + /* Set foreground color */ + fg_color = arg - 30; + + } else if (arg == 39) { + /* Default text color */ + fg_color = 7; + fg_bright = 0; + + } else if (arg >= 40 && arg <= 47) { + /* Set background color */ + bg_color = arg - 40; + + } else if (arg == 49) { + /* Default background color */ + bg_color = 0; + bg_bright = 0; + + } else if (arg >= 90 && arg <= 97) { + /* Set bold foreground color */ + fg_bright = 1; + fg_color = arg - 90; + + } else if (arg >= 100 && arg <= 107) { + /* Set bold background color */ + bg_bright = 1; + bg_color = arg - 100; + + } + } + + if (fg_color == -1 && bg_color == -1 && fg_bright == -1 && + bg_bright == -1) { + /* Nothing changed */ + return 0; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + if (fg_color != -1) { + info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + if (fg_color & 1) info.wAttributes |= FOREGROUND_RED; + if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN; + if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE; + } + + if (fg_bright != -1) { + if (fg_bright) { + info.wAttributes |= FOREGROUND_INTENSITY; + } else { + info.wAttributes &= ~FOREGROUND_INTENSITY; + } + } + + if (bg_color != -1) { + info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + if (bg_color & 1) info.wAttributes |= BACKGROUND_RED; + if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN; + if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE; + } + + if (bg_bright != -1) { + if (bg_bright) { + info.wAttributes |= BACKGROUND_INTENSITY; + } else { + info.wAttributes &= ~BACKGROUND_INTENSITY; + } + } + + if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) { + *error = GetLastError(); + return -1; + } + + return 0; +} + + +static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, + DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + uv_tty_update_virtual_window(&info); + + handle->saved_position.X = info.dwCursorPosition.X; + handle->saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset; + handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; + + if (save_attributes) { + handle->saved_attributes = info.wAttributes & + (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES; + } + + return 0; +} + + +static int uv_tty_restore_state(uv_tty_t* handle, + unsigned char restore_attributes, DWORD* error) { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD new_attributes; + + if (*error != ERROR_SUCCESS) { + return -1; + } + + if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { + if (uv_tty_move_caret(handle, + handle->saved_position.X, + 0, + handle->saved_position.Y, + 0, + error) != 0) { + return -1; + } + } + + if (restore_attributes && + (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) { + if (!GetConsoleScreenBufferInfo(handle->handle, &info)) { + *error = GetLastError(); + return -1; + } + + new_attributes = info.wAttributes; + new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); + new_attributes |= handle->saved_attributes; + + if (!SetConsoleTextAttribute(handle->handle, new_attributes)) { + *error = GetLastError(); + return -1; + } + } + + return 0; +} + + +static int uv_tty_write_bufs(uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + DWORD* error) { + /* We can only write 8k characters at a time. Windows can't handle */ + /* much more characters in a single console write anyway. */ + WCHAR utf16_buf[8192]; + DWORD utf16_buf_used = 0; + unsigned int i; + +#define FLUSH_TEXT() \ + do { \ + if (utf16_buf_used > 0) { \ + uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ + utf16_buf_used = 0; \ + } \ + } while (0) + + /* Cache for fast access */ + unsigned char utf8_bytes_left = handle->utf8_bytes_left; + unsigned int utf8_codepoint = handle->utf8_codepoint; + unsigned char previous_eol = handle->previous_eol; + unsigned char ansi_parser_state = handle->ansi_parser_state; + + /* Store the error here. If we encounter an error, stop trying to do i/o */ + /* but keep parsing the buffer so we leave the parser in a consistent */ + /* state. */ + *error = ERROR_SUCCESS; + + EnterCriticalSection(&uv_tty_output_lock); + + for (i = 0; i < nbufs; i++) { + uv_buf_t buf = bufs[i]; + unsigned int j; + + for (j = 0; j < buf.len; j++) { + unsigned char c = buf.base[j]; + + /* Run the character through the utf8 decoder We happily accept non */ + /* shortest form encodings and invalid code points - there's no real */ + /* harm that can be done. */ + if (utf8_bytes_left == 0) { + /* Read utf-8 start byte */ + DWORD first_zero_bit; + unsigned char not_c = ~c; +#ifdef _MSC_VER /* msvc */ + if (_BitScanReverse(&first_zero_bit, not_c)) { +#else /* assume gcc */ + if (c != 0) { + first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c); +#endif + if (first_zero_bit == 7) { + /* Ascii - pass right through */ + utf8_codepoint = (unsigned int) c; + + } else if (first_zero_bit <= 5) { + /* Multibyte sequence */ + utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c; + utf8_bytes_left = (char) (6 - first_zero_bit); + + } else { + /* Invalid continuation */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else { + /* 0xff -- invalid */ + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + } else if ((c & 0xc0) == 0x80) { + /* Valid continuation of utf-8 multibyte sequence */ + utf8_bytes_left--; + utf8_codepoint <<= 6; + utf8_codepoint |= ((unsigned int) c & 0x3f); + + } else { + /* Start byte where continuation was expected. */ + utf8_bytes_left = 0; + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + /* Patch buf offset so this character will be parsed again as a */ + /* start byte. */ + j--; + } + + /* Maybe we need to parse more bytes to find a character. */ + if (utf8_bytes_left != 0) { + continue; + } + + /* Parse vt100/ansi escape codes */ + if (ansi_parser_state == ANSI_NORMAL) { + switch (utf8_codepoint) { + case '\033': + ansi_parser_state = ANSI_ESCAPE_SEEN; + continue; + + case 0233: + ansi_parser_state = ANSI_CSI; + handle->ansi_csi_argc = 0; + continue; + } + + } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) { + switch (utf8_codepoint) { + case '[': + ansi_parser_state = ANSI_CSI; + handle->ansi_csi_argc = 0; + continue; + + case '^': + case '_': + case 'P': + case ']': + /* Not supported, but we'll have to parse until we see a stop */ + /* code, e.g. ESC \ or BEL. */ + ansi_parser_state = ANSI_ST_CONTROL; + continue; + + case '\033': + /* Ignore double escape. */ + continue; + + case 'c': + /* Full console reset. */ + FLUSH_TEXT(); + uv_tty_reset(handle, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '7': + /* Save the cursor position and text attributes. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + case '8': + /* Restore the cursor position and text attributes */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 1, error); + ansi_parser_state = ANSI_NORMAL; + continue; + + default: + if (utf8_codepoint >= '@' && utf8_codepoint <= '_') { + /* Single-char control. */ + ansi_parser_state = ANSI_NORMAL; + continue; + } else { + /* Invalid - proceed as normal, */ + ansi_parser_state = ANSI_NORMAL; + } + } + + } else if (ansi_parser_state & ANSI_CSI) { + if (!(ansi_parser_state & ANSI_IGNORE)) { + if (utf8_codepoint >= '0' && utf8_codepoint <= '9') { + /* Parsing a numerical argument */ + + if (!(ansi_parser_state & ANSI_IN_ARG)) { + /* We were not currently parsing a number */ + + /* Check for too many arguments */ + if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + ansi_parser_state |= ANSI_IN_ARG; + handle->ansi_csi_argc++; + handle->ansi_csi_argv[handle->ansi_csi_argc - 1] = + (unsigned short) utf8_codepoint - '0'; + continue; + } else { + /* We were already parsing a number. Parse next digit. */ + uint32_t value = 10 * + handle->ansi_csi_argv[handle->ansi_csi_argc - 1]; + + /* Check for overflow. */ + if (value > UINT16_MAX) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->ansi_csi_argv[handle->ansi_csi_argc - 1] = + (unsigned short) value + (utf8_codepoint - '0'); + continue; + } + + } else if (utf8_codepoint == ';') { + /* Denotes the end of an argument. */ + if (ansi_parser_state & ANSI_IN_ARG) { + ansi_parser_state &= ~ANSI_IN_ARG; + continue; + + } else { + /* If ANSI_IN_ARG is not set, add another argument and */ + /* default it to 0. */ + /* Check for too many arguments */ + if (handle->ansi_csi_argc >= ARRAY_SIZE(handle->ansi_csi_argv)) { + ansi_parser_state |= ANSI_IGNORE; + continue; + } + + handle->ansi_csi_argc++; + handle->ansi_csi_argv[handle->ansi_csi_argc - 1] = 0; + continue; + } + + } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && + (handle->ansi_csi_argc > 0 || utf8_codepoint != '[')) { + int x, y, d; + + /* Command byte */ + switch (utf8_codepoint) { + case 'A': + /* cursor up */ + FLUSH_TEXT(); + y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'B': + /* cursor down */ + FLUSH_TEXT(); + y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 1, y, 1, error); + break; + + case 'C': + /* cursor forward */ + FLUSH_TEXT(); + x = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'D': + /* cursor back */ + FLUSH_TEXT(); + x = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, x, 1, 0, 1, error); + break; + + case 'E': + /* cursor next line */ + FLUSH_TEXT(); + y = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1; + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'F': + /* cursor previous line */ + FLUSH_TEXT(); + y = -(handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 1); + uv_tty_move_caret(handle, 0, 0, y, 1, error); + break; + + case 'G': + /* cursor horizontal move absolute */ + FLUSH_TEXT(); + x = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0]) + ? handle->ansi_csi_argv[0] - 1 : 0; + uv_tty_move_caret(handle, x, 0, 0, 1, error); + break; + + case 'H': + case 'f': + /* cursor move absolute */ + FLUSH_TEXT(); + y = (handle->ansi_csi_argc >= 1 && handle->ansi_csi_argv[0]) + ? handle->ansi_csi_argv[0] - 1 : 0; + x = (handle->ansi_csi_argc >= 2 && handle->ansi_csi_argv[1]) + ? handle->ansi_csi_argv[1] - 1 : 0; + uv_tty_move_caret(handle, x, 0, y, 0, error); + break; + + case 'J': + /* Erase screen */ + FLUSH_TEXT(); + d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 1, error); + } + break; + + case 'K': + /* Erase line */ + FLUSH_TEXT(); + d = handle->ansi_csi_argc ? handle->ansi_csi_argv[0] : 0; + if (d >= 0 && d <= 2) { + uv_tty_clear(handle, d, 0, error); + } + break; + + case 'm': + /* Set style */ + FLUSH_TEXT(); + uv_tty_set_style(handle, error); + break; + + case 's': + /* Save the cursor position. */ + FLUSH_TEXT(); + uv_tty_save_state(handle, 0, error); + break; + + case 'u': + /* Restore the cursor position */ + FLUSH_TEXT(); + uv_tty_restore_state(handle, 0, error); + break; + } + + /* Sequence ended - go back to normal state. */ + ansi_parser_state = ANSI_NORMAL; + continue; + + } else { + /* We don't support commands that use private mode characters or */ + /* intermediaries. Ignore the rest of the sequence. */ + ansi_parser_state |= ANSI_IGNORE; + continue; + } + } else { + /* We're ignoring this command. Stop only on command character. */ + if (utf8_codepoint >= '@' && utf8_codepoint <= '~') { + ansi_parser_state = ANSI_NORMAL; + } + continue; + } + + } else if (ansi_parser_state & ANSI_ST_CONTROL) { + /* Unsupported control code */ + /* Ignore everything until we see BEL or ESC \ */ + if (ansi_parser_state & ANSI_IN_STRING) { + if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { + if (utf8_codepoint == '"') { + ansi_parser_state &= ~ANSI_IN_STRING; + } else if (utf8_codepoint == '\\') { + ansi_parser_state |= ANSI_BACKSLASH_SEEN; + } + } else { + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } + } else { + if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' && + (ansi_parser_state & ANSI_ESCAPE_SEEN))) { + /* End of sequence */ + ansi_parser_state = ANSI_NORMAL; + } else if (utf8_codepoint == '\033') { + /* Escape character */ + ansi_parser_state |= ANSI_ESCAPE_SEEN; + } else if (utf8_codepoint == '"') { + /* String starting */ + ansi_parser_state |= ANSI_IN_STRING; + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + ansi_parser_state &= ~ANSI_BACKSLASH_SEEN; + } else { + ansi_parser_state &= ~ANSI_ESCAPE_SEEN; + } + } + continue; + } else { + /* Inconsistent state */ + abort(); + } + + /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */ + /* windows console doesn't really support UTF-16, so just emit the */ + /* replacement character. */ + if (utf8_codepoint > 0xffff) { + utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; + } + + if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) { + /* EOL conversion - emit \r\n, when we see either \r or \n. */ + /* If a \n immediately follows a \r or vice versa, ignore it. */ + if (previous_eol == 0 || utf8_codepoint == previous_eol) { + /* If there's no room in the utf16 buf, flush it first. */ + if (2 > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { + uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); + utf16_buf_used = 0; + } + + utf16_buf[utf16_buf_used++] = L'\r'; + utf16_buf[utf16_buf_used++] = L'\n'; + previous_eol = (char) utf8_codepoint; + } else { + /* Ignore this newline, but don't ignore later ones. */ + previous_eol = 0; + } + + } else if (utf8_codepoint <= 0xffff) { + /* Encode character into utf-16 buffer. */ + + /* If there's no room in the utf16 buf, flush it first. */ + if (1 > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { + uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); + utf16_buf_used = 0; + } + + utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint; + previous_eol = 0; + } + } + } + + /* Flush remaining characters */ + FLUSH_TEXT(); + + /* Copy cached values back to struct. */ + handle->utf8_bytes_left = utf8_bytes_left; + handle->utf8_codepoint = utf8_codepoint; + handle->previous_eol = previous_eol; + handle->ansi_parser_state = ansi_parser_state; + + LeaveCriticalSection(&uv_tty_output_lock); + + if (*error == STATUS_SUCCESS) { + return 0; + } else { + return -1; + } + +#undef FLUSH_TEXT +} + + +int uv_tty_write(uv_loop_t* loop, + uv_write_t* req, + uv_tty_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_write_cb cb) { + DWORD error; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_WRITE; + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + handle->reqs_pending++; + handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + + req->queued_bytes = 0; + + if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_ERROR(req, error); + } + + uv_insert_pending_req(loop, (uv_req_t*) req); + + return 0; +} + + +void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, + uv_write_t* req) { + int err; + + handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = GET_REQ_ERROR(req); + req->cb(req, uv_translate_sys_error(err)); + } + + handle->write_reqs_pending--; + if (handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_tty_close(uv_tty_t* handle) { + CloseHandle(handle->handle); + + if (handle->flags & UV_HANDLE_READING) + uv_tty_read_stop(handle); + + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(handle->loop, (uv_handle_t*) handle); + } +} + + +void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { + if (!(handle->flags && UV_HANDLE_TTY_READABLE) && + handle->shutdown_req != NULL && + handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + + /* TTY shutdown is really just a no-op */ + if (handle->shutdown_req->cb) { + if (handle->flags & UV__HANDLE_CLOSING) { + handle->shutdown_req->cb(handle->shutdown_req, UV_ECANCELED); + } else { + handle->shutdown_req->cb(handle->shutdown_req, 0); + } + } + + handle->shutdown_req = NULL; + + DECREASE_PENDING_REQ_COUNT(handle); + return; + } + + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + /* The console handle duplicate used for line reading should be destroyed */ + /* by uv_tty_read_stop. */ + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->read_line_handle == NULL); + + /* The wait handle used for raw reading should be unregistered when the */ + /* wait callback runs. */ + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->read_raw_wait == NULL); + + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +/* TODO: remove me */ +void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, + uv_req_t* raw_req) { + abort(); +} + + +/* TODO: remove me */ +void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, + uv_connect_t* req) { + abort(); +} + + +int uv_tty_reset_mode(void) { + /* Not necessary to do anything. */ + return 0; +} diff --git a/src/win/udp.c b/src/win/udp.c new file mode 100644 index 0000000000..31812e4642 --- /dev/null +++ b/src/win/udp.c @@ -0,0 +1,749 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + + +/* + * Threshold of active udp streams for which to preallocate udp read buffers. + */ +const unsigned int uv_active_udp_streams_threshold = 0; + +/* A zero-size buffer for use by uv_udp_read */ +static char uv_zero_[] = ""; + +int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, + int* namelen) { + int result; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + return UV_EINVAL; + } + + result = getsockname(handle->socket, name, namelen); + if (result != 0) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, + int family) { + DWORD yes = 1; + WSAPROTOCOL_INFOW info; + int opt_len; + + assert(handle->socket == INVALID_SOCKET); + + /* Set SO_REUSEADDR on the socket. */ + if (setsockopt(socket, + SOL_SOCKET, + SO_REUSEADDR, + (char*) &yes, + sizeof yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Set the socket to nonblocking mode */ + if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { + return WSAGetLastError(); + } + + /* Make the socket non-inheritable */ + if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) { + return GetLastError(); + } + + /* Associate it with the I/O completion port. */ + /* Use uv_handle_t pointer as completion key. */ + if (CreateIoCompletionPort((HANDLE)socket, + loop->iocp, + (ULONG_PTR)socket, + 0) == NULL) { + return GetLastError(); + } + + if (pSetFileCompletionNotificationModes) { + /* All know windowses that support SetFileCompletionNotificationModes */ + /* have a bug that makes it impossible to use this function in */ + /* conjunction with datagram sockets. We can work around that but only */ + /* if the user is using the default UDP driver (AFD) and has no other */ + /* LSPs stacked on top. Here we check whether that is the case. */ + opt_len = (int) sizeof info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &info, + &opt_len) == SOCKET_ERROR) { + return GetLastError(); + } + + if (info.ProtocolChain.ChainLen == 1) { + if (pSetFileCompletionNotificationModes((HANDLE)socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + handle->func_wsarecv = uv_wsarecv_workaround; + handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); + } + } + } + + handle->socket = socket; + + if (family == AF_INET6) { + handle->flags |= UV_HANDLE_IPV6; + } else { + assert(!(handle->flags & UV_HANDLE_IPV6)); + } + + return 0; +} + + +int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP); + + handle->socket = INVALID_SOCKET; + handle->reqs_pending = 0; + handle->activecnt = 0; + handle->func_wsarecv = WSARecv; + handle->func_wsarecvfrom = WSARecvFrom; + + uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); + handle->recv_req.type = UV_UDP_RECV; + handle->recv_req.data = handle; + + return 0; +} + + +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + + uv__handle_closing(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { + if (handle->flags & UV__HANDLE_CLOSING && + handle->reqs_pending == 0) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); + } +} + + +static int uv_udp_try_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int r; + int err; + DWORD no = 0; + + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { + /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ + return ERROR_INVALID_PARAMETER; + } + + if (handle->socket == INVALID_SOCKET) { + SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) { + return WSAGetLastError(); + } + + err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); + if (err) { + closesocket(sock); + return err; + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + } + + if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { + /* On windows IPV6ONLY is on by default. */ + /* If the user doesn't specify it libuv turns it off. */ + + /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ + /* available, or when run on XP/2003 which have no support for dualstack */ + /* sockets. For now we're silently ignoring the error. */ + setsockopt(handle->socket, + IPPROTO_IPV6, + IPV6_V6ONLY, + (char*) &no, + sizeof no); + } + + r = bind(handle->socket, addr, addrlen); + if (r == SOCKET_ERROR) { + return WSAGetLastError(); + } + + handle->flags |= UV_HANDLE_BOUND; + + return 0; +} + + +static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { + uv_req_t* req; + uv_buf_t buf; + DWORD bytes, flags; + int result; + + assert(handle->flags & UV_HANDLE_READING); + assert(!(handle->flags & UV_HANDLE_READ_PENDING)); + + req = &handle->recv_req; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (loop->active_udp_streams < uv_active_udp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + if (handle->recv_buffer.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); + return; + } + assert(handle->recv_buffer.base != NULL); + + buf = handle->recv_buffer; + memset(&handle->recv_from, 0, sizeof handle->recv_from); + handle->recv_from_len = sizeof handle->recv_from; + flags = 0; + + result = handle->func_wsarecvfrom(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &handle->recv_from, + &handle->recv_from_len, + &req->overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + + buf.base = (char*) uv_zero_; + buf.len = 0; + flags = MSG_PEEK; + + result = handle->func_wsarecv(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + &req->overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + handle->reqs_pending++; + } + } +} + + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + uv_loop_t* loop = handle->loop; + int err; + + if (handle->flags & UV_HANDLE_READING) { + return WSAEALREADY; + } + + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_udp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return err; + } + + handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); + loop->active_udp_streams++; + + handle->recv_cb = recv_cb; + handle->alloc_cb = alloc_cb; + + /* If reading was stopped and then started again, there could still be a */ + /* recv request pending. */ + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + uv_udp_queue_recv(loop, handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + return 0; +} + + +static int uv__send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb cb) { + uv_loop_t* loop = handle->loop; + DWORD result, bytes; + + uv_req_init(loop, (uv_req_t*) req); + req->type = UV_UDP_SEND; + req->handle = handle; + req->cb = cb; + memset(&req->overlapped, 0, sizeof(req->overlapped)); + + result = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + addr, + addrlen, + &req->overlapped, + NULL); + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Request completed immediately. */ + req->queued_bytes = 0; + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + uv_insert_pending_req(loop, (uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* Request queued by the kernel. */ + req->queued_bytes = uv_count_bufs(bufs, nbufs); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } else { + /* Send failed due to an error. */ + return WSAGetLastError(); + } + + return 0; +} + + +void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, + uv_req_t* req) { + uv_buf_t buf; + int partial; + + assert(handle->type == UV_UDP); + + handle->flags &= ~UV_HANDLE_READ_PENDING; + + if (!REQ_SUCCESS(req)) { + DWORD err = GET_REQ_SOCK_ERROR(req); + if (err == WSAEMSGSIZE) { + /* Not a real error, it just indicates that the received packet */ + /* was bigger than the receive buffer. */ + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* A previous sendto operation failed; ignore this error. If */ + /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */ + /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */ + /* immediately queue a new receive. */ + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + goto done; + } + } else { + /* A real error occurred. Report the error to the user only if we're */ + /* currently reading. */ + if (handle->flags & UV_HANDLE_READING) { + uv_udp_recv_stop(handle); + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->recv_buffer; + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + goto done; + } + } + + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* Successful read */ + partial = !REQ_SUCCESS(req); + handle->recv_cb(handle, + req->overlapped.InternalHigh, + &handle->recv_buffer, + (const struct sockaddr*) &handle->recv_from, + partial ? UV_UDP_PARTIAL : 0); + } else if (handle->flags & UV_HANDLE_READING) { + DWORD bytes, err, flags; + struct sockaddr_storage from; + int from_len; + + /* Do a nonblocking receive */ + /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + goto done; + } + assert(buf.base != NULL); + + memset(&from, 0, sizeof from); + from_len = sizeof from; + + flags = 0; + + if (WSARecvFrom(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &from, + &from_len, + NULL, + NULL) != SOCKET_ERROR) { + + /* Message received */ + handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); + } else { + err = WSAGetLastError(); + if (err == WSAEMSGSIZE) { + /* Message truncated */ + handle->recv_cb(handle, + bytes, + &buf, + (const struct sockaddr*) &from, + UV_UDP_PARTIAL); + } else if (err == WSAEWOULDBLOCK) { + /* Kernel buffer empty */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else if (err != WSAECONNRESET && err != WSAENETRESET) { + /* Serious error. WSAECONNRESET/WSANETRESET is ignored because this */ + /* just indicates that a previous sendto operation failed. */ + uv_udp_recv_stop(handle); + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } + } + } + +done: + /* Post another read if still reading and not closing. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_udp_queue_recv(loop, handle); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, + uv_udp_send_t* req) { + int err; + + assert(handle->type == UV_UDP); + + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (req->cb) { + err = 0; + if (!REQ_SUCCESS(req)) { + err = GET_REQ_SOCK_ERROR(req); + } + req->cb(req, uv_translate_sys_error(err)); + } + + DECREASE_PENDING_REQ_COUNT(handle); +} + + +int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, + const char* interface_addr, uv_membership membership) { + int err; + int optname; + struct ip_mreq mreq; + + /* If the socket is unbound, bind to inaddr_any. */ + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_udp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return uv_translate_sys_error(err); + } + + if (handle->flags & UV_HANDLE_IPV6) { + return UV_ENOSYS; + } + + memset(&mreq, 0, sizeof mreq); + + if (interface_addr) { + mreq.imr_interface.s_addr = inet_addr(interface_addr); + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr); + + switch (membership) { + case UV_JOIN_GROUP: + optname = IP_ADD_MEMBERSHIP; + break; + case UV_LEAVE_GROUP: + optname = IP_DROP_MEMBERSHIP; + break; + default: + return UV_EINVAL; + } + + if (setsockopt(handle->socket, + IPPROTO_IP, + optname, + (char*) &mreq, + sizeof mreq) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_set_broadcast(uv_udp_t* handle, int value) { + BOOL optval = (BOOL) value; + int err; + + /* If the socket is unbound, bind to inaddr_any. */ + if (!(handle->flags & UV_HANDLE_BOUND)) { + err = uv_udp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); + if (err) + return uv_translate_sys_error(err); + } + + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_BROADCAST, + (char*) &optval, + sizeof optval)) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + int err; + + /* Detect the address family of the socket. */ + opt_len = (int) sizeof protocol_info; + if (getsockopt(sock, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) { + return uv_translate_sys_error(GetLastError()); + } + + err = uv_udp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily); + return uv_translate_sys_error(err); +} + + +#define SOCKOPT_SETTER(name, option4, option6, validate) \ + int uv_udp_set_##name(uv_udp_t* handle, int value) { \ + DWORD optval = (DWORD) value; \ + int err; \ + \ + if (!(validate(value))) { \ + return UV_EINVAL; \ + } \ + \ + /* If the socket is unbound, bind to inaddr_any. */ \ + if (!(handle->flags & UV_HANDLE_BOUND)) { \ + err = uv_udp_try_bind(handle, \ + (const struct sockaddr*) &uv_addr_ip4_any_, \ + sizeof(uv_addr_ip4_any_), \ + 0); \ + if (err) \ + return uv_translate_sys_error(err); \ + } \ + \ + if (!(handle->flags & UV_HANDLE_IPV6)) { \ + /* Set IPv4 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IP, \ + option4, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } else { \ + /* Set IPv6 socket option */ \ + if (setsockopt(handle->socket, \ + IPPROTO_IPV6, \ + option6, \ + (char*) &optval, \ + sizeof optval)) { \ + return uv_translate_sys_error(WSAGetLastError()); \ + } \ + } \ + return 0; \ + } + +#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255) +#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255) +#define VALIDATE_MULTICAST_LOOP(value) (1) + +SOCKOPT_SETTER(ttl, + IP_TTL, + IPV6_HOPLIMIT, + VALIDATE_TTL) +SOCKOPT_SETTER(multicast_ttl, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + VALIDATE_MULTICAST_TTL) +SOCKOPT_SETTER(multicast_loop, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + VALIDATE_MULTICAST_LOOP) + +#undef SOCKOPT_SETTER +#undef VALIDATE_TTL +#undef VALIDATE_MULTICAST_TTL +#undef VALIDATE_MULTICAST_LOOP + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { + int err; + + err = uv_udp_try_bind(handle, addr, addrlen, flags); + if (err) + return uv_translate_sys_error(err); + + return 0; +} + + +/* This function is an egress point, i.e. it returns libuv errors rather than + * system errors. + */ +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen, + uv_udp_send_cb send_cb) { + const struct sockaddr* bind_addr; + int err; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + } else { + abort(); + } + err = uv_udp_try_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb); + if (err) + return uv_translate_sys_error(err); + + return 0; +} diff --git a/src/win/util.c b/src/win/util.c new file mode 100644 index 0000000000..266b881640 --- /dev/null +++ b/src/win/util.c @@ -0,0 +1,990 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + + +/* + * Max title length; the only thing MSDN tells us about the maximum length + * of the console title is that it is smaller than 64K. However in practice + * it is much smaller, and there is no way to figure out what the exact length + * of the title is or can be, at least not on XP. To make it even more + * annoying, GetConsoleTitle failes when the buffer to be read into is bigger + * than the actual maximum length. So we make a conservative guess here; + * just don't put the novel you're writing in the title, unless the plot + * survives truncation. + */ +#define MAX_TITLE_LENGTH 8192 + +/* The number of nanoseconds in one second. */ +#undef NANOSEC +#define NANOSEC 1000000000 + + +/* Cached copy of the process title, plus a mutex guarding it. */ +static char *process_title; +static CRITICAL_SECTION process_title_lock; + +/* Frequency (ticks per nanosecond) of the high-resolution clock. */ +static double hrtime_frequency_ = 0; + + +/* + * One-time intialization code for functionality defined in util.c. + */ +void uv__util_init() { + LARGE_INTEGER perf_frequency; + + /* Initialize process title access mutex. */ + InitializeCriticalSection(&process_title_lock); + + /* Retrieve high-resolution timer frequency. */ + if (QueryPerformanceFrequency(&perf_frequency)) + hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC; + else + hrtime_frequency_= 0; +} + + +int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, + char* utf8Buffer, size_t utf8Size) { + return WideCharToMultiByte(CP_UTF8, + 0, + utf16Buffer, + utf16Size, + utf8Buffer, + utf8Size, + NULL, + NULL); +} + + +int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, + size_t utf16Size) { + return MultiByteToWideChar(CP_UTF8, + 0, + utf8Buffer, + -1, + utf16Buffer, + utf16Size); +} + + +int uv_exepath(char* buffer, size_t* size_ptr) { + int utf8_len, utf16_buffer_len, utf16_len; + WCHAR* utf16_buffer; + int err; + + if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) { + return UV_EINVAL; + } + + if (*size_ptr > 32768) { + /* Windows paths can never be longer than this. */ + utf16_buffer_len = 32768; + } else { + utf16_buffer_len = (int) *size_ptr; + } + + utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len); + if (!utf16_buffer) { + return UV_ENOMEM; + } + + /* Get the path as UTF-16. */ + utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len); + if (utf16_len <= 0) { + err = GetLastError(); + goto error; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* Convert to UTF-8 */ + utf8_len = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr, + NULL, + NULL); + if (utf8_len == 0) { + err = GetLastError(); + goto error; + } + + free(utf16_buffer); + + /* utf8_len *does* include the terminating null at this point, but the */ + /* returned size shouldn't. */ + *size_ptr = utf8_len - 1; + return 0; + + error: + free(utf16_buffer); + return uv_translate_sys_error(err); +} + + +int uv_cwd(char* buffer, size_t size) { + DWORD utf16_len; + WCHAR utf16_buffer[MAX_PATH]; + int r; + + if (buffer == NULL || size == 0) { + return UV_EINVAL; + } + + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + /* This should be impossible; however the CRT has a code path to deal */ + /* with this scenario, so I added a check anyway. */ + return UV_EIO; + } + + /* utf16_len contains the length, *not* including the terminating null. */ + utf16_buffer[utf16_len] = L'\0'; + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + /* Convert to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + 0, + utf16_buffer, + -1, + buffer, + size > INT_MAX ? INT_MAX : (int) size, + NULL, + NULL); + if (r == 0) { + return uv_translate_sys_error(GetLastError()); + } + + return 0; +} + + +int uv_chdir(const char* dir) { + WCHAR utf16_buffer[MAX_PATH]; + size_t utf16_len; + WCHAR drive_letter, env_var[4]; + + if (dir == NULL) { + return UV_EINVAL; + } + + if (MultiByteToWideChar(CP_UTF8, + 0, + dir, + -1, + utf16_buffer, + MAX_PATH) == 0) { + DWORD error = GetLastError(); + /* The maximum length of the current working directory is 260 chars, */ + /* including terminating null. If it doesn't fit, the path name must be */ + /* too long. */ + if (error == ERROR_INSUFFICIENT_BUFFER) { + return UV_ENAMETOOLONG; + } else { + return uv_translate_sys_error(error); + } + } + + if (!SetCurrentDirectoryW(utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + + /* Windows stores the drive-local path in an "hidden" environment variable, */ + /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ + /* update this, so we'll have to do it. */ + utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); + if (utf16_len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (utf16_len > MAX_PATH) { + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed. */ + if (utf16_buffer[utf16_len - 1] == L'\\' && + !(utf16_len == 3 && utf16_buffer[1] == L':')) { + utf16_len--; + utf16_buffer[utf16_len] = L'\0'; + } + + if (utf16_len < 2 || utf16_buffer[1] != L':') { + /* Doesn't look like a drive letter could be there - probably an UNC */ + /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + drive_letter = 0; + } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { + drive_letter = utf16_buffer[0]; + } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') { + /* Convert to uppercase. */ + drive_letter = utf16_buffer[0] - L'a' + L'A'; + } else { + /* Not valid. */ + drive_letter = 0; + } + + if (drive_letter != 0) { + /* Construct the environment variable name and set it. */ + env_var[0] = L'='; + env_var[1] = drive_letter; + env_var[2] = L':'; + env_var[3] = L'\0'; + + if (!SetEnvironmentVariableW(env_var, utf16_buffer)) { + return uv_translate_sys_error(GetLastError()); + } + } + + return 0; +} + + +void uv_loadavg(double avg[3]) { + /* Can't be implemented */ + avg[0] = avg[1] = avg[2] = 0; +} + + +uint64_t uv_get_free_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if(!GlobalMemoryStatusEx(&memory_status)) + { + return -1; + } + + return (uint64_t)memory_status.ullAvailPhys; +} + + +uint64_t uv_get_total_memory(void) { + MEMORYSTATUSEX memory_status; + memory_status.dwLength = sizeof(memory_status); + + if(!GlobalMemoryStatusEx(&memory_status)) + { + return -1; + } + + return (uint64_t)memory_status.ullTotalPhys; +} + + +int uv_parent_pid() { + int parent_pid = -1; + HANDLE handle; + PROCESSENTRY32 pe; + int current_pid = GetCurrentProcessId(); + + pe.dwSize = sizeof(PROCESSENTRY32); + handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (Process32First(handle, &pe)) { + do { + if (pe.th32ProcessID == current_pid) { + parent_pid = pe.th32ParentProcessID; + break; + } + } while( Process32Next(handle, &pe)); + } + + CloseHandle(handle); + return parent_pid; +} + + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + int err; + int length; + WCHAR* title_w = NULL; + + uv__once_init(); + + /* Find out how big the buffer for the wide-char title must be */ + length = uv_utf8_to_utf16(title, NULL, 0); + if (!length) { + err = GetLastError(); + goto done; + } + + /* Convert to wide-char string */ + title_w = (WCHAR*)malloc(sizeof(WCHAR) * length); + if (!title_w) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + length = uv_utf8_to_utf16(title, title_w, length); + if (!length) { + err = GetLastError(); + goto done; + }; + + /* If the title must be truncated insert a \0 terminator there */ + if (length > MAX_TITLE_LENGTH) { + title_w[MAX_TITLE_LENGTH - 1] = L'\0'; + } + + if (!SetConsoleTitleW(title_w)) { + err = GetLastError(); + goto done; + } + + EnterCriticalSection(&process_title_lock); + free(process_title); + process_title = strdup(title); + LeaveCriticalSection(&process_title_lock); + + err = 0; + +done: + free(title_w); + return uv_translate_sys_error(err); +} + + +static int uv__get_process_title() { + WCHAR title_w[MAX_TITLE_LENGTH]; + int length; + + if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { + return -1; + } + + /* Find out what the size of the buffer is that we need */ + length = uv_utf16_to_utf8(title_w, -1, NULL, 0); + if (!length) { + return -1; + } + + assert(!process_title); + process_title = (char*)malloc(length); + if (!process_title) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + /* Do utf16 -> utf8 conversion here */ + if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) { + free(process_title); + return -1; + } + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + uv__once_init(); + + EnterCriticalSection(&process_title_lock); + /* + * If the process_title was never read before nor explicitly set, + * we must query it with getConsoleTitleW + */ + if (!process_title && uv__get_process_title() == -1) { + return uv_translate_sys_error(GetLastError()); + } + + assert(process_title); + strncpy(buffer, process_title, size); + LeaveCriticalSection(&process_title_lock); + + return 0; +} + + +uint64_t uv_hrtime(void) { + LARGE_INTEGER counter; + + uv__once_init(); + + /* If the performance frequency is zero, there's no support. */ + if (hrtime_frequency_ == 0) { + /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */ + return 0; + } + + if (!QueryPerformanceCounter(&counter)) { + /* uv__set_sys_error(loop, GetLastError()); */ + return 0; + } + + /* Because we have no guarantee about the order of magnitude of the + * performance counter frequency, integer math could cause this computation + * to overflow. Therefore we resort to floating point math. + */ + return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_); +} + + +int uv_resident_set_memory(size_t* rss) { + HANDLE current_process; + PROCESS_MEMORY_COUNTERS pmc; + + current_process = GetCurrentProcess(); + + if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) { + return uv_translate_sys_error(GetLastError()); + } + + *rss = pmc.WorkingSetSize; + + return 0; +} + + +int uv_uptime(double* uptime) { + BYTE stack_buffer[4096]; + BYTE* malloced_buffer = NULL; + BYTE* buffer = (BYTE*) stack_buffer; + size_t buffer_size = sizeof(stack_buffer); + DWORD data_size; + + PERF_DATA_BLOCK* data_block; + PERF_OBJECT_TYPE* object_type; + PERF_COUNTER_DEFINITION* counter_definition; + + DWORD i; + + for (;;) { + LONG result; + + data_size = (DWORD) buffer_size; + result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, + L"2", + NULL, + NULL, + buffer, + &data_size); + if (result == ERROR_SUCCESS) { + break; + } else if (result != ERROR_MORE_DATA) { + *uptime = 0; + return uv_translate_sys_error(result); + } + + free(malloced_buffer); + + buffer_size *= 2; + /* Don't let the buffer grow infinitely. */ + if (buffer_size > 1 << 20) { + goto internalError; + } + + buffer = malloced_buffer = (BYTE*) malloc(buffer_size); + if (malloced_buffer == NULL) { + *uptime = 0; + return UV_ENOMEM; + } + } + + if (data_size < sizeof(*data_block)) + goto internalError; + + data_block = (PERF_DATA_BLOCK*) buffer; + + if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) + goto internalError; + + if (data_size < data_block->HeaderLength + sizeof(*object_type)) + goto internalError; + + object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); + + if (object_type->NumInstances != PERF_NO_INSTANCES) + goto internalError; + + counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + + data_block->HeaderLength + object_type->HeaderLength); + for (i = 0; i < object_type->NumCounters; i++) { + if ((BYTE*) counter_definition + sizeof(*counter_definition) > + buffer + data_size) { + break; + } + + if (counter_definition->CounterNameTitleIndex == 674 && + counter_definition->CounterSize == sizeof(uint64_t)) { + if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || + !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { + goto internalError; + } else { + BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + + counter_definition->CounterOffset; + uint64_t value = *((uint64_t*) address); + *uptime = (double) (object_type->PerfTime.QuadPart - value) / + (double) object_type->PerfFreq.QuadPart; + free(malloced_buffer); + return 0; + } + } + + counter_definition = (PERF_COUNTER_DEFINITION*) + ((BYTE*) counter_definition + counter_definition->ByteLength); + } + + /* If we get here, the uptime value was not found. */ + free(malloced_buffer); + *uptime = 0; + return UV_ENOSYS; + + internalError: + free(malloced_buffer); + *uptime = 0; + return UV_EIO; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { + uv_cpu_info_t* cpu_infos; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; + DWORD sppi_size; + SYSTEM_INFO system_info; + DWORD cpu_count, r, i; + NTSTATUS status; + ULONG result_size; + int err; + uv_cpu_info_t* cpu_info; + + cpu_infos = NULL; + cpu_count = 0; + sppi = NULL; + + uv__once_init(); + + GetSystemInfo(&system_info); + cpu_count = system_info.dwNumberOfProcessors; + + cpu_infos = calloc(cpu_count, sizeof *cpu_infos); + if (cpu_infos == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + sppi_size = cpu_count * sizeof(*sppi); + sppi = malloc(sppi_size); + if (sppi == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (!NT_SUCCESS(status)) { + err = pRtlNtStatusToDosError(status); + goto error; + } + + assert(result_size == sppi_size); + + for (i = 0; i < cpu_count; i++) { + WCHAR key_name[128]; + HKEY processor_key; + DWORD cpu_speed; + DWORD cpu_speed_size = sizeof(cpu_speed); + WCHAR cpu_brand[256]; + DWORD cpu_brand_size = sizeof(cpu_brand); + int len; + + len = _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); + + assert(len > 0 && len < ARRAY_SIZE(key_name)); + + r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (r != ERROR_SUCCESS) { + err = GetLastError(); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"~MHz", + NULL, + NULL, + (BYTE*) &cpu_speed, + &cpu_speed_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + if (RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, + NULL, + (BYTE*) &cpu_brand, + &cpu_brand_size) != ERROR_SUCCESS) { + err = GetLastError(); + RegCloseKey(processor_key); + goto error; + } + + RegCloseKey(processor_key); + + cpu_info = &cpu_infos[i]; + cpu_info->speed = cpu_speed; + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - + sppi[i].IdleTime.QuadPart) / 10000; + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000; + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; + cpu_info->cpu_times.nice = 0; + + + len = WideCharToMultiByte(CP_UTF8, + 0, + cpu_brand, + cpu_brand_size / sizeof(WCHAR), + NULL, + 0, + NULL, + NULL); + if (len == 0) { + err = GetLastError(); + goto error; + } + + assert(len > 0); + + /* Allocate 1 extra byte for the null terminator. */ + cpu_info->model = malloc(len + 1); + if (cpu_info->model == NULL) { + err = ERROR_OUTOFMEMORY; + goto error; + } + + if (WideCharToMultiByte(CP_UTF8, + 0, + cpu_brand, + cpu_brand_size / sizeof(WCHAR), + cpu_info->model, + len, + NULL, + NULL) == 0) { + err = GetLastError(); + goto error; + } + + /* Ensure that cpu_info->model is null terminated. */ + cpu_info->model[len] = '\0'; + } + + free(sppi); + + *cpu_count_ptr = cpu_count; + *cpu_infos_ptr = cpu_infos; + + return 0; + + error: + /* This is safe because the cpu_infos array is zeroed on allocation. */ + for (i = 0; i < cpu_count; i++) + free(cpu_infos[i].model); + + free(cpu_infos); + free(sppi); + + return uv_translate_sys_error(err); +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) { + free(cpu_infos[i].model); + } + + free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses_ptr, + int* count_ptr) { + IP_ADAPTER_ADDRESSES* win_address_buf; + ULONG win_address_buf_size; + IP_ADAPTER_ADDRESSES* win_address; + + uv_interface_address_t* uv_address_buf; + char* name_buf; + size_t uv_address_buf_size; + uv_interface_address_t* uv_address; + + int count; + + /* Fetch the size of the adapters reported by windows, and then get the */ + /* list itself. */ + win_address_buf_size = 0; + win_address_buf = NULL; + + for (;;) { + ULONG r; + + /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ + /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ + /* win_address_buf_size. */ + r = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX, + NULL, + win_address_buf, + &win_address_buf_size); + + if (r == ERROR_SUCCESS) + break; + + free(win_address_buf); + + switch (r) { + case ERROR_BUFFER_OVERFLOW: + /* This happens when win_address_buf is NULL or too small to hold */ + /* all adapters. */ + win_address_buf = malloc(win_address_buf_size); + if (win_address_buf == NULL) + return UV_ENOMEM; + + continue; + + case ERROR_NO_DATA: { + /* No adapters were found. */ + uv_address_buf = malloc(1); + if (uv_address_buf == NULL) + return UV_ENOMEM; + + *count_ptr = 0; + *addresses_ptr = uv_address_buf; + + return 0; + } + + case ERROR_ADDRESS_NOT_ASSOCIATED: + return UV_EAGAIN; + + case ERROR_INVALID_PARAMETER: + /* MSDN says: + * "This error is returned for any of the following conditions: the + * SizePointer parameter is NULL, the Address parameter is not + * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for + * the parameters requested is greater than ULONG_MAX." + * Since the first two conditions are not met, it must be that the + * adapter data is too big. + */ + return UV_ENOBUFS; + + default: + /* Other (unspecified) errors can happen, but we don't have any */ + /* special meaning for them. */ + assert(r != ERROR_SUCCESS); + return uv_translate_sys_error(r); + } + } + + /* Count the number of enabled interfaces and compute how much space is */ + /* needed to store their info. */ + count = 0; + uv_address_buf_size = 0; + + for (win_address = win_address_buf; + win_address != NULL; + win_address = win_address->Next) { + /* Use IP_ADAPTER_UNICAST_ADDRESS_XP to retain backwards compatibility */ + /* with Windows XP */ + IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; + int name_size; + + /* Interfaces that are not 'up' should not be reported. Also skip */ + /* interfaces that have no associated unicast address, as to avoid */ + /* allocating space for the name for this interface. */ + if (win_address->OperStatus != IfOperStatusUp || + win_address->FirstUnicastAddress == NULL) + continue; + + /* Compute the size of the interface name. */ + name_size = WideCharToMultiByte(CP_UTF8, + 0, + win_address->FriendlyName, + -1, + NULL, + 0, + NULL, + FALSE); + if (name_size <= 0) { + free(win_address_buf); + return uv_translate_sys_error(GetLastError()); + } + uv_address_buf_size += name_size; + + /* Count the number of addresses associated with this interface, and */ + /* compute the size. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) + win_address->FirstUnicastAddress; + unicast_address != NULL; + unicast_address = unicast_address->Next) { + count++; + uv_address_buf_size += sizeof(uv_interface_address_t); + } + } + + /* Allocate space to store interface data plus adapter names. */ + uv_address_buf = malloc(uv_address_buf_size); + if (uv_address_buf == NULL) { + free(win_address_buf); + return UV_ENOMEM; + } + + /* Compute the start of the uv_interface_address_t array, and the place in */ + /* the buffer where the interface names will be stored. */ + uv_address = uv_address_buf; + name_buf = (char*) (uv_address_buf + count); + + /* Fill out the output buffer. */ + for (win_address = win_address_buf; + win_address != NULL; + win_address = win_address->Next) { + IP_ADAPTER_UNICAST_ADDRESS_XP* unicast_address; + IP_ADAPTER_PREFIX* prefix; + int name_size; + size_t max_name_size; + + if (win_address->OperStatus != IfOperStatusUp || + win_address->FirstUnicastAddress == NULL) + continue; + + /* Convert the interface name to UTF8. */ + max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; + if (max_name_size > (size_t) INT_MAX) + max_name_size = INT_MAX; + name_size = WideCharToMultiByte(CP_UTF8, + 0, + win_address->FriendlyName, + -1, + name_buf, + (int) max_name_size, + NULL, + FALSE); + if (name_size <= 0) { + free(win_address_buf); + free(uv_address_buf); + return uv_translate_sys_error(GetLastError()); + } + + prefix = win_address->FirstPrefix; + + /* Add an uv_interface_address_t element for every unicast address. */ + /* Walk the prefix list in tandem with the address list. */ + for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*) + win_address->FirstUnicastAddress; + unicast_address != NULL && prefix != NULL; + unicast_address = unicast_address->Next, prefix = prefix->Next) { + struct sockaddr* sa; + ULONG prefix_len; + + sa = unicast_address->Address.lpSockaddr; + prefix_len = prefix->PrefixLength; + + memset(uv_address, 0, sizeof *uv_address); + + uv_address->name = name_buf; + + if (win_address->PhysicalAddressLength == sizeof(uv_address->phys_addr)) { + memcpy(uv_address->phys_addr, + win_address->PhysicalAddress, + sizeof(uv_address->phys_addr)); + } + + uv_address->is_internal = + (win_address->IfType == IF_TYPE_SOFTWARE_LOOPBACK); + + if (sa->sa_family == AF_INET6) { + uv_address->address.address6 = *((struct sockaddr_in6 *) sa); + + uv_address->netmask.netmask6.sin6_family = AF_INET6; + memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3); + uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] = + 0xff << (8 - prefix_len % 8); + + } else { + uv_address->address.address4 = *((struct sockaddr_in *) sa); + + uv_address->netmask.netmask4.sin_family = AF_INET; + uv_address->netmask.netmask4.sin_addr.s_addr = + htonl(0xffffffff << (32 - prefix_len)); + } + + uv_address++; + } + + name_buf += name_size; + } + + free(win_address_buf); + + *addresses_ptr = uv_address_buf; + *count_ptr = count; + + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + free(addresses); +} diff --git a/src/win/winapi.c b/src/win/winapi.c new file mode 100644 index 0000000000..3e439ea5b2 --- /dev/null +++ b/src/win/winapi.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "internal.h" + + +/* Ntdll function pointers */ +sRtlNtStatusToDosError pRtlNtStatusToDosError; +sNtDeviceIoControlFile pNtDeviceIoControlFile; +sNtQueryInformationFile pNtQueryInformationFile; +sNtSetInformationFile pNtSetInformationFile; +sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +sCreateSymbolicLinkW pCreateSymbolicLinkW; +sCancelIoEx pCancelIoEx; +sInitializeSRWLock pInitializeSRWLock; +sAcquireSRWLockShared pAcquireSRWLockShared; +sAcquireSRWLockExclusive pAcquireSRWLockExclusive; +sTryAcquireSRWLockShared pTryAcquireSRWLockShared; +sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive; +sReleaseSRWLockShared pReleaseSRWLockShared; +sReleaseSRWLockExclusive pReleaseSRWLockExclusive; +sInitializeConditionVariable pInitializeConditionVariable; +sSleepConditionVariableCS pSleepConditionVariableCS; +sSleepConditionVariableSRW pSleepConditionVariableSRW; +sWakeAllConditionVariable pWakeAllConditionVariable; +sWakeConditionVariable pWakeConditionVariable; + + +void uv_winapi_init() { + HMODULE ntdll_module; + HMODULE kernel32_module; + + ntdll_module = GetModuleHandleA("ntdll.dll"); + if (ntdll_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( + ntdll_module, + "RtlNtStatusToDosError"); + if (pRtlNtStatusToDosError == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress( + ntdll_module, + "NtDeviceIoControlFile"); + if (pNtDeviceIoControlFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress( + ntdll_module, + "NtQueryInformationFile"); + if (pNtQueryInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress( + ntdll_module, + "NtSetInformationFile"); + if (pNtSetInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile) + GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile"); + if (pNtQueryVolumeInformationFile == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( + ntdll_module, + "NtQuerySystemInformation"); + if (pNtQuerySystemInformation == NULL) { + uv_fatal_error(GetLastError(), "GetProcAddress"); + } + + kernel32_module = GetModuleHandleA("kernel32.dll"); + if (kernel32_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( + kernel32_module, + "GetQueuedCompletionStatusEx"); + + pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) + GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); + + pCreateSymbolicLinkW = (sCreateSymbolicLinkW) + GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + + pCancelIoEx = (sCancelIoEx) + GetProcAddress(kernel32_module, "CancelIoEx"); + + pInitializeSRWLock = (sInitializeSRWLock) + GetProcAddress(kernel32_module, "InitializeSRWLock"); + + pAcquireSRWLockShared = (sAcquireSRWLockShared) + GetProcAddress(kernel32_module, "AcquireSRWLockShared"); + + pAcquireSRWLockExclusive = (sAcquireSRWLockExclusive) + GetProcAddress(kernel32_module, "AcquireSRWLockExclusive"); + + pTryAcquireSRWLockShared = (sTryAcquireSRWLockShared) + GetProcAddress(kernel32_module, "TryAcquireSRWLockShared"); + + pTryAcquireSRWLockExclusive = (sTryAcquireSRWLockExclusive) + GetProcAddress(kernel32_module, "TryAcquireSRWLockExclusive"); + + pReleaseSRWLockShared = (sReleaseSRWLockShared) + GetProcAddress(kernel32_module, "ReleaseSRWLockShared"); + + pReleaseSRWLockExclusive = (sReleaseSRWLockExclusive) + GetProcAddress(kernel32_module, "ReleaseSRWLockExclusive"); + + pInitializeConditionVariable = (sInitializeConditionVariable) + GetProcAddress(kernel32_module, "InitializeConditionVariable"); + + pSleepConditionVariableCS = (sSleepConditionVariableCS) + GetProcAddress(kernel32_module, "SleepConditionVariableCS"); + + pSleepConditionVariableSRW = (sSleepConditionVariableSRW) + GetProcAddress(kernel32_module, "SleepConditionVariableSRW"); + + pWakeAllConditionVariable = (sWakeAllConditionVariable) + GetProcAddress(kernel32_module, "WakeAllConditionVariable"); + + pWakeConditionVariable = (sWakeConditionVariable) + GetProcAddress(kernel32_module, "WakeConditionVariable"); +} diff --git a/src/win/winapi.h b/src/win/winapi.h new file mode 100644 index 0000000000..21d7fe4ac3 --- /dev/null +++ b/src/win/winapi.h @@ -0,0 +1,4648 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_WINAPI_H_ +#define UV_WIN_WINAPI_H_ + +#include + + +/* + * Ntdll headers + */ +#ifndef STATUS_SEVERITY_SUCCESS +# define STATUS_SEVERITY_SUCCESS 0x0 +#endif + +#ifndef STATUS_SEVERITY_INFORMATIONAL +# define STATUS_SEVERITY_INFORMATIONAL 0x1 +#endif + +#ifndef STATUS_SEVERITY_WARNING +# define STATUS_SEVERITY_WARNING 0x2 +#endif + +#ifndef STATUS_SEVERITY_ERROR +# define STATUS_SEVERITY_ERROR 0x3 +#endif + +#ifndef FACILITY_NTWIN32 +# define FACILITY_NTWIN32 0x7 +#endif + +#ifndef NT_SUCCESS +# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0) +#endif + +#ifndef NT_INFORMATION +# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1) +#endif + +#ifndef NT_WARNING +# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2) +#endif + +#ifndef NT_ERROR +# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3) +#endif + +#ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_0 +# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L) +#endif + +#ifndef STATUS_WAIT_1 +# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L) +#endif + +#ifndef STATUS_WAIT_2 +# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L) +#endif + +#ifndef STATUS_WAIT_3 +# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L) +#endif + +#ifndef STATUS_WAIT_63 +# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL) +#endif + +#ifndef STATUS_ABANDONED +# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_0 +# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L) +#endif + +#ifndef STATUS_ABANDONED_WAIT_63 +# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL) +#endif + +#ifndef STATUS_USER_APC +# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L) +#endif + +#ifndef STATUS_KERNEL_APC +# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L) +#endif + +#ifndef STATUS_ALERTED +# define STATUS_ALERTED ((NTSTATUS) 0x00000101L) +#endif + +#ifndef STATUS_TIMEOUT +# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L) +#endif + +#ifndef STATUS_PENDING +# define STATUS_PENDING ((NTSTATUS) 0x00000103L) +#endif + +#ifndef STATUS_REPARSE +# define STATUS_REPARSE ((NTSTATUS) 0x00000104L) +#endif + +#ifndef STATUS_MORE_ENTRIES +# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L) +#endif + +#ifndef STATUS_NOT_ALL_ASSIGNED +# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L) +#endif + +#ifndef STATUS_SOME_NOT_MAPPED +# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L) +#endif + +#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS +# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L) +#endif + +#ifndef STATUS_VOLUME_MOUNTED +# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L) +#endif + +#ifndef STATUS_RXACT_COMMITTED +# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL) +#endif + +#ifndef STATUS_NOTIFY_CLEANUP +# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL) +#endif + +#ifndef STATUS_NOTIFY_ENUM_DIR +# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL) +#endif + +#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT +# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL) +#endif + +#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED +# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL) +#endif + +#ifndef STATUS_PAGE_FAULT_TRANSITION +# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L) +#endif + +#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO +# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L) +#endif + +#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE +# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L) +#endif + +#ifndef STATUS_PAGE_FAULT_GUARD_PAGE +# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L) +#endif + +#ifndef STATUS_PAGE_FAULT_PAGING_FILE +# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L) +#endif + +#ifndef STATUS_CACHE_PAGE_LOCKED +# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L) +#endif + +#ifndef STATUS_CRASH_DUMP +# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L) +#endif + +#ifndef STATUS_BUFFER_ALL_ZEROS +# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L) +#endif + +#ifndef STATUS_REPARSE_OBJECT +# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L) +#endif + +#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED +# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L) +#endif + +#ifndef STATUS_TRANSLATION_COMPLETE +# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L) +#endif + +#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY +# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L) +#endif + +#ifndef STATUS_NOTHING_TO_TERMINATE +# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L) +#endif + +#ifndef STATUS_PROCESS_NOT_IN_JOB +# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L) +#endif + +#ifndef STATUS_PROCESS_IN_JOB +# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L) +#endif + +#ifndef STATUS_VOLSNAP_HIBERNATE_READY +# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L) +#endif + +#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY +# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L) +#endif + +#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED +# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L) +#endif + +#ifndef STATUS_INTERRUPT_STILL_CONNECTED +# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L) +#endif + +#ifndef STATUS_PROCESS_CLONED +# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS +# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL) +#endif + +#ifndef STATUS_FILE_LOCKED_WITH_WRITERS +# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL) +#endif + +#ifndef STATUS_RESOURCEMANAGER_READ_ONLY +# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_EMPTY +# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_FULL +# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L) +#endif + +#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA +# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L) +#endif + +#ifndef STATUS_RING_NEWLY_EMPTY +# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L) +#endif + +#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT +# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L) +#endif + +#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE +# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L) +#endif + +#ifndef STATUS_OPLOCK_HANDLE_CLOSED +# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L) +#endif + +#ifndef STATUS_WAIT_FOR_OPLOCK +# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L) +#endif + +#ifndef STATUS_OBJECT_NAME_EXISTS +# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L) +#endif + +#ifndef STATUS_THREAD_WAS_SUSPENDED +# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L) +#endif + +#ifndef STATUS_WORKING_SET_LIMIT_RANGE +# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L) +#endif + +#ifndef STATUS_IMAGE_NOT_AT_BASE +# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L) +#endif + +#ifndef STATUS_RXACT_STATE_CREATED +# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L) +#endif + +#ifndef STATUS_SEGMENT_NOTIFICATION +# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L) +#endif + +#ifndef STATUS_LOCAL_USER_SESSION_KEY +# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L) +#endif + +#ifndef STATUS_BAD_CURRENT_DIRECTORY +# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L) +#endif + +#ifndef STATUS_SERIAL_MORE_WRITES +# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L) +#endif + +#ifndef STATUS_REGISTRY_RECOVERED +# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L) +#endif + +#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP +# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL) +#endif + +#ifndef STATUS_FT_WRITE_RECOVERY +# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL) +#endif + +#ifndef STATUS_SERIAL_COUNTER_TIMEOUT +# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL) +#endif + +#ifndef STATUS_NULL_LM_PASSWORD +# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL +# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL) +#endif + +#ifndef STATUS_RECEIVE_EXPEDITED +# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L) +#endif + +#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED +# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L) +#endif + +#ifndef STATUS_EVENT_DONE +# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L) +#endif + +#ifndef STATUS_EVENT_PENDING +# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L) +#endif + +#ifndef STATUS_CHECKING_FILE_SYSTEM +# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L) +#endif + +#ifndef STATUS_FATAL_APP_EXIT +# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L) +#endif + +#ifndef STATUS_PREDEFINED_HANDLE +# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L) +#endif + +#ifndef STATUS_WAS_UNLOCKED +# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L) +#endif + +#ifndef STATUS_SERVICE_NOTIFICATION +# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L) +#endif + +#ifndef STATUS_WAS_LOCKED +# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L) +#endif + +#ifndef STATUS_LOG_HARD_ERROR +# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL) +#endif + +#ifndef STATUS_ALREADY_WIN32 +# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL) +#endif + +#ifndef STATUS_WX86_UNSIMULATE +# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL) +#endif + +#ifndef STATUS_WX86_CONTINUE +# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL) +#endif + +#ifndef STATUS_WX86_SINGLE_STEP +# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL) +#endif + +#ifndef STATUS_WX86_BREAKPOINT +# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CONTINUE +# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE +# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L) +#endif + +#ifndef STATUS_WX86_EXCEPTION_CHAIN +# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L) +#endif + +#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE +# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L) +#endif + +#ifndef STATUS_NO_YIELD_PERFORMED +# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L) +#endif + +#ifndef STATUS_TIMER_RESUME_IGNORED +# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L) +#endif + +#ifndef STATUS_ARBITRATION_UNHANDLED +# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L) +#endif + +#ifndef STATUS_CARDBUS_NOT_SUPPORTED +# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L) +#endif + +#ifndef STATUS_WX86_CREATEWX86TIB +# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L) +#endif + +#ifndef STATUS_MP_PROCESSOR_MISMATCH +# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L) +#endif + +#ifndef STATUS_HIBERNATED +# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL) +#endif + +#ifndef STATUS_RESUME_HIBERNATION +# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL) +#endif + +#ifndef STATUS_FIRMWARE_UPDATED +# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL) +#endif + +#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES +# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL) +#endif + +#ifndef STATUS_MESSAGE_RETRIEVED +# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL) +#endif + +#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST +# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L) +#endif + +#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION +# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L) +#endif + +#ifndef STATUS_ACCESS_AUDIT_BY_POLICY +# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L) +#endif + +#ifndef STATUS_ABANDON_HIBERFILE +# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L) +#endif + +#ifndef STATUS_BIZRULES_NOT_ENABLED +# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L) +#endif + +#ifndef STATUS_GUARD_PAGE_VIOLATION +# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT +# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L) +#endif + +#ifndef STATUS_BREAKPOINT +# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L) +#endif + +#ifndef STATUS_SINGLE_STEP +# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L) +#endif + +#ifndef STATUS_BUFFER_OVERFLOW +# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L) +#endif + +#ifndef STATUS_NO_MORE_FILES +# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L) +#endif + +#ifndef STATUS_WAKE_SYSTEM_DEBUGGER +# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L) +#endif + +#ifndef STATUS_HANDLES_CLOSED +# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL) +#endif + +#ifndef STATUS_NO_INHERITANCE +# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL) +#endif + +#ifndef STATUS_GUID_SUBSTITUTION_MADE +# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL) +#endif + +#ifndef STATUS_PARTIAL_COPY +# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL) +#endif + +#ifndef STATUS_DEVICE_PAPER_EMPTY +# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL) +#endif + +#ifndef STATUS_DEVICE_POWERED_OFF +# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL) +#endif + +#ifndef STATUS_DEVICE_OFF_LINE +# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L) +#endif + +#ifndef STATUS_DEVICE_BUSY +# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L) +#endif + +#ifndef STATUS_NO_MORE_EAS +# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L) +#endif + +#ifndef STATUS_INVALID_EA_NAME +# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L) +#endif + +#ifndef STATUS_EA_LIST_INCONSISTENT +# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L) +#endif + +#ifndef STATUS_INVALID_EA_FLAG +# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L) +#endif + +#ifndef STATUS_VERIFY_REQUIRED +# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L) +#endif + +#ifndef STATUS_EXTRANEOUS_INFORMATION +# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L) +#endif + +#ifndef STATUS_RXACT_COMMIT_NECESSARY +# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L) +#endif + +#ifndef STATUS_NO_MORE_ENTRIES +# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL) +#endif + +#ifndef STATUS_FILEMARK_DETECTED +# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL) +#endif + +#ifndef STATUS_MEDIA_CHANGED +# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL) +#endif + +#ifndef STATUS_BUS_RESET +# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL) +#endif + +#ifndef STATUS_END_OF_MEDIA +# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL) +#endif + +#ifndef STATUS_BEGINNING_OF_MEDIA +# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL) +#endif + +#ifndef STATUS_MEDIA_CHECK +# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L) +#endif + +#ifndef STATUS_SETMARK_DETECTED +# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L) +#endif + +#ifndef STATUS_NO_DATA_DETECTED +# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L) +#endif + +#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES +# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L) +#endif + +#ifndef STATUS_SERVER_HAS_OPEN_HANDLES +# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L) +#endif + +#ifndef STATUS_ALREADY_DISCONNECTED +# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L) +#endif + +#ifndef STATUS_LONGJUMP +# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L) +#endif + +#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED +# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L) +#endif + +#ifndef STATUS_PLUGPLAY_QUERY_VETOED +# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L) +#endif + +#ifndef STATUS_UNWIND_CONSOLIDATE +# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L) +#endif + +#ifndef STATUS_REGISTRY_HIVE_RECOVERED +# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INSECURE +# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL) +#endif + +#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE +# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL) +#endif + +#ifndef STATUS_STOPPED_ON_SYMLINK +# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL) +#endif + +#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK +# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL) +#endif + +#ifndef STATUS_NO_ACE_CONDITION +# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL) +#endif + +#ifndef STATUS_UNSUCCESSFUL +# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L) +#endif + +#ifndef STATUS_NOT_IMPLEMENTED +# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L) +#endif + +#ifndef STATUS_INVALID_INFO_CLASS +# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L) +#endif + +#ifndef STATUS_INFO_LENGTH_MISMATCH +# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L) +#endif + +#ifndef STATUS_ACCESS_VIOLATION +# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L) +#endif + +#ifndef STATUS_IN_PAGE_ERROR +# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA +# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L) +#endif + +#ifndef STATUS_INVALID_HANDLE +# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L) +#endif + +#ifndef STATUS_BAD_INITIAL_STACK +# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L) +#endif + +#ifndef STATUS_BAD_INITIAL_PC +# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL) +#endif + +#ifndef STATUS_INVALID_CID +# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL) +#endif + +#ifndef STATUS_TIMER_NOT_CANCELED +# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL) +#endif + +#ifndef STATUS_INVALID_PARAMETER +# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL) +#endif + +#ifndef STATUS_NO_SUCH_DEVICE +# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL) +#endif + +#ifndef STATUS_NO_SUCH_FILE +# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL) +#endif + +#ifndef STATUS_INVALID_DEVICE_REQUEST +# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L) +#endif + +#ifndef STATUS_END_OF_FILE +# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L) +#endif + +#ifndef STATUS_WRONG_VOLUME +# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L) +#endif + +#ifndef STATUS_NO_MEDIA_IN_DEVICE +# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L) +#endif + +#ifndef STATUS_UNRECOGNIZED_MEDIA +# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L) +#endif + +#ifndef STATUS_NONEXISTENT_SECTOR +# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L) +#endif + +#ifndef STATUS_MORE_PROCESSING_REQUIRED +# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L) +#endif + +#ifndef STATUS_NO_MEMORY +# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L) +#endif + +#ifndef STATUS_CONFLICTING_ADDRESSES +# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L) +#endif + +#ifndef STATUS_NOT_MAPPED_VIEW +# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L) +#endif + +#ifndef STATUS_UNABLE_TO_FREE_VM +# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL) +#endif + +#ifndef STATUS_UNABLE_TO_DELETE_SECTION +# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL) +#endif + +#ifndef STATUS_INVALID_SYSTEM_SERVICE +# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL) +#endif + +#ifndef STATUS_ILLEGAL_INSTRUCTION +# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL) +#endif + +#ifndef STATUS_INVALID_LOCK_SEQUENCE +# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL) +#endif + +#ifndef STATUS_INVALID_VIEW_SIZE +# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL) +#endif + +#ifndef STATUS_INVALID_FILE_FOR_SECTION +# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L) +#endif + +#ifndef STATUS_ALREADY_COMMITTED +# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L) +#endif + +#ifndef STATUS_ACCESS_DENIED +# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L) +#endif + +#ifndef STATUS_BUFFER_TOO_SMALL +# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L) +#endif + +#ifndef STATUS_OBJECT_TYPE_MISMATCH +# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L) +#endif + +#ifndef STATUS_NONCONTINUABLE_EXCEPTION +# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L) +#endif + +#ifndef STATUS_INVALID_DISPOSITION +# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L) +#endif + +#ifndef STATUS_UNWIND +# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L) +#endif + +#ifndef STATUS_BAD_STACK +# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L) +#endif + +#ifndef STATUS_INVALID_UNWIND_TARGET +# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L) +#endif + +#ifndef STATUS_NOT_LOCKED +# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL) +#endif + +#ifndef STATUS_PARITY_ERROR +# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL) +#endif + +#ifndef STATUS_UNABLE_TO_DECOMMIT_VM +# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL) +#endif + +#ifndef STATUS_NOT_COMMITTED +# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL) +#endif + +#ifndef STATUS_INVALID_PORT_ATTRIBUTES +# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL) +#endif + +#ifndef STATUS_PORT_MESSAGE_TOO_LONG +# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_MIX +# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L) +#endif + +#ifndef STATUS_INVALID_QUOTA_LOWER +# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L) +#endif + +#ifndef STATUS_DISK_CORRUPT_ERROR +# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L) +#endif + +#ifndef STATUS_OBJECT_NAME_INVALID +# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L) +#endif + +#ifndef STATUS_OBJECT_NAME_NOT_FOUND +# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L) +#endif + +#ifndef STATUS_OBJECT_NAME_COLLISION +# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L) +#endif + +#ifndef STATUS_PORT_DISCONNECTED +# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L) +#endif + +#ifndef STATUS_DEVICE_ALREADY_ATTACHED +# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L) +#endif + +#ifndef STATUS_OBJECT_PATH_INVALID +# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L) +#endif + +#ifndef STATUS_OBJECT_PATH_NOT_FOUND +# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL) +#endif + +#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD +# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL) +#endif + +#ifndef STATUS_DATA_OVERRUN +# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL) +#endif + +#ifndef STATUS_DATA_LATE_ERROR +# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL) +#endif + +#ifndef STATUS_DATA_ERROR +# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL) +#endif + +#ifndef STATUS_CRC_ERROR +# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL) +#endif + +#ifndef STATUS_SECTION_TOO_BIG +# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L) +#endif + +#ifndef STATUS_PORT_CONNECTION_REFUSED +# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L) +#endif + +#ifndef STATUS_INVALID_PORT_HANDLE +# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L) +#endif + +#ifndef STATUS_SHARING_VIOLATION +# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L) +#endif + +#ifndef STATUS_QUOTA_EXCEEDED +# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L) +#endif + +#ifndef STATUS_INVALID_PAGE_PROTECTION +# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L) +#endif + +#ifndef STATUS_MUTANT_NOT_OWNED +# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L) +#endif + +#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED +# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L) +#endif + +#ifndef STATUS_PORT_ALREADY_SET +# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L) +#endif + +#ifndef STATUS_SECTION_NOT_IMAGE +# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L) +#endif + +#ifndef STATUS_SUSPEND_COUNT_EXCEEDED +# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL) +#endif + +#ifndef STATUS_THREAD_IS_TERMINATING +# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL) +#endif + +#ifndef STATUS_BAD_WORKING_SET_LIMIT +# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL) +#endif + +#ifndef STATUS_INCOMPATIBLE_FILE_MAP +# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL) +#endif + +#ifndef STATUS_SECTION_PROTECTION +# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL) +#endif + +#ifndef STATUS_EAS_NOT_SUPPORTED +# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL) +#endif + +#ifndef STATUS_EA_TOO_LARGE +# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L) +#endif + +#ifndef STATUS_NONEXISTENT_EA_ENTRY +# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L) +#endif + +#ifndef STATUS_NO_EAS_ON_FILE +# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L) +#endif + +#ifndef STATUS_EA_CORRUPT_ERROR +# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L) +#endif + +#ifndef STATUS_FILE_LOCK_CONFLICT +# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L) +#endif + +#ifndef STATUS_LOCK_NOT_GRANTED +# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L) +#endif + +#ifndef STATUS_DELETE_PENDING +# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L) +#endif + +#ifndef STATUS_CTL_FILE_NOT_SUPPORTED +# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L) +#endif + +#ifndef STATUS_UNKNOWN_REVISION +# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L) +#endif + +#ifndef STATUS_REVISION_MISMATCH +# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L) +#endif + +#ifndef STATUS_INVALID_OWNER +# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL) +#endif + +#ifndef STATUS_INVALID_PRIMARY_GROUP +# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL) +#endif + +#ifndef STATUS_NO_IMPERSONATION_TOKEN +# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL) +#endif + +#ifndef STATUS_CANT_DISABLE_MANDATORY +# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL) +#endif + +#ifndef STATUS_NO_LOGON_SERVERS +# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL) +#endif + +#ifndef STATUS_NO_SUCH_LOGON_SESSION +# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL) +#endif + +#ifndef STATUS_NO_SUCH_PRIVILEGE +# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L) +#endif + +#ifndef STATUS_PRIVILEGE_NOT_HELD +# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L) +#endif + +#ifndef STATUS_INVALID_ACCOUNT_NAME +# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L) +#endif + +#ifndef STATUS_USER_EXISTS +# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L) +#endif + +#ifndef STATUS_NO_SUCH_USER +# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L) +#endif + +#ifndef STATUS_GROUP_EXISTS +# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L) +#endif + +#ifndef STATUS_NO_SUCH_GROUP +# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L) +#endif + +#ifndef STATUS_MEMBER_IN_GROUP +# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_GROUP +# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L) +#endif + +#ifndef STATUS_LAST_ADMIN +# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L) +#endif + +#ifndef STATUS_WRONG_PASSWORD +# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL) +#endif + +#ifndef STATUS_ILL_FORMED_PASSWORD +# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL) +#endif + +#ifndef STATUS_PASSWORD_RESTRICTION +# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL) +#endif + +#ifndef STATUS_LOGON_FAILURE +# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL) +#endif + +#ifndef STATUS_ACCOUNT_RESTRICTION +# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL) +#endif + +#ifndef STATUS_INVALID_LOGON_HOURS +# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL) +#endif + +#ifndef STATUS_INVALID_WORKSTATION +# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L) +#endif + +#ifndef STATUS_PASSWORD_EXPIRED +# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L) +#endif + +#ifndef STATUS_ACCOUNT_DISABLED +# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L) +#endif + +#ifndef STATUS_NONE_MAPPED +# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L) +#endif + +#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED +# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L) +#endif + +#ifndef STATUS_LUIDS_EXHAUSTED +# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L) +#endif + +#ifndef STATUS_INVALID_SUB_AUTHORITY +# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L) +#endif + +#ifndef STATUS_INVALID_ACL +# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L) +#endif + +#ifndef STATUS_INVALID_SID +# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L) +#endif + +#ifndef STATUS_INVALID_SECURITY_DESCR +# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L) +#endif + +#ifndef STATUS_PROCEDURE_NOT_FOUND +# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_FORMAT +# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL) +#endif + +#ifndef STATUS_NO_TOKEN +# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL) +#endif + +#ifndef STATUS_BAD_INHERITANCE_ACL +# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL) +#endif + +#ifndef STATUS_RANGE_NOT_LOCKED +# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL) +#endif + +#ifndef STATUS_DISK_FULL +# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL) +#endif + +#ifndef STATUS_SERVER_DISABLED +# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L) +#endif + +#ifndef STATUS_SERVER_NOT_DISABLED +# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L) +#endif + +#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED +# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L) +#endif + +#ifndef STATUS_GUIDS_EXHAUSTED +# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L) +#endif + +#ifndef STATUS_INVALID_ID_AUTHORITY +# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L) +#endif + +#ifndef STATUS_AGENTS_EXHAUSTED +# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L) +#endif + +#ifndef STATUS_INVALID_VOLUME_LABEL +# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L) +#endif + +#ifndef STATUS_SECTION_NOT_EXTENDED +# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L) +#endif + +#ifndef STATUS_NOT_MAPPED_DATA +# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L) +#endif + +#ifndef STATUS_RESOURCE_DATA_NOT_FOUND +# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L) +#endif + +#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND +# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL) +#endif + +#ifndef STATUS_RESOURCE_NAME_NOT_FOUND +# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL) +#endif + +#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED +# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL) +#endif + +#ifndef STATUS_FLOAT_DENORMAL_OPERAND +# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL) +#endif + +#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO +# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL) +#endif + +#ifndef STATUS_FLOAT_INEXACT_RESULT +# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL) +#endif + +#ifndef STATUS_FLOAT_INVALID_OPERATION +# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L) +#endif + +#ifndef STATUS_FLOAT_OVERFLOW +# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L) +#endif + +#ifndef STATUS_FLOAT_STACK_CHECK +# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L) +#endif + +#ifndef STATUS_FLOAT_UNDERFLOW +# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L) +#endif + +#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO +# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L) +#endif + +#ifndef STATUS_INTEGER_OVERFLOW +# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L) +#endif + +#ifndef STATUS_PRIVILEGED_INSTRUCTION +# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L) +#endif + +#ifndef STATUS_TOO_MANY_PAGING_FILES +# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L) +#endif + +#ifndef STATUS_FILE_INVALID +# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L) +#endif + +#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED +# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCES +# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL) +#endif + +#ifndef STATUS_DFS_EXIT_PATH_FOUND +# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL) +#endif + +#ifndef STATUS_DEVICE_DATA_ERROR +# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL) +#endif + +#ifndef STATUS_DEVICE_NOT_CONNECTED +# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL) +#endif + +#ifndef STATUS_DEVICE_POWER_FAILURE +# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL) +#endif + +#ifndef STATUS_FREE_VM_NOT_AT_BASE +# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL) +#endif + +#ifndef STATUS_MEMORY_NOT_ALLOCATED +# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L) +#endif + +#ifndef STATUS_WORKING_SET_QUOTA +# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L) +#endif + +#ifndef STATUS_MEDIA_WRITE_PROTECTED +# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L) +#endif + +#ifndef STATUS_DEVICE_NOT_READY +# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L) +#endif + +#ifndef STATUS_INVALID_GROUP_ATTRIBUTES +# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L) +#endif + +#ifndef STATUS_BAD_IMPERSONATION_LEVEL +# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L) +#endif + +#ifndef STATUS_CANT_OPEN_ANONYMOUS +# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L) +#endif + +#ifndef STATUS_BAD_VALIDATION_CLASS +# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L) +#endif + +#ifndef STATUS_BAD_TOKEN_TYPE +# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L) +#endif + +#ifndef STATUS_BAD_MASTER_BOOT_RECORD +# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L) +#endif + +#ifndef STATUS_INSTRUCTION_MISALIGNMENT +# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL) +#endif + +#ifndef STATUS_INSTANCE_NOT_AVAILABLE +# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL) +#endif + +#ifndef STATUS_PIPE_NOT_AVAILABLE +# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL) +#endif + +#ifndef STATUS_INVALID_PIPE_STATE +# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL) +#endif + +#ifndef STATUS_PIPE_BUSY +# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL) +#endif + +#ifndef STATUS_ILLEGAL_FUNCTION +# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL) +#endif + +#ifndef STATUS_PIPE_DISCONNECTED +# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L) +#endif + +#ifndef STATUS_PIPE_CLOSING +# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L) +#endif + +#ifndef STATUS_PIPE_CONNECTED +# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L) +#endif + +#ifndef STATUS_PIPE_LISTENING +# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L) +#endif + +#ifndef STATUS_INVALID_READ_MODE +# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L) +#endif + +#ifndef STATUS_IO_TIMEOUT +# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L) +#endif + +#ifndef STATUS_FILE_FORCED_CLOSED +# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L) +#endif + +#ifndef STATUS_PROFILING_NOT_STARTED +# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L) +#endif + +#ifndef STATUS_PROFILING_NOT_STOPPED +# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L) +#endif + +#ifndef STATUS_COULD_NOT_INTERPRET +# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L) +#endif + +#ifndef STATUS_FILE_IS_A_DIRECTORY +# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL) +#endif + +#ifndef STATUS_NOT_SUPPORTED +# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL) +#endif + +#ifndef STATUS_REMOTE_NOT_LISTENING +# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL) +#endif + +#ifndef STATUS_DUPLICATE_NAME +# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL) +#endif + +#ifndef STATUS_BAD_NETWORK_PATH +# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL) +#endif + +#ifndef STATUS_NETWORK_BUSY +# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL) +#endif + +#ifndef STATUS_DEVICE_DOES_NOT_EXIST +# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L) +#endif + +#ifndef STATUS_TOO_MANY_COMMANDS +# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L) +#endif + +#ifndef STATUS_ADAPTER_HARDWARE_ERROR +# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L) +#endif + +#ifndef STATUS_INVALID_NETWORK_RESPONSE +# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L) +#endif + +#ifndef STATUS_UNEXPECTED_NETWORK_ERROR +# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L) +#endif + +#ifndef STATUS_BAD_REMOTE_ADAPTER +# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L) +#endif + +#ifndef STATUS_PRINT_QUEUE_FULL +# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L) +#endif + +#ifndef STATUS_NO_SPOOL_SPACE +# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L) +#endif + +#ifndef STATUS_PRINT_CANCELLED +# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L) +#endif + +#ifndef STATUS_NETWORK_NAME_DELETED +# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L) +#endif + +#ifndef STATUS_NETWORK_ACCESS_DENIED +# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL) +#endif + +#ifndef STATUS_BAD_DEVICE_TYPE +# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL) +#endif + +#ifndef STATUS_BAD_NETWORK_NAME +# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL) +#endif + +#ifndef STATUS_TOO_MANY_NAMES +# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL) +#endif + +#ifndef STATUS_TOO_MANY_SESSIONS +# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL) +#endif + +#ifndef STATUS_SHARING_PAUSED +# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL) +#endif + +#ifndef STATUS_REQUEST_NOT_ACCEPTED +# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L) +#endif + +#ifndef STATUS_REDIRECTOR_PAUSED +# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L) +#endif + +#ifndef STATUS_NET_WRITE_FAULT +# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L) +#endif + +#ifndef STATUS_PROFILING_AT_LIMIT +# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L) +#endif + +#ifndef STATUS_NOT_SAME_DEVICE +# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L) +#endif + +#ifndef STATUS_FILE_RENAMED +# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L) +#endif + +#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED +# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L) +#endif + +#ifndef STATUS_NO_SECURITY_ON_OBJECT +# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L) +#endif + +#ifndef STATUS_CANT_WAIT +# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L) +#endif + +#ifndef STATUS_PIPE_EMPTY +# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L) +#endif + +#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO +# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL) +#endif + +#ifndef STATUS_CANT_TERMINATE_SELF +# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL) +#endif + +#ifndef STATUS_INVALID_SERVER_STATE +# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_STATE +# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL) +#endif + +#ifndef STATUS_INVALID_DOMAIN_ROLE +# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL) +#endif + +#ifndef STATUS_NO_SUCH_DOMAIN +# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL) +#endif + +#ifndef STATUS_DOMAIN_EXISTS +# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L) +#endif + +#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED +# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L) +#endif + +#ifndef STATUS_OPLOCK_NOT_GRANTED +# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L) +#endif + +#ifndef STATUS_INVALID_OPLOCK_PROTOCOL +# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L) +#endif + +#ifndef STATUS_INTERNAL_DB_CORRUPTION +# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L) +#endif + +#ifndef STATUS_INTERNAL_ERROR +# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L) +#endif + +#ifndef STATUS_GENERIC_NOT_MAPPED +# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L) +#endif + +#ifndef STATUS_BAD_DESCRIPTOR_FORMAT +# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L) +#endif + +#ifndef STATUS_INVALID_USER_BUFFER +# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L) +#endif + +#ifndef STATUS_UNEXPECTED_IO_ERROR +# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L) +#endif + +#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR +# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR +# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL) +#endif + +#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR +# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL) +#endif + +#ifndef STATUS_NOT_LOGON_PROCESS +# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL) +#endif + +#ifndef STATUS_LOGON_SESSION_EXISTS +# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_1 +# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL) +#endif + +#ifndef STATUS_INVALID_PARAMETER_2 +# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_3 +# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_4 +# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_5 +# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_6 +# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_7 +# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_8 +# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_9 +# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_10 +# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_11 +# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L) +#endif + +#ifndef STATUS_INVALID_PARAMETER_12 +# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL) +#endif + +#ifndef STATUS_REDIRECTOR_NOT_STARTED +# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL) +#endif + +#ifndef STATUS_REDIRECTOR_STARTED +# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL) +#endif + +#ifndef STATUS_STACK_OVERFLOW +# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL) +#endif + +#ifndef STATUS_NO_SUCH_PACKAGE +# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL) +#endif + +#ifndef STATUS_BAD_FUNCTION_TABLE +# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL) +#endif + +#ifndef STATUS_VARIABLE_NOT_FOUND +# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L) +#endif + +#ifndef STATUS_DIRECTORY_NOT_EMPTY +# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L) +#endif + +#ifndef STATUS_FILE_CORRUPT_ERROR +# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L) +#endif + +#ifndef STATUS_NOT_A_DIRECTORY +# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L) +#endif + +#ifndef STATUS_BAD_LOGON_SESSION_STATE +# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L) +#endif + +#ifndef STATUS_LOGON_SESSION_COLLISION +# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L) +#endif + +#ifndef STATUS_NAME_TOO_LONG +# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L) +#endif + +#ifndef STATUS_FILES_OPEN +# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L) +#endif + +#ifndef STATUS_CONNECTION_IN_USE +# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L) +#endif + +#ifndef STATUS_MESSAGE_NOT_FOUND +# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L) +#endif + +#ifndef STATUS_PROCESS_IS_TERMINATING +# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL) +#endif + +#ifndef STATUS_INVALID_LOGON_TYPE +# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL) +#endif + +#ifndef STATUS_NO_GUID_TRANSLATION +# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL) +#endif + +#ifndef STATUS_CANNOT_IMPERSONATE +# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED +# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL) +#endif + +#ifndef STATUS_ABIOS_NOT_PRESENT +# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL) +#endif + +#ifndef STATUS_ABIOS_LID_NOT_EXIST +# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L) +#endif + +#ifndef STATUS_ABIOS_LID_ALREADY_OWNED +# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L) +#endif + +#ifndef STATUS_ABIOS_NOT_LID_OWNER +# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L) +#endif + +#ifndef STATUS_ABIOS_INVALID_COMMAND +# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L) +#endif + +#ifndef STATUS_ABIOS_INVALID_LID +# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L) +#endif + +#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE +# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L) +#endif + +#ifndef STATUS_ABIOS_INVALID_SELECTOR +# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L) +#endif + +#ifndef STATUS_NO_LDT +# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L) +#endif + +#ifndef STATUS_INVALID_LDT_SIZE +# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L) +#endif + +#ifndef STATUS_INVALID_LDT_OFFSET +# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L) +#endif + +#ifndef STATUS_INVALID_LDT_DESCRIPTOR +# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NE_FORMAT +# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL) +#endif + +#ifndef STATUS_RXACT_INVALID_STATE +# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL) +#endif + +#ifndef STATUS_RXACT_COMMIT_FAILURE +# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL) +#endif + +#ifndef STATUS_MAPPED_FILE_SIZE_ZERO +# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL) +#endif + +#ifndef STATUS_TOO_MANY_OPENED_FILES +# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL) +#endif + +#ifndef STATUS_CANCELLED +# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L) +#endif + +#ifndef STATUS_CANNOT_DELETE +# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L) +#endif + +#ifndef STATUS_INVALID_COMPUTER_NAME +# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L) +#endif + +#ifndef STATUS_FILE_DELETED +# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L) +#endif + +#ifndef STATUS_SPECIAL_ACCOUNT +# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L) +#endif + +#ifndef STATUS_SPECIAL_GROUP +# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L) +#endif + +#ifndef STATUS_SPECIAL_USER +# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L) +#endif + +#ifndef STATUS_MEMBERS_PRIMARY_GROUP +# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L) +#endif + +#ifndef STATUS_FILE_CLOSED +# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L) +#endif + +#ifndef STATUS_TOO_MANY_THREADS +# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L) +#endif + +#ifndef STATUS_THREAD_NOT_IN_PROCESS +# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL) +#endif + +#ifndef STATUS_TOKEN_ALREADY_IN_USE +# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL) +#endif + +#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED +# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL) +#endif + +#ifndef STATUS_COMMITMENT_LIMIT +# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL) +#endif + +#ifndef STATUS_INVALID_IMAGE_LE_FORMAT +# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL) +#endif + +#ifndef STATUS_INVALID_IMAGE_NOT_MZ +# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL) +#endif + +#ifndef STATUS_INVALID_IMAGE_PROTECT +# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_16 +# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L) +#endif + +#ifndef STATUS_LOGON_SERVER_CONFLICT +# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L) +#endif + +#ifndef STATUS_TIME_DIFFERENCE_AT_DC +# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L) +#endif + +#ifndef STATUS_SYNCHRONIZATION_REQUIRED +# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L) +#endif + +#ifndef STATUS_DLL_NOT_FOUND +# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L) +#endif + +#ifndef STATUS_OPEN_FAILED +# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L) +#endif + +#ifndef STATUS_IO_PRIVILEGE_FAILED +# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L) +#endif + +#ifndef STATUS_ORDINAL_NOT_FOUND +# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L) +#endif + +#ifndef STATUS_ENTRYPOINT_NOT_FOUND +# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L) +#endif + +#ifndef STATUS_CONTROL_C_EXIT +# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL) +#endif + +#ifndef STATUS_LOCAL_DISCONNECT +# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL) +#endif + +#ifndef STATUS_REMOTE_DISCONNECT +# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL) +#endif + +#ifndef STATUS_REMOTE_RESOURCES +# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL) +#endif + +#ifndef STATUS_LINK_FAILED +# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL) +#endif + +#ifndef STATUS_LINK_TIMEOUT +# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL) +#endif + +#ifndef STATUS_INVALID_CONNECTION +# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L) +#endif + +#ifndef STATUS_INVALID_ADDRESS +# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L) +#endif + +#ifndef STATUS_DLL_INIT_FAILED +# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L) +#endif + +#ifndef STATUS_MISSING_SYSTEMFILE +# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L) +#endif + +#ifndef STATUS_UNHANDLED_EXCEPTION +# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L) +#endif + +#ifndef STATUS_APP_INIT_FAILURE +# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L) +#endif + +#ifndef STATUS_PAGEFILE_CREATE_FAILED +# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L) +#endif + +#ifndef STATUS_NO_PAGEFILE +# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L) +#endif + +#ifndef STATUS_INVALID_LEVEL +# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L) +#endif + +#ifndef STATUS_WRONG_PASSWORD_CORE +# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L) +#endif + +#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT +# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL) +#endif + +#ifndef STATUS_PIPE_BROKEN +# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL) +#endif + +#ifndef STATUS_REGISTRY_CORRUPT +# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL) +#endif + +#ifndef STATUS_REGISTRY_IO_FAILED +# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL) +#endif + +#ifndef STATUS_NO_EVENT_PAIR +# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL) +#endif + +#ifndef STATUS_UNRECOGNIZED_VOLUME +# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL) +#endif + +#ifndef STATUS_SERIAL_NO_DEVICE_INITED +# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L) +#endif + +#ifndef STATUS_NO_SUCH_ALIAS +# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L) +#endif + +#ifndef STATUS_MEMBER_NOT_IN_ALIAS +# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L) +#endif + +#ifndef STATUS_MEMBER_IN_ALIAS +# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L) +#endif + +#ifndef STATUS_ALIAS_EXISTS +# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L) +#endif + +#ifndef STATUS_LOGON_NOT_GRANTED +# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L) +#endif + +#ifndef STATUS_TOO_MANY_SECRETS +# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L) +#endif + +#ifndef STATUS_SECRET_TOO_LONG +# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L) +#endif + +#ifndef STATUS_INTERNAL_DB_ERROR +# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L) +#endif + +#ifndef STATUS_FULLSCREEN_MODE +# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L) +#endif + +#ifndef STATUS_TOO_MANY_CONTEXT_IDS +# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL) +#endif + +#ifndef STATUS_LOGON_TYPE_NOT_GRANTED +# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL) +#endif + +#ifndef STATUS_NOT_REGISTRY_FILE +# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL) +#endif + +#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED +# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL) +#endif + +#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR +# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL) +#endif + +#ifndef STATUS_FT_MISSING_MEMBER +# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL) +#endif + +#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY +# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L) +#endif + +#ifndef STATUS_ILLEGAL_CHARACTER +# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L) +#endif + +#ifndef STATUS_UNMAPPABLE_CHARACTER +# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L) +#endif + +#ifndef STATUS_UNDEFINED_CHARACTER +# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L) +#endif + +#ifndef STATUS_FLOPPY_VOLUME +# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L) +#endif + +#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND +# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L) +#endif + +#ifndef STATUS_FLOPPY_WRONG_CYLINDER +# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L) +#endif + +#ifndef STATUS_FLOPPY_UNKNOWN_ERROR +# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L) +#endif + +#ifndef STATUS_FLOPPY_BAD_REGISTERS +# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L) +#endif + +#ifndef STATUS_DISK_RECALIBRATE_FAILED +# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L) +#endif + +#ifndef STATUS_DISK_OPERATION_FAILED +# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL) +#endif + +#ifndef STATUS_DISK_RESET_FAILED +# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL) +#endif + +#ifndef STATUS_SHARED_IRQ_BUSY +# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL) +#endif + +#ifndef STATUS_FT_ORPHANING +# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL) +#endif + +#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT +# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL) +#endif + +#ifndef STATUS_PARTITION_FAILURE +# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L) +#endif + +#ifndef STATUS_INVALID_BLOCK_LENGTH +# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L) +#endif + +#ifndef STATUS_DEVICE_NOT_PARTITIONED +# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L) +#endif + +#ifndef STATUS_UNABLE_TO_LOCK_MEDIA +# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L) +#endif + +#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA +# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L) +#endif + +#ifndef STATUS_EOM_OVERFLOW +# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L) +#endif + +#ifndef STATUS_NO_MEDIA +# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L) +#endif + +#ifndef STATUS_NO_SUCH_MEMBER +# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL) +#endif + +#ifndef STATUS_INVALID_MEMBER +# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL) +#endif + +#ifndef STATUS_KEY_DELETED +# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL) +#endif + +#ifndef STATUS_NO_LOG_SPACE +# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL) +#endif + +#ifndef STATUS_TOO_MANY_SIDS +# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL) +#endif + +#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED +# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL) +#endif + +#ifndef STATUS_KEY_HAS_CHILDREN +# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L) +#endif + +#ifndef STATUS_CHILD_MUST_BE_VOLATILE +# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L) +#endif + +#ifndef STATUS_DEVICE_CONFIGURATION_ERROR +# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L) +#endif + +#ifndef STATUS_DRIVER_INTERNAL_ERROR +# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L) +#endif + +#ifndef STATUS_INVALID_DEVICE_STATE +# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L) +#endif + +#ifndef STATUS_IO_DEVICE_ERROR +# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L) +#endif + +#ifndef STATUS_DEVICE_PROTOCOL_ERROR +# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L) +#endif + +#ifndef STATUS_BACKUP_CONTROLLER +# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L) +#endif + +#ifndef STATUS_LOG_FILE_FULL +# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L) +#endif + +#ifndef STATUS_TOO_LATE +# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L) +#endif + +#ifndef STATUS_NO_TRUST_LSA_SECRET +# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL) +#endif + +#ifndef STATUS_NO_TRUST_SAM_ACCOUNT +# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL) +#endif + +#ifndef STATUS_TRUSTED_DOMAIN_FAILURE +# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL) +#endif + +#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE +# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CORRUPT +# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL) +#endif + +#ifndef STATUS_EVENTLOG_CANT_START +# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL) +#endif + +#ifndef STATUS_TRUST_FAILURE +# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L) +#endif + +#ifndef STATUS_MUTANT_LIMIT_EXCEEDED +# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L) +#endif + +#ifndef STATUS_NETLOGON_NOT_STARTED +# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L) +#endif + +#ifndef STATUS_ACCOUNT_EXPIRED +# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L) +#endif + +#ifndef STATUS_POSSIBLE_DEADLOCK +# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L) +#endif + +#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT +# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L) +#endif + +#ifndef STATUS_REMOTE_SESSION_LIMIT +# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L) +#endif + +#ifndef STATUS_EVENTLOG_FILE_CHANGED +# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L) +#endif + +#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT +# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L) +#endif + +#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT +# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L) +#endif + +#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT +# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL) +#endif + +#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT +# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL) +#endif + +#ifndef STATUS_FS_DRIVER_REQUIRED +# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL) +#endif + +#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL +# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL) +#endif + +#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING +# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL) +#endif + +#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME +# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL) +#endif + +#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT +# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L) +#endif + +#ifndef STATUS_INVALID_LOCK_RANGE +# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L) +#endif + +#ifndef STATUS_INVALID_ACE_CONDITION +# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L) +#endif + +#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT +# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L) +#endif + +#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED +# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L) +#endif + +#ifndef STATUS_NETWORK_OPEN_RESTRICTION +# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L) +#endif + +#ifndef STATUS_NO_USER_SESSION_KEY +# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L) +#endif + +#ifndef STATUS_USER_SESSION_DELETED +# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L) +#endif + +#ifndef STATUS_RESOURCE_LANG_NOT_FOUND +# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L) +#endif + +#ifndef STATUS_INSUFF_SERVER_RESOURCES +# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L) +#endif + +#ifndef STATUS_INVALID_BUFFER_SIZE +# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_COMPONENT +# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L) +#endif + +#ifndef STATUS_INVALID_ADDRESS_WILDCARD +# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L) +#endif + +#ifndef STATUS_TOO_MANY_ADDRESSES +# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_EXISTS +# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL) +#endif + +#ifndef STATUS_ADDRESS_CLOSED +# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL) +#endif + +#ifndef STATUS_CONNECTION_DISCONNECTED +# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL) +#endif + +#ifndef STATUS_CONNECTION_RESET +# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL) +#endif + +#ifndef STATUS_TOO_MANY_NODES +# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL) +#endif + +#ifndef STATUS_TRANSACTION_ABORTED +# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL) +#endif + +#ifndef STATUS_TRANSACTION_TIMED_OUT +# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L) +#endif + +#ifndef STATUS_TRANSACTION_NO_RELEASE +# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L) +#endif + +#ifndef STATUS_TRANSACTION_NO_MATCH +# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L) +#endif + +#ifndef STATUS_TRANSACTION_RESPONDED +# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_ID +# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L) +#endif + +#ifndef STATUS_TRANSACTION_INVALID_TYPE +# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L) +#endif + +#ifndef STATUS_NOT_SERVER_SESSION +# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L) +#endif + +#ifndef STATUS_NOT_CLIENT_SESSION +# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L) +#endif + +#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE +# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L) +#endif + +#ifndef STATUS_DEBUG_ATTACH_FAILED +# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L) +#endif + +#ifndef STATUS_SYSTEM_PROCESS_TERMINATED +# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL) +#endif + +#ifndef STATUS_DATA_NOT_ACCEPTED +# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL) +#endif + +#ifndef STATUS_NO_BROWSER_SERVERS_FOUND +# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL) +#endif + +#ifndef STATUS_VDM_HARD_ERROR +# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL) +#endif + +#ifndef STATUS_DRIVER_CANCEL_TIMEOUT +# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL) +#endif + +#ifndef STATUS_REPLY_MESSAGE_MISMATCH +# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL) +#endif + +#ifndef STATUS_MAPPED_ALIGNMENT +# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L) +#endif + +#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH +# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA +# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L) +#endif + +#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID +# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L) +#endif + +#ifndef STATUS_PASSWORD_MUST_CHANGE +# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L) +#endif + +#ifndef STATUS_NOT_FOUND +# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L) +#endif + +#ifndef STATUS_NOT_TINY_STREAM +# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L) +#endif + +#ifndef STATUS_RECOVERY_FAILURE +# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L) +#endif + +#ifndef STATUS_STACK_OVERFLOW_READ +# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L) +#endif + +#ifndef STATUS_FAIL_CHECK +# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L) +#endif + +#ifndef STATUS_DUPLICATE_OBJECTID +# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL) +#endif + +#ifndef STATUS_OBJECTID_EXISTS +# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL) +#endif + +#ifndef STATUS_CONVERT_TO_LARGE +# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL) +#endif + +#ifndef STATUS_RETRY +# define STATUS_RETRY ((NTSTATUS) 0xC000022DL) +#endif + +#ifndef STATUS_FOUND_OUT_OF_SCOPE +# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL) +#endif + +#ifndef STATUS_ALLOCATE_BUCKET +# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL) +#endif + +#ifndef STATUS_PROPSET_NOT_FOUND +# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L) +#endif + +#ifndef STATUS_MARSHALL_OVERFLOW +# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L) +#endif + +#ifndef STATUS_INVALID_VARIANT +# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L) +#endif + +#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND +# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L) +#endif + +#ifndef STATUS_ACCOUNT_LOCKED_OUT +# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L) +#endif + +#ifndef STATUS_HANDLE_NOT_CLOSABLE +# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L) +#endif + +#ifndef STATUS_CONNECTION_REFUSED +# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L) +#endif + +#ifndef STATUS_GRACEFUL_DISCONNECT +# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L) +#endif + +#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED +# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L) +#endif + +#ifndef STATUS_ADDRESS_NOT_ASSOCIATED +# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L) +#endif + +#ifndef STATUS_CONNECTION_INVALID +# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL) +#endif + +#ifndef STATUS_CONNECTION_ACTIVE +# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL) +#endif + +#ifndef STATUS_NETWORK_UNREACHABLE +# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL) +#endif + +#ifndef STATUS_HOST_UNREACHABLE +# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL) +#endif + +#ifndef STATUS_PROTOCOL_UNREACHABLE +# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL) +#endif + +#ifndef STATUS_PORT_UNREACHABLE +# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL) +#endif + +#ifndef STATUS_REQUEST_ABORTED +# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L) +#endif + +#ifndef STATUS_CONNECTION_ABORTED +# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L) +#endif + +#ifndef STATUS_BAD_COMPRESSION_BUFFER +# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L) +#endif + +#ifndef STATUS_USER_MAPPED_FILE +# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L) +#endif + +#ifndef STATUS_AUDIT_FAILED +# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L) +#endif + +#ifndef STATUS_TIMER_RESOLUTION_NOT_SET +# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L) +#endif + +#ifndef STATUS_CONNECTION_COUNT_LIMIT +# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L) +#endif + +#ifndef STATUS_LOGIN_TIME_RESTRICTION +# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L) +#endif + +#ifndef STATUS_LOGIN_WKSTA_RESTRICTION +# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L) +#endif + +#ifndef STATUS_IMAGE_MP_UP_MISMATCH +# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L) +#endif + +#ifndef STATUS_INSUFFICIENT_LOGON_INFO +# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L) +#endif + +#ifndef STATUS_BAD_DLL_ENTRYPOINT +# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L) +#endif + +#ifndef STATUS_BAD_SERVICE_ENTRYPOINT +# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L) +#endif + +#ifndef STATUS_LPC_REPLY_LOST +# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT1 +# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L) +#endif + +#ifndef STATUS_IP_ADDRESS_CONFLICT2 +# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L) +#endif + +#ifndef STATUS_REGISTRY_QUOTA_LIMIT +# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L) +#endif + +#ifndef STATUS_PATH_NOT_COVERED +# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L) +#endif + +#ifndef STATUS_NO_CALLBACK_ACTIVE +# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L) +#endif + +#ifndef STATUS_LICENSE_QUOTA_EXCEEDED +# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L) +#endif + +#ifndef STATUS_PWD_TOO_SHORT +# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL) +#endif + +#ifndef STATUS_PWD_TOO_RECENT +# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL) +#endif + +#ifndef STATUS_PWD_HISTORY_CONFLICT +# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL) +#endif + +#ifndef STATUS_PLUGPLAY_NO_DEVICE +# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL) +#endif + +#ifndef STATUS_UNSUPPORTED_COMPRESSION +# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL) +#endif + +#ifndef STATUS_INVALID_HW_PROFILE +# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L) +#endif + +#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH +# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L) +#endif + +#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND +# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L) +#endif + +#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND +# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L) +#endif + +#ifndef STATUS_RESOURCE_NOT_OWNED +# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L) +#endif + +#ifndef STATUS_TOO_MANY_LINKS +# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L) +#endif + +#ifndef STATUS_QUOTA_LIST_INCONSISTENT +# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L) +#endif + +#ifndef STATUS_FILE_IS_OFFLINE +# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L) +#endif + +#ifndef STATUS_EVALUATION_EXPIRATION +# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L) +#endif + +#ifndef STATUS_ILLEGAL_DLL_RELOCATION +# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L) +#endif + +#ifndef STATUS_LICENSE_VIOLATION +# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL) +#endif + +#ifndef STATUS_DLL_INIT_FAILED_LOGOFF +# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL) +#endif + +#ifndef STATUS_DRIVER_UNABLE_TO_LOAD +# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL) +#endif + +#ifndef STATUS_DFS_UNAVAILABLE +# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL) +#endif + +#ifndef STATUS_VOLUME_DISMOUNTED +# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL) +#endif + +#ifndef STATUS_WX86_INTERNAL_ERROR +# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL) +#endif + +#ifndef STATUS_WX86_FLOAT_STACK_CHECK +# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L) +#endif + +#ifndef STATUS_VALIDATE_CONTINUE +# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L) +#endif + +#ifndef STATUS_NO_MATCH +# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L) +#endif + +#ifndef STATUS_NO_MORE_MATCHES +# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L) +#endif + +#ifndef STATUS_NOT_A_REPARSE_POINT +# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_INVALID +# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_MISMATCH +# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L) +#endif + +#ifndef STATUS_IO_REPARSE_DATA_INVALID +# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L) +#endif + +#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED +# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L) +#endif + +#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED +# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L) +#endif + +#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT +# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L) +#endif + +#ifndef STATUS_RANGE_LIST_CONFLICT +# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L) +#endif + +#ifndef STATUS_SOURCE_ELEMENT_EMPTY +# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L) +#endif + +#ifndef STATUS_DESTINATION_ELEMENT_FULL +# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L) +#endif + +#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS +# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L) +#endif + +#ifndef STATUS_MAGAZINE_NOT_PRESENT +# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L) +#endif + +#ifndef STATUS_REINITIALIZATION_NEEDED +# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L) +#endif + +#ifndef STATUS_DEVICE_REQUIRES_CLEANING +# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L) +#endif + +#ifndef STATUS_DEVICE_DOOR_OPEN +# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L) +#endif + +#ifndef STATUS_ENCRYPTION_FAILED +# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL) +#endif + +#ifndef STATUS_DECRYPTION_FAILED +# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL) +#endif + +#ifndef STATUS_RANGE_NOT_FOUND +# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL) +#endif + +#ifndef STATUS_NO_RECOVERY_POLICY +# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL) +#endif + +#ifndef STATUS_NO_EFS +# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL) +#endif + +#ifndef STATUS_WRONG_EFS +# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL) +#endif + +#ifndef STATUS_NO_USER_KEYS +# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L) +#endif + +#ifndef STATUS_FILE_NOT_ENCRYPTED +# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L) +#endif + +#ifndef STATUS_NOT_EXPORT_FORMAT +# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L) +#endif + +#ifndef STATUS_FILE_ENCRYPTED +# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L) +#endif + +#ifndef STATUS_WAKE_SYSTEM +# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L) +#endif + +#ifndef STATUS_WMI_GUID_NOT_FOUND +# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L) +#endif + +#ifndef STATUS_WMI_INSTANCE_NOT_FOUND +# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L) +#endif + +#ifndef STATUS_WMI_ITEMID_NOT_FOUND +# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L) +#endif + +#ifndef STATUS_WMI_TRY_AGAIN +# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L) +#endif + +#ifndef STATUS_SHARED_POLICY +# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L) +#endif + +#ifndef STATUS_POLICY_OBJECT_NOT_FOUND +# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL) +#endif + +#ifndef STATUS_POLICY_ONLY_IN_DS +# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL) +#endif + +#ifndef STATUS_VOLUME_NOT_UPGRADED +# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE +# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL) +#endif + +#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR +# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL) +#endif + +#ifndef STATUS_NO_TRACKING_SERVICE +# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL) +#endif + +#ifndef STATUS_SERVER_SID_MISMATCH +# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L) +#endif + +#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE +# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L) +#endif + +#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX +# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED +# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L) +#endif + +#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS +# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L) +#endif + +#ifndef STATUS_DS_BUSY +# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L) +#endif + +#ifndef STATUS_DS_UNAVAILABLE +# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L) +#endif + +#ifndef STATUS_DS_NO_RIDS_ALLOCATED +# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L) +#endif + +#ifndef STATUS_DS_NO_MORE_RIDS +# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L) +#endif + +#ifndef STATUS_DS_INCORRECT_ROLE_OWNER +# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L) +#endif + +#ifndef STATUS_DS_RIDMGR_INIT_ERROR +# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL) +#endif + +#ifndef STATUS_DS_OBJ_CLASS_VIOLATION +# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL) +#endif + +#ifndef STATUS_DS_CANT_ON_NON_LEAF +# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL) +#endif + +#ifndef STATUS_DS_CANT_ON_RDN +# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL) +#endif + +#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS +# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL) +#endif + +#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED +# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL) +#endif + +#ifndef STATUS_DS_GC_NOT_AVAILABLE +# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L) +#endif + +#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED +# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L) +#endif + +#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT +# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L) +#endif + +#ifndef STATUS_CANT_ENABLE_DENY_ONLY +# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_FAULTS +# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L) +#endif + +#ifndef STATUS_FLOAT_MULTIPLE_TRAPS +# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L) +#endif + +#ifndef STATUS_DEVICE_REMOVED +# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L) +#endif + +#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS +# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L) +#endif + +#ifndef STATUS_JOURNAL_NOT_ACTIVE +# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L) +#endif + +#ifndef STATUS_NOINTERFACE +# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L) +#endif + +#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED +# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L) +#endif + +#ifndef STATUS_DRIVER_FAILED_SLEEP +# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L) +#endif + +#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED +# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L) +#endif + +#ifndef STATUS_CORRUPT_SYSTEM_FILE +# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L) +#endif + +#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR +# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L) +#endif + +#ifndef STATUS_WMI_READ_ONLY +# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L) +#endif + +#ifndef STATUS_WMI_SET_FAILURE +# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L) +#endif + +#ifndef STATUS_COMMITMENT_MINIMUM +# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L) +#endif + +#ifndef STATUS_REG_NAT_CONSUMPTION +# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L) +#endif + +#ifndef STATUS_TRANSPORT_FULL +# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE +# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL) +#endif + +#ifndef STATUS_ONLY_IF_CONNECTED +# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL) +#endif + +#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION +# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL) +#endif + +#ifndef STATUS_PNP_RESTART_ENUMERATION +# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL) +#endif + +#ifndef STATUS_JOURNAL_ENTRY_DELETED +# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL) +#endif + +#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID +# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L) +#endif + +#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE +# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L) +#endif + +#ifndef STATUS_PNP_REBOOT_REQUIRED +# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L) +#endif + +#ifndef STATUS_POWER_STATE_INVALID +# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L) +#endif + +#ifndef STATUS_DS_INVALID_GROUP_TYPE +# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L) +#endif + +#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L) +#endif + +#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN +# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L) +#endif + +#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER +# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L) +#endif + +#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER +# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL) +#endif + +#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER +# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL) +#endif + +#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS +# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL) +#endif + +#ifndef STATUS_WMI_NOT_SUPPORTED +# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL) +#endif + +#ifndef STATUS_INSUFFICIENT_POWER +# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD +# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL) +#endif + +#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY +# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L) +#endif + +#ifndef STATUS_DS_CANT_START +# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L) +#endif + +#ifndef STATUS_DS_INIT_FAILURE +# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L) +#endif + +#ifndef STATUS_SAM_INIT_FAILURE +# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L) +#endif + +#ifndef STATUS_DS_GC_REQUIRED +# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L) +#endif + +#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY +# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L) +#endif + +#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS +# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L) +#endif + +#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED +# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L) +#endif + +#ifndef STATUS_MULTIPLE_FAULT_VIOLATION +# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L) +#endif + +#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED +# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L) +#endif + +#ifndef STATUS_CANNOT_MAKE +# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL) +#endif + +#ifndef STATUS_SYSTEM_SHUTDOWN +# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL) +#endif + +#ifndef STATUS_DS_INIT_FAILURE_CONSOLE +# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL) +#endif + +#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE +# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL) +#endif + +#ifndef STATUS_UNFINISHED_CONTEXT_DELETED +# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL) +#endif + +#ifndef STATUS_NO_TGT_REPLY +# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL) +#endif + +#ifndef STATUS_OBJECTID_NOT_FOUND +# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L) +#endif + +#ifndef STATUS_NO_IP_ADDRESSES +# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L) +#endif + +#ifndef STATUS_WRONG_CREDENTIAL_HANDLE +# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L) +#endif + +#ifndef STATUS_CRYPTO_SYSTEM_INVALID +# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L) +#endif + +#ifndef STATUS_MAX_REFERRALS_EXCEEDED +# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L) +#endif + +#ifndef STATUS_MUST_BE_KDC +# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L) +#endif + +#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED +# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L) +#endif + +#ifndef STATUS_TOO_MANY_PRINCIPALS +# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L) +#endif + +#ifndef STATUS_NO_PA_DATA +# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L) +#endif + +#ifndef STATUS_PKINIT_NAME_MISMATCH +# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L) +#endif + +#ifndef STATUS_SMARTCARD_LOGON_REQUIRED +# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL) +#endif + +#ifndef STATUS_KDC_INVALID_REQUEST +# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL) +#endif + +#ifndef STATUS_KDC_UNABLE_TO_REFER +# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL) +#endif + +#ifndef STATUS_KDC_UNKNOWN_ETYPE +# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL) +#endif + +#ifndef STATUS_SHUTDOWN_IN_PROGRESS +# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL) +#endif + +#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS +# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL) +#endif + +#ifndef STATUS_NOT_SUPPORTED_ON_SBS +# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L) +#endif + +#ifndef STATUS_WMI_GUID_DISCONNECTED +# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L) +#endif + +#ifndef STATUS_WMI_ALREADY_DISABLED +# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L) +#endif + +#ifndef STATUS_WMI_ALREADY_ENABLED +# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L) +#endif + +#ifndef STATUS_MFT_TOO_FRAGMENTED +# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L) +#endif + +#ifndef STATUS_COPY_PROTECTION_FAILURE +# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L) +#endif + +#ifndef STATUS_CSS_AUTHENTICATION_FAILURE +# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_PRESENT +# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L) +#endif + +#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED +# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L) +#endif + +#ifndef STATUS_CSS_SCRAMBLED_SECTOR +# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L) +#endif + +#ifndef STATUS_CSS_REGION_MISMATCH +# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL) +#endif + +#ifndef STATUS_CSS_RESETS_EXHAUSTED +# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL) +#endif + +#ifndef STATUS_PKINIT_FAILURE +# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L) +#endif + +#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE +# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L) +#endif + +#ifndef STATUS_NO_KERB_KEY +# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L) +#endif + +#ifndef STATUS_HOST_DOWN +# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L) +#endif + +#ifndef STATUS_UNSUPPORTED_PREAUTH +# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L) +#endif + +#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG +# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L) +#endif + +#ifndef STATUS_PORT_NOT_SET +# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L) +#endif + +#ifndef STATUS_DEBUGGER_INACTIVE +# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L) +#endif + +#ifndef STATUS_DS_VERSION_CHECK_FAILURE +# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L) +#endif + +#ifndef STATUS_AUDITING_DISABLED +# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L) +#endif + +#ifndef STATUS_PRENT4_MACHINE_ACCOUNT +# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L) +#endif + +#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER +# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_32 +# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L) +#endif + +#ifndef STATUS_INVALID_IMAGE_WIN_64 +# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL) +#endif + +#ifndef STATUS_BAD_BINDINGS +# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL) +#endif + +#ifndef STATUS_NETWORK_SESSION_EXPIRED +# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL) +#endif + +#ifndef STATUS_APPHELP_BLOCK +# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL) +#endif + +#ifndef STATUS_ALL_SIDS_FILTERED +# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL) +#endif + +#ifndef STATUS_NOT_SAFE_MODE_DRIVER +# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT +# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH +# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER +# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L) +#endif + +#ifndef STATUS_FAILED_DRIVER_ENTRY +# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L) +#endif + +#ifndef STATUS_DEVICE_ENUMERATION_ERROR +# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L) +#endif + +#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED +# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L) +#endif + +#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER +# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L) +#endif + +#ifndef STATUS_MCA_OCCURED +# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED_CRITICAL +# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL) +#endif + +#ifndef STATUS_DRIVER_BLOCKED +# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL) +#endif + +#ifndef STATUS_DRIVER_DATABASE_ERROR +# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL) +#endif + +#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE +# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL) +#endif + +#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL +# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL) +#endif + +#ifndef STATUS_DS_SHUTTING_DOWN +# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L) +#endif + +#ifndef STATUS_NO_SECRETS +# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L) +#endif + +#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY +# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L) +#endif + +#ifndef STATUS_FAILED_STACK_SWITCH +# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L) +#endif + +#ifndef STATUS_HEAP_CORRUPTION +# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L) +#endif + +#ifndef STATUS_SMARTCARD_WRONG_PIN +# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_BLOCKED +# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L) +#endif + +#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED +# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CARD +# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER +# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L) +#endif + +#ifndef STATUS_SMARTCARD_NO_CERTIFICATE +# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L) +#endif + +#ifndef STATUS_SMARTCARD_NO_KEYSET +# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L) +#endif + +#ifndef STATUS_SMARTCARD_IO_ERROR +# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L) +#endif + +#ifndef STATUS_DOWNGRADE_DETECTED +# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L) +#endif + +#ifndef STATUS_SMARTCARD_CERT_REVOKED +# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED +# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_C +# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL) +#endif + +#ifndef STATUS_PKINIT_CLIENT_FAILURE +# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL) +#endif + +#ifndef STATUS_SMARTCARD_CERT_EXPIRED +# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL) +#endif + +#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD +# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL) +#endif + +#ifndef STATUS_SMARTCARD_SILENT_CONTEXT +# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL) +#endif + +#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L) +#endif + +#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED +# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L) +#endif + +#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED +# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L) +#endif + +#ifndef STATUS_DS_NAME_NOT_UNIQUE +# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L) +#endif + +#ifndef STATUS_DS_DUPLICATE_ID_FOUND +# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L) +#endif + +#ifndef STATUS_DS_GROUP_CONVERSION_ERROR +# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L) +#endif + +#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE +# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L) +#endif + +#ifndef STATUS_USER2USER_REQUIRED +# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L) +#endif + +#ifndef STATUS_STACK_BUFFER_OVERRUN +# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L) +#endif + +#ifndef STATUS_NO_S4U_PROT_SUPPORT +# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL) +#endif + +#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE +# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL) +#endif + +#ifndef STATUS_REVOCATION_OFFLINE_KDC +# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL) +#endif + +#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC +# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL) +#endif + +#ifndef STATUS_KDC_CERT_EXPIRED +# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL) +#endif + +#ifndef STATUS_KDC_CERT_REVOKED +# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL) +#endif + +#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED +# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L) +#endif + +#ifndef STATUS_HIBERNATION_FAILURE +# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L) +#endif + +#ifndef STATUS_DELAY_LOAD_FAILED +# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L) +#endif + +#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED +# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L) +#endif + +#ifndef STATUS_VDM_DISALLOWED +# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L) +#endif + +#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD +# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L) +#endif + +#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE +# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L) +#endif + +#ifndef STATUS_INVALID_CRUNTIME_PARAMETER +# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L) +#endif + +#ifndef STATUS_NTLM_BLOCKED +# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L) +#endif + +#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST +# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L) +#endif + +#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST +# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL) +#endif + +#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST +# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL) +#endif + +#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME +# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL) +#endif + +#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION +# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL) +#endif + +#ifndef STATUS_ASSERTION_FAILURE +# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L) +#endif + +#ifndef STATUS_VERIFIER_STOP +# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L) +#endif + +#ifndef STATUS_CALLBACK_POP_STACK +# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L) +#endif + +#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED +# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L) +#endif + +#ifndef STATUS_HIVE_UNLOADED +# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L) +#endif + +#ifndef STATUS_COMPRESSION_DISABLED +# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L) +#endif + +#ifndef STATUS_FILE_SYSTEM_LIMITATION +# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L) +#endif + +#ifndef STATUS_INVALID_IMAGE_HASH +# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L) +#endif + +#ifndef STATUS_NOT_CAPABLE +# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L) +#endif + +#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE +# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL) +#endif + +#ifndef STATUS_IMPLEMENTATION_LIMIT +# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL) +#endif + +#ifndef STATUS_ELEVATION_REQUIRED +# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL) +#endif + +#ifndef STATUS_NO_SECURITY_CONTEXT +# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL) +#endif + +#ifndef STATUS_PKU2U_CERT_FAILURE +# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL) +#endif + +#ifndef STATUS_BEYOND_VDL +# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L) +#endif + +#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS +# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L) +#endif + +#ifndef STATUS_PTE_CHANGED +# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L) +#endif + +#ifndef STATUS_PURGE_FAILED +# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L) +#endif + +#ifndef STATUS_CRED_REQUIRES_CONFIRMATION +# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE +# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER +# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE +# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L) +#endif + +#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE +# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L) +#endif + +#ifndef STATUS_INVALID_LABEL +# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L) +#endif + +#ifndef STATUS_DRIVER_PROCESS_TERMINATED +# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L) +#endif + +#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE +# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L) +#endif + +#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND +# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L) +#endif + +#ifndef STATUS_RESTART_BOOT_APPLICATION +# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L) +#endif + +#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES +# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L) +#endif + +#ifndef STATUS_INVALID_TASK_NAME +# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L) +#endif + +#ifndef STATUS_INVALID_TASK_INDEX +# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L) +#endif + +#ifndef STATUS_THREAD_ALREADY_IN_TASK +# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L) +#endif + +#ifndef STATUS_CALLBACK_BYPASS +# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L) +#endif + +#ifndef STATUS_FAIL_FAST_EXCEPTION +# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L) +#endif + +#ifndef STATUS_IMAGE_CERT_REVOKED +# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L) +#endif + +#ifndef STATUS_PORT_CLOSED +# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L) +#endif + +#ifndef STATUS_MESSAGE_LOST +# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L) +#endif + +#ifndef STATUS_INVALID_MESSAGE +# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L) +#endif + +#ifndef STATUS_REQUEST_CANCELED +# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L) +#endif + +#ifndef STATUS_RECURSIVE_DISPATCH +# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L) +#endif + +#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED +# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L) +#endif + +#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE +# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L) +#endif + +#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED +# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L) +#endif + +#ifndef STATUS_RESOURCE_IN_USE +# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L) +#endif + +#ifndef STATUS_HARDWARE_MEMORY_ERROR +# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L) +#endif + +#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION +# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL) +#endif + +#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL) +#endif + +#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED +# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL) +#endif + +#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION +# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING +# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L) +#endif + +#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING +# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L) +#endif + +#ifndef STATUS_PROCESS_IS_PROTECTED +# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L) +#endif + +#ifndef STATUS_MCA_EXCEPTION +# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L) +#endif + +#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE +# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L) +#endif + +#ifndef STATUS_SYMLINK_CLASS_DISABLED +# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L) +#endif + +#ifndef STATUS_INVALID_IDN_NORMALIZATION +# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L) +#endif + +#ifndef STATUS_NO_UNICODE_TRANSLATION +# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L) +#endif + +#ifndef STATUS_ALREADY_REGISTERED +# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L) +#endif + +#ifndef STATUS_CONTEXT_MISMATCH +# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L) +#endif + +#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST +# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY +# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL) +#endif + +#ifndef STATUS_INVALID_THREAD +# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION +# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK +# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_LANG +# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK +# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L) +#endif + +#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY +# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L) +#endif + +#ifndef STATUS_DISK_REPAIR_DISABLED +# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L) +#endif + +#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS +# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L) +#endif + +#ifndef STATUS_DISK_QUOTA_EXCEEDED +# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L) +#endif + +#ifndef STATUS_DATA_LOST_REPAIR +# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L) +#endif + +#ifndef STATUS_CONTENT_BLOCKED +# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L) +#endif + +#ifndef STATUS_BAD_CLUSTERS +# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L) +#endif + +#ifndef STATUS_VOLUME_DIRTY +# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L) +#endif + +#ifndef STATUS_FILE_CHECKED_OUT +# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L) +#endif + +#ifndef STATUS_CHECKOUT_REQUIRED +# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L) +#endif + +#ifndef STATUS_BAD_FILE_TYPE +# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L) +#endif + +#ifndef STATUS_FILE_TOO_LARGE +# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L) +#endif + +#ifndef STATUS_FORMS_AUTH_REQUIRED +# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L) +#endif + +#ifndef STATUS_VIRUS_INFECTED +# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L) +#endif + +#ifndef STATUS_VIRUS_DELETED +# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L) +#endif + +#ifndef STATUS_BAD_MCFG_TABLE +# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L) +#endif + +#ifndef STATUS_CANNOT_BREAK_OPLOCK +# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L) +#endif + +#ifndef STATUS_WOW_ASSERTION +# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L) +#endif + +#ifndef STATUS_INVALID_SIGNATURE +# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L) +#endif + +#ifndef STATUS_HMAC_NOT_SUPPORTED +# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L) +#endif + +#ifndef STATUS_AUTH_TAG_MISMATCH +# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L) +#endif + +#ifndef STATUS_IPSEC_QUEUE_OVERFLOW +# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L) +#endif + +#ifndef STATUS_ND_QUEUE_OVERFLOW +# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L) +#endif + +#ifndef STATUS_HOPLIMIT_EXCEEDED +# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L) +#endif + +#ifndef STATUS_PROTOCOL_NOT_SUPPORTED +# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L) +#endif + +#ifndef STATUS_FASTPATH_REJECTED +# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L) +#endif + +#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR +# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L) +#endif + +#ifndef STATUS_XML_PARSE_ERROR +# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L) +#endif + +#ifndef STATUS_XMLDSIG_ERROR +# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L) +#endif + +#ifndef STATUS_WRONG_COMPARTMENT +# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L) +#endif + +#ifndef STATUS_AUTHIP_FAILURE +# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L) +#endif + +#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS +# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L) +#endif + +#ifndef STATUS_DS_OID_NOT_FOUND +# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L) +#endif + +#ifndef STATUS_HASH_NOT_SUPPORTED +# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L) +#endif + +#ifndef STATUS_HASH_NOT_PRESENT +# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L) +#endif + +/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */ +/* DDK got it wrong! */ +#ifdef NTSTATUS_FROM_WIN32 +# undef NTSTATUS_FROM_WIN32 +#endif +#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \ + ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \ + (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING))) + +#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY +# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 +#endif +#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY +# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 +#endif +#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION +# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 +#endif +#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 +#endif +#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK +# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 +#endif +#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE +# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 +#endif + +#ifndef DEVICE_TYPE +# define DEVICE_TYPE DWORD +#endif + +/* from ntifs.h */ +/* MinGW already has it, mingw-w64 does not. */ +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileAttributeCacheInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +typedef enum _FS_INFORMATION_CLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation = 2, + FileFsSizeInformation = 3, + FileFsDeviceInformation = 4, + FileFsAttributeInformation = 5, + FileFsControlInformation = 6, + FileFsFullSizeInformation = 7, + FileFsObjectIdInformation = 8, + FileFsDriverPathInformation = 9, + FileFsVolumeFlagsInformation = 10, + FileFsSectorSizeInformation = 11 +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef struct _FILE_FS_VOLUME_INFORMATION { + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +typedef struct _FILE_FS_LABEL_INFORMATION { + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; + +typedef struct _FILE_FS_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +typedef struct _FILE_FS_CONTROL_INFORMATION { + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION; + +typedef struct _FILE_FS_FULL_SIZE_INFORMATION { + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; + +typedef struct _FILE_FS_OBJECTID_INFORMATION { + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; + +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION { + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION; + +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION { + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION; + +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION { + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#ifndef SystemProcessorPerformanceInformation +# define SystemProcessorPerformanceInformation 8 +#endif + +#ifndef FILE_DEVICE_FILE_SYSTEM +# define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#endif + +#ifndef FILE_DEVICE_NETWORK +# define FILE_DEVICE_NETWORK 0x00000012 +#endif + +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif + +#ifndef METHOD_IN_DIRECT +# define METHOD_IN_DIRECT 1 +#endif + +#ifndef METHOD_OUT_DIRECT +# define METHOD_OUT_DIRECT 2 +#endif + +#ifndef METHOD_NEITHER +#define METHOD_NEITHER 3 +#endif + +#ifndef METHOD_DIRECT_TO_HARDWARE +# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT +#endif + +#ifndef METHOD_DIRECT_FROM_HARDWARE +# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT +#endif + +#ifndef FILE_ANY_ACCESS +# define FILE_ANY_ACCESS 0 +#endif + +#ifndef FILE_SPECIAL_ACCESS +# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +#ifndef FILE_READ_ACCESS +# define FILE_READ_ACCESS 0x0001 +#endif + +#ifndef FILE_WRITE_ACCESS +# define FILE_WRITE_ACCESS 0x0002 +#endif + +#ifndef CTL_CODE +# define CTL_CODE(device_type, function, method, access) \ + (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method)) +#endif + +#ifndef FSCTL_SET_REPARSE_POINT +# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 41, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 42, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) +#endif + +#ifndef FSCTL_DELETE_REPARSE_POINT +# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \ + 43, \ + METHOD_BUFFERED, \ + FILE_SPECIAL_ACCESS) +#endif + +#ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#endif + +typedef VOID (NTAPI *PIO_APC_ROUTINE) + (PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved); + +typedef ULONG (NTAPI *sRtlNtStatusToDosError) + (NTSTATUS Status); + +typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile) + (HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength); + +typedef NTSTATUS (NTAPI *sNtQueryInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtSetInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile) + (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass); + +typedef NTSTATUS (NTAPI *sNtQuerySystemInformation) + (UINT SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + + +/* + * Kernel32 headers + */ +#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS +# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#endif + +#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE +# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) + typedef struct _OVERLAPPED_ENTRY { + ULONG_PTR lpCompletionKey; + LPOVERLAPPED lpOverlapped; + ULONG_PTR Internal; + DWORD dwNumberOfBytesTransferred; + } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; +#endif + +/* from wincon.h */ +#ifndef ENABLE_INSERT_MODE +# define ENABLE_INSERT_MODE 0x20 +#endif + +#ifndef ENABLE_QUICK_EDIT_MODE +# define ENABLE_QUICK_EDIT_MODE 0x40 +#endif + +#ifndef ENABLE_EXTENDED_FLAGS +# define ENABLE_EXTENDED_FLAGS 0x80 +#endif + +/* from winerror.h */ +#ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +#endif + +typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) + (HANDLE CompletionPort, + LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, + PULONG ulNumEntriesRemoved, + DWORD dwMilliseconds, + BOOL fAlertable); + +typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) + (HANDLE FileHandle, + UCHAR Flags); + +typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) + (LPCWSTR lpSymlinkFileName, + LPCWSTR lpTargetFileName, + DWORD dwFlags); + +typedef BOOL (WINAPI* sCancelIoEx) + (HANDLE hFile, + LPOVERLAPPED lpOverlapped); + +typedef VOID (WINAPI* sInitializeSRWLock) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sAcquireSRWLockShared) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sAcquireSRWLockExclusive) + (PSRWLOCK SRWLock); + +typedef BOOL (WINAPI* sTryAcquireSRWLockShared) + (PSRWLOCK SRWLock); + +typedef BOOL (WINAPI* sTryAcquireSRWLockExclusive) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sReleaseSRWLockShared) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sReleaseSRWLockExclusive) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sInitializeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef BOOL (WINAPI* sSleepConditionVariableCS) + (PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); + +typedef BOOL (WINAPI* sSleepConditionVariableSRW) + (PCONDITION_VARIABLE ConditionVariable, + PSRWLOCK SRWLock, + DWORD dwMilliseconds, + ULONG Flags); + +typedef VOID (WINAPI* sWakeAllConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + +typedef VOID (WINAPI* sWakeConditionVariable) + (PCONDITION_VARIABLE ConditionVariable); + + +/* Ntdll function pointers */ +extern sRtlNtStatusToDosError pRtlNtStatusToDosError; +extern sNtDeviceIoControlFile pNtDeviceIoControlFile; +extern sNtQueryInformationFile pNtQueryInformationFile; +extern sNtSetInformationFile pNtSetInformationFile; +extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; +extern sNtQuerySystemInformation pNtQuerySystemInformation; + + +/* Kernel32 function pointers */ +extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; +extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sCancelIoEx pCancelIoEx; +extern sInitializeSRWLock pInitializeSRWLock; +extern sAcquireSRWLockShared pAcquireSRWLockShared; +extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive; +extern sTryAcquireSRWLockShared pTryAcquireSRWLockShared; +extern sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive; +extern sReleaseSRWLockShared pReleaseSRWLockShared; +extern sReleaseSRWLockExclusive pReleaseSRWLockExclusive; +extern sInitializeConditionVariable pInitializeConditionVariable; +extern sSleepConditionVariableCS pSleepConditionVariableCS; +extern sSleepConditionVariableSRW pSleepConditionVariableSRW; +extern sWakeAllConditionVariable pWakeAllConditionVariable; +extern sWakeConditionVariable pWakeConditionVariable; + +#endif /* UV_WIN_WINAPI_H_ */ diff --git a/src/win/winsock.c b/src/win/winsock.c new file mode 100644 index 0000000000..938b6d031a --- /dev/null +++ b/src/win/winsock.c @@ -0,0 +1,560 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "uv.h" +#include "internal.h" + + +/* Whether there are any non-IFS LSPs stacked on TCP */ +int uv_tcp_non_ifs_lsp_ipv4; +int uv_tcp_non_ifs_lsp_ipv6; + +/* Ip address used to bind to any port at any interface */ +struct sockaddr_in uv_addr_ip4_any_; +struct sockaddr_in6 uv_addr_ip6_any_; + + +/* + * Retrieves the pointer to a winsock extension function. + */ +static BOOL uv_get_extension_function(SOCKET socket, GUID guid, + void **target) { + DWORD result, bytes; + + result = WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL); + + if (result == SOCKET_ERROR) { + *target = NULL; + return FALSE; + } else { + return TRUE; + } +} + + +BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { + const GUID wsaid_acceptex = WSAID_ACCEPTEX; + return uv_get_extension_function(socket, wsaid_acceptex, (void**)target); +} + + +BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { + const GUID wsaid_connectex = WSAID_CONNECTEX; + return uv_get_extension_function(socket, wsaid_connectex, (void**)target); +} + + +static int error_means_no_support(DWORD error) { + return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT || + error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT; +} + + +void uv_winsock_init() { + WSADATA wsa_data; + int errorno; + SOCKET dummy; + WSAPROTOCOL_INFOW protocol_info; + int opt_len; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + + /* Set implicit binding address used by connectEx */ + if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) { + abort(); + } + + if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) { + abort(); + } + + /* Detect non-IFS LSPs */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv4 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } + + /* Detect IPV6 support and non-IFS LSPs */ + dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + + if (dummy != INVALID_SOCKET) { + opt_len = (int) sizeof protocol_info; + if (getsockopt(dummy, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &opt_len) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "getsockopt"); + + if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)) + uv_tcp_non_ifs_lsp_ipv6 = 1; + + if (closesocket(dummy) == SOCKET_ERROR) + uv_fatal_error(WSAGetLastError(), "closesocket"); + + } else if (!error_means_no_support(WSAGetLastError())) { + /* Any error other than "socket type not supported" is fatal. */ + uv_fatal_error(WSAGetLastError(), "socket"); + } +} + + +int uv_ntstatus_to_winsock_error(NTSTATUS status) { + switch (status) { + case STATUS_SUCCESS: + return ERROR_SUCCESS; + + case STATUS_PENDING: + return ERROR_IO_PENDING; + + case STATUS_INVALID_HANDLE: + case STATUS_OBJECT_TYPE_MISMATCH: + return WSAENOTSOCK; + + case STATUS_INSUFFICIENT_RESOURCES: + case STATUS_PAGEFILE_QUOTA: + case STATUS_COMMITMENT_LIMIT: + case STATUS_WORKING_SET_QUOTA: + case STATUS_NO_MEMORY: + case STATUS_CONFLICTING_ADDRESSES: + case STATUS_QUOTA_EXCEEDED: + case STATUS_TOO_MANY_PAGING_FILES: + case STATUS_REMOTE_RESOURCES: + case STATUS_TOO_MANY_ADDRESSES: + return WSAENOBUFS; + + case STATUS_SHARING_VIOLATION: + case STATUS_ADDRESS_ALREADY_EXISTS: + return WSAEADDRINUSE; + + case STATUS_LINK_TIMEOUT: + case STATUS_IO_TIMEOUT: + case STATUS_TIMEOUT: + return WSAETIMEDOUT; + + case STATUS_GRACEFUL_DISCONNECT: + return WSAEDISCON; + + case STATUS_REMOTE_DISCONNECT: + case STATUS_CONNECTION_RESET: + case STATUS_LINK_FAILED: + case STATUS_CONNECTION_DISCONNECTED: + case STATUS_PORT_UNREACHABLE: + case STATUS_HOPLIMIT_EXCEEDED: + return WSAECONNRESET; + + case STATUS_LOCAL_DISCONNECT: + case STATUS_TRANSACTION_ABORTED: + case STATUS_CONNECTION_ABORTED: + return WSAECONNABORTED; + + case STATUS_BAD_NETWORK_PATH: + case STATUS_NETWORK_UNREACHABLE: + case STATUS_PROTOCOL_UNREACHABLE: + return WSAENETUNREACH; + + case STATUS_HOST_UNREACHABLE: + return WSAEHOSTUNREACH; + + case STATUS_CANCELLED: + case STATUS_REQUEST_ABORTED: + return WSAEINTR; + + case STATUS_BUFFER_OVERFLOW: + case STATUS_INVALID_BUFFER_SIZE: + return WSAEMSGSIZE; + + case STATUS_BUFFER_TOO_SMALL: + case STATUS_ACCESS_VIOLATION: + return WSAEFAULT; + + case STATUS_DEVICE_NOT_READY: + case STATUS_REQUEST_NOT_ACCEPTED: + return WSAEWOULDBLOCK; + + case STATUS_INVALID_NETWORK_RESPONSE: + case STATUS_NETWORK_BUSY: + case STATUS_NO_SUCH_DEVICE: + case STATUS_NO_SUCH_FILE: + case STATUS_OBJECT_PATH_NOT_FOUND: + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_UNEXPECTED_NETWORK_ERROR: + return WSAENETDOWN; + + case STATUS_INVALID_CONNECTION: + return WSAENOTCONN; + + case STATUS_REMOTE_NOT_LISTENING: + case STATUS_CONNECTION_REFUSED: + return WSAECONNREFUSED; + + case STATUS_PIPE_DISCONNECTED: + return WSAESHUTDOWN; + + case STATUS_INVALID_ADDRESS: + case STATUS_INVALID_ADDRESS_COMPONENT: + return WSAEADDRNOTAVAIL; + + case STATUS_NOT_SUPPORTED: + case STATUS_NOT_IMPLEMENTED: + return WSAEOPNOTSUPP; + + case STATUS_ACCESS_DENIED: + return WSAEACCES; + + default: + if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && + (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { + /* It's a windows error that has been previously mapped to an */ + /* ntstatus code. */ + return (DWORD) (status & 0xffff); + } else { + /* The default fallback for unmappable ntstatus codes. */ + return WSAEINVAL; + } + } +} + + +/* + * This function provides a workaround for a bug in the winsock implementation + * of WSARecv. The problem is that when SetFileCompletionNotificationModes is + * used to avoid IOCP notifications of completed reads, WSARecv does not + * reliably indicate whether we can expect a completion package to be posted + * when the receive buffer is smaller than the received datagram. + * + * However it is desirable to use SetFileCompletionNotificationModes because + * it yields a massive performance increase. + * + * This function provides a workaround for that bug, but it only works for the + * specific case that we need it for. E.g. it assumes that the "avoid iocp" + * bit has been set, and supports only overlapped operation. It also requires + * the user to use the default msafd driver, doesn't work when other LSPs are + * stacked on top of it. + */ +int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_INFO info; + DWORD error; + + if (overlapped == NULL || completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +/* See description of uv_wsarecv_workaround. */ +int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, + DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, + int* addr_len, WSAOVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { + NTSTATUS status; + void* apc_context; + IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal; + AFD_RECV_DATAGRAM_INFO info; + DWORD error; + + if (overlapped == NULL || addr == NULL || addr_len == NULL || + completion_routine != NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + info.BufferArray = buffers; + info.BufferCount = buffer_count; + info.AfdFlags = AFD_OVERLAPPED; + info.TdiFlags = TDI_RECEIVE_NORMAL; + info.Address = addr; + info.AddressLength = addr_len; + + if (*flags & MSG_PEEK) { + info.TdiFlags |= TDI_RECEIVE_PEEK; + } + + if (*flags & MSG_PARTIAL) { + info.TdiFlags |= TDI_RECEIVE_PARTIAL; + } + + if (!((intptr_t) overlapped->hEvent & 1)) { + apc_context = (void*) overlapped; + } else { + apc_context = NULL; + } + + iosb->Status = STATUS_PENDING; + iosb->Pointer = 0; + + status = pNtDeviceIoControlFile((HANDLE) socket, + overlapped->hEvent, + NULL, + apc_context, + iosb, + IOCTL_AFD_RECEIVE_DATAGRAM, + &info, + sizeof(info), + NULL, + 0); + + *flags = 0; + *bytes = (DWORD) iosb->Information; + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + case STATUS_BUFFER_OVERFLOW: + error = WSAEMSGSIZE; + break; + + case STATUS_RECEIVE_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL_EXPEDITED: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL | MSG_OOB; + break; + + case STATUS_RECEIVE_PARTIAL: + error = ERROR_SUCCESS; + *flags = MSG_PARTIAL; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} + + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped) { + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK* iosb_ptr; + HANDLE event = NULL; + void* apc_context; + NTSTATUS status; + DWORD error; + + if (overlapped != NULL) { + /* Overlapped operation. */ + iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; + event = overlapped->hEvent; + + /* Do not report iocp completion if hEvent is tagged. */ + if ((uintptr_t) event & 1) { + event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); + apc_context = NULL; + } else { + apc_context = overlapped; + } + + } else { + /* Blocking operation. */ + iosb_ptr = &iosb; + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = pNtDeviceIoControlFile((HANDLE) socket, + event, + NULL, + apc_context, + iosb_ptr, + IOCTL_AFD_POLL, + info, + sizeof *info, + info, + sizeof *info); + + if (overlapped == NULL) { + /* If this is a blocking operation, wait for the event to become */ + /* signaled, and then grab the real status from the io status block. */ + if (status == STATUS_PENDING) { + DWORD r = WaitForSingleObject(event, INFINITE); + + if (r == WAIT_FAILED) { + DWORD saved_error = GetLastError(); + CloseHandle(event); + WSASetLastError(saved_error); + return SOCKET_ERROR; + } + + status = iosb.Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/src/win/winsock.h b/src/win/winsock.h new file mode 100644 index 0000000000..957d08ec19 --- /dev/null +++ b/src/win/winsock.h @@ -0,0 +1,171 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include +#include + +#include "winapi.h" + + +/* + * MinGW is missing these too + */ +#ifndef SO_UPDATE_CONNECT_CONTEXT +# define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + +#ifndef TCP_KEEPALIVE +# define TCP_KEEPALIVE 3 +#endif + +#ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +#endif + +#ifndef IPV6_HOPLIMIT +# define IPV6_HOPLIMIT 21 +#endif + +#ifndef SIO_BASE_HANDLE +# define SIO_BASE_HANDLE 0x48000022 +#endif + +/* + * TDI defines that are only in the DDK. + * We only need receive flags so far. + */ +#ifndef TDI_RECEIVE_NORMAL + #define TDI_RECEIVE_BROADCAST 0x00000004 + #define TDI_RECEIVE_MULTICAST 0x00000008 + #define TDI_RECEIVE_PARTIAL 0x00000010 + #define TDI_RECEIVE_NORMAL 0x00000020 + #define TDI_RECEIVE_EXPEDITED 0x00000040 + #define TDI_RECEIVE_PEEK 0x00000080 + #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 + #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 + #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 + #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 + #define TDI_RECEIVE_CONTROL_INFO 0x00001000 + #define TDI_RECEIVE_FORCE_INDICATION 0x00002000 + #define TDI_RECEIVE_NO_PUSH 0x00004000 +#endif + +/* + * The "Auxiliary Function Driver" is the windows kernel-mode driver that does + * TCP, UDP etc. Winsock is just a layer that dispatches requests to it. + * Having these definitions allows us to bypass winsock and make an AFD kernel + * call directly, avoiding a bug in winsock's recvfrom implementation. + */ + +#define AFD_NO_FAST_IO 0x00000001 +#define AFD_OVERLAPPED 0x00000002 +#define AFD_IMMEDIATE 0x00000004 + +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + +typedef struct _AFD_RECV_DATAGRAM_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; + struct sockaddr* Address; + int* AddressLength; +} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO; + +typedef struct _AFD_RECV_INFO { + LPWSABUF BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; +} AFD_RECV_INFO, *PAFD_RECV_INFO; + + +#define _AFD_CONTROL_CODE(operation, method) \ + ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method) + +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK + +#define AFD_RECEIVE 5 +#define AFD_RECEIVE_DATAGRAM 6 +#define AFD_POLL 9 + +#define IOCTL_AFD_RECEIVE \ + _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) + +#define IOCTL_AFD_RECEIVE_DATAGRAM \ + _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) + +#define IOCTL_AFD_POLL \ + _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { + /* FIXME: __C89_NAMELESS was removed */ + /* __C89_NAMELESS */ union { + ULONGLONG Alignment; + /* __C89_NAMELESS */ struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; + SOCKET_ADDRESS Address; + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; +} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; + +#endif + +#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/test/benchmark-async-pummel.c b/test/benchmark-async-pummel.c new file mode 100644 index 0000000000..4761c1928e --- /dev/null +++ b/test/benchmark-async-pummel.c @@ -0,0 +1,119 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include + +#define NUM_PINGS (1000 * 1000) +#define ACCESS_ONCE(type, var) (*(volatile type*) &(var)) + +static unsigned int callbacks; +static volatile int done; + +static const char running[] = "running"; +static const char stop[] = "stop"; +static const char stopped[] = "stopped"; + + +static void async_cb(uv_async_t* handle, int status) { + if (++callbacks == NUM_PINGS) { + /* Tell the pummel thread to stop. */ + ACCESS_ONCE(const char*, handle->data) = stop; + + /* Wait for for the pummel thread to acknowledge that it has stoppped. */ + while (ACCESS_ONCE(const char*, handle->data) != stopped) + uv_sleep(0); + + uv_close((uv_handle_t*) handle, NULL); + } +} + + +static void pummel(void* arg) { + uv_async_t* handle = (uv_async_t*) arg; + + while (ACCESS_ONCE(const char*, handle->data) == running) + uv_async_send(handle); + + /* Acknowledge that we've seen handle->data change. */ + ACCESS_ONCE(const char*, handle->data) = stopped; +} + + +static int test_async_pummel(int nthreads) { + uv_thread_t* tids; + uv_async_t handle; + uint64_t time; + int i; + + tids = calloc(nthreads, sizeof(tids[0])); + ASSERT(tids != NULL); + + ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb)); + ACCESS_ONCE(const char*, handle.data) = running; + + for (i = 0; i < nthreads; i++) + ASSERT(0 == uv_thread_create(tids + i, pummel, &handle)); + + time = uv_hrtime(); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + time = uv_hrtime() - time; + done = 1; + + for (i = 0; i < nthreads; i++) + ASSERT(0 == uv_thread_join(tids + i)); + + printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n", + nthreads, + fmt(callbacks), + time / 1e9, + fmt(callbacks / (time / 1e9))); + + free(tids); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +BENCHMARK_IMPL(async_pummel_1) { + return test_async_pummel(1); +} + + +BENCHMARK_IMPL(async_pummel_2) { + return test_async_pummel(2); +} + + +BENCHMARK_IMPL(async_pummel_4) { + return test_async_pummel(4); +} + + +BENCHMARK_IMPL(async_pummel_8) { + return test_async_pummel(8); +} diff --git a/test/benchmark-async.c b/test/benchmark-async.c new file mode 100644 index 0000000000..33d9ab446a --- /dev/null +++ b/test/benchmark-async.c @@ -0,0 +1,141 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include + +#define NUM_PINGS (1000 * 1000) + +struct ctx { + uv_loop_t* loop; + uv_thread_t thread; + uv_async_t main_async; /* wake up main thread */ + uv_async_t worker_async; /* wake up worker */ + unsigned int nthreads; + unsigned int main_sent; + unsigned int main_seen; + unsigned int worker_sent; + unsigned int worker_seen; +}; + + +static void worker_async_cb(uv_async_t* handle, int status) { + struct ctx* ctx = container_of(handle, struct ctx, worker_async); + + ASSERT(0 == uv_async_send(&ctx->main_async)); + ctx->worker_sent++; + ctx->worker_seen++; + + if (ctx->worker_sent >= NUM_PINGS) + uv_close((uv_handle_t*) &ctx->worker_async, NULL); +} + + +static void main_async_cb(uv_async_t* handle, int status) { + struct ctx* ctx = container_of(handle, struct ctx, main_async); + + ASSERT(0 == uv_async_send(&ctx->worker_async)); + ctx->main_sent++; + ctx->main_seen++; + + if (ctx->main_sent >= NUM_PINGS) + uv_close((uv_handle_t*) &ctx->main_async, NULL); +} + + +static void worker(void* arg) { + struct ctx* ctx = arg; + ASSERT(0 == uv_async_send(&ctx->main_async)); + ASSERT(0 == uv_run(ctx->loop, UV_RUN_DEFAULT)); +} + + +static int test_async(int nthreads) { + struct ctx* threads; + struct ctx* ctx; + uint64_t time; + int i; + + threads = calloc(nthreads, sizeof(threads[0])); + ASSERT(threads != NULL); + + for (i = 0; i < nthreads; i++) { + ctx = threads + i; + ctx->nthreads = nthreads; + ctx->loop = uv_loop_new(); + ASSERT(ctx->loop != NULL); + ASSERT(0 == uv_async_init(ctx->loop, &ctx->worker_async, worker_async_cb)); + ASSERT(0 == uv_async_init(uv_default_loop(), + &ctx->main_async, + main_async_cb)); + ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx)); + } + + time = uv_hrtime(); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + for (i = 0; i < nthreads; i++) + ASSERT(0 == uv_thread_join(&threads[i].thread)); + + time = uv_hrtime() - time; + + for (i = 0; i < nthreads; i++) { + ctx = threads + i; + ASSERT(ctx->worker_sent == NUM_PINGS); + ASSERT(ctx->worker_seen == NUM_PINGS); + ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS); + ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS); + } + + printf("async%d: %.2f sec (%s/sec)\n", + nthreads, + time / 1e9, + fmt(NUM_PINGS / (time / 1e9))); + + free(threads); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +BENCHMARK_IMPL(async1) { + return test_async(1); +} + + +BENCHMARK_IMPL(async2) { + return test_async(2); +} + + +BENCHMARK_IMPL(async4) { + return test_async(4); +} + + +BENCHMARK_IMPL(async8) { + return test_async(8); +} diff --git a/test/benchmark-fs-stat.c b/test/benchmark-fs-stat.c new file mode 100644 index 0000000000..5c87de0043 --- /dev/null +++ b/test/benchmark-fs-stat.c @@ -0,0 +1,136 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include + +#define NUM_SYNC_REQS (10 * 1e5) +#define NUM_ASYNC_REQS (1 * (int) 1e5) +#define MAX_CONCURRENT_REQS 32 + +#define sync_stat(req, path) \ + do { \ + uv_fs_stat(uv_default_loop(), (req), (path), NULL); \ + uv_fs_req_cleanup((req)); \ + } \ + while (0) + +struct async_req { + const char* path; + uv_fs_t fs_req; + int* count; +}; + + +static void warmup(const char* path) { + uv_fs_t reqs[MAX_CONCURRENT_REQS]; + unsigned int i; + + /* warm up the thread pool */ + for (i = 0; i < ARRAY_SIZE(reqs); i++) + uv_fs_stat(uv_default_loop(), reqs + i, path, uv_fs_req_cleanup); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + /* warm up the OS dirent cache */ + for (i = 0; i < 16; i++) + sync_stat(reqs + 0, path); +} + + +static void sync_bench(const char* path) { + uint64_t before; + uint64_t after; + uv_fs_t req; + int i; + + /* do the sync benchmark */ + before = uv_hrtime(); + + for (i = 0; i < NUM_SYNC_REQS; i++) + sync_stat(&req, path); + + after = uv_hrtime(); + + printf("%s stats (sync): %.2fs (%s/s)\n", + fmt(1.0 * NUM_SYNC_REQS), + (after - before) / 1e9, + fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9))); + fflush(stdout); +} + + +static void stat_cb(uv_fs_t* fs_req) { + struct async_req* req = container_of(fs_req, struct async_req, fs_req); + uv_fs_req_cleanup(&req->fs_req); + if (*req->count == 0) return; + uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb); + (*req->count)--; +} + + +static void async_bench(const char* path) { + struct async_req reqs[MAX_CONCURRENT_REQS]; + struct async_req* req; + uint64_t before; + uint64_t after; + int count; + int i; + + for (i = 1; i <= MAX_CONCURRENT_REQS; i++) { + count = NUM_ASYNC_REQS; + + for (req = reqs; req < reqs + i; req++) { + req->path = path; + req->count = &count; + uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb); + } + + before = uv_hrtime(); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + after = uv_hrtime(); + + printf("%s stats (%d concurrent): %.2fs (%s/s)\n", + fmt(1.0 * NUM_ASYNC_REQS), + i, + (after - before) / 1e9, + fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9))); + fflush(stdout); + } +} + + +/* This benchmark aims to measure the overhead of doing I/O syscalls from + * the thread pool. The stat() syscall was chosen because its results are + * easy for the operating system to cache, taking the actual I/O overhead + * out of the equation. + */ +BENCHMARK_IMPL(fs_stat) { + const char path[] = "."; + warmup(path); + sync_bench(path); + async_bench(path); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-getaddrinfo.c b/test/benchmark-getaddrinfo.c new file mode 100644 index 0000000000..c7f99a2fcb --- /dev/null +++ b/test/benchmark-getaddrinfo.c @@ -0,0 +1,91 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#define CONCURRENT_CALLS 10 +#define TOTAL_CALLS 10000 + +static const char* name = "localhost"; + +static uv_loop_t* loop; + +static uv_getaddrinfo_t handles[CONCURRENT_CALLS]; + +static int calls_initiated = 0; +static int calls_completed = 0; +static int64_t start_time; +static int64_t end_time; + + +static void getaddrinfo_initiate(uv_getaddrinfo_t* handle); + + +static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status, + struct addrinfo* res) { + ASSERT(status == 0); + calls_completed++; + if (calls_initiated < TOTAL_CALLS) { + getaddrinfo_initiate(handle); + } + + uv_freeaddrinfo(res); +} + + +static void getaddrinfo_initiate(uv_getaddrinfo_t* handle) { + int r; + + calls_initiated++; + + r = uv_getaddrinfo(loop, handle, &getaddrinfo_cb, name, NULL, NULL); + ASSERT(r == 0); +} + + +BENCHMARK_IMPL(getaddrinfo) { + int i; + + loop = uv_default_loop(); + + uv_update_time(loop); + start_time = uv_now(loop); + + for (i = 0; i < CONCURRENT_CALLS; i++) { + getaddrinfo_initiate(&handles[i]); + } + + uv_run(loop, UV_RUN_DEFAULT); + + uv_update_time(loop); + end_time = uv_now(loop); + + ASSERT(calls_initiated == TOTAL_CALLS); + ASSERT(calls_completed == TOTAL_CALLS); + + LOGF("getaddrinfo: %.0f req/s\n", + (double) calls_completed / (double) (end_time - start_time) * 1000.0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-list.h b/test/benchmark-list.h new file mode 100644 index 0000000000..1e843071c0 --- /dev/null +++ b/test/benchmark-list.h @@ -0,0 +1,163 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +BENCHMARK_DECLARE (sizes) +BENCHMARK_DECLARE (loop_count) +BENCHMARK_DECLARE (loop_count_timed) +BENCHMARK_DECLARE (ping_pongs) +BENCHMARK_DECLARE (tcp_write_batch) +BENCHMARK_DECLARE (tcp4_pound_100) +BENCHMARK_DECLARE (tcp4_pound_1000) +BENCHMARK_DECLARE (pipe_pound_100) +BENCHMARK_DECLARE (pipe_pound_1000) +BENCHMARK_DECLARE (tcp_pump100_client) +BENCHMARK_DECLARE (tcp_pump1_client) +BENCHMARK_DECLARE (pipe_pump100_client) +BENCHMARK_DECLARE (pipe_pump1_client) + +BENCHMARK_DECLARE (tcp_multi_accept2) +BENCHMARK_DECLARE (tcp_multi_accept4) +BENCHMARK_DECLARE (tcp_multi_accept8) + +/* Run until X packets have been sent/received. */ +BENCHMARK_DECLARE (udp_pummel_1v1) +BENCHMARK_DECLARE (udp_pummel_1v10) +BENCHMARK_DECLARE (udp_pummel_1v100) +BENCHMARK_DECLARE (udp_pummel_1v1000) +BENCHMARK_DECLARE (udp_pummel_10v10) +BENCHMARK_DECLARE (udp_pummel_10v100) +BENCHMARK_DECLARE (udp_pummel_10v1000) +BENCHMARK_DECLARE (udp_pummel_100v100) +BENCHMARK_DECLARE (udp_pummel_100v1000) +BENCHMARK_DECLARE (udp_pummel_1000v1000) + +/* Run until X seconds have elapsed. */ +BENCHMARK_DECLARE (udp_timed_pummel_1v1) +BENCHMARK_DECLARE (udp_timed_pummel_1v10) +BENCHMARK_DECLARE (udp_timed_pummel_1v100) +BENCHMARK_DECLARE (udp_timed_pummel_1v1000) +BENCHMARK_DECLARE (udp_timed_pummel_10v10) +BENCHMARK_DECLARE (udp_timed_pummel_10v100) +BENCHMARK_DECLARE (udp_timed_pummel_10v1000) +BENCHMARK_DECLARE (udp_timed_pummel_100v100) +BENCHMARK_DECLARE (udp_timed_pummel_100v1000) +BENCHMARK_DECLARE (udp_timed_pummel_1000v1000) + +BENCHMARK_DECLARE (getaddrinfo) +BENCHMARK_DECLARE (fs_stat) +BENCHMARK_DECLARE (async1) +BENCHMARK_DECLARE (async2) +BENCHMARK_DECLARE (async4) +BENCHMARK_DECLARE (async8) +BENCHMARK_DECLARE (async_pummel_1) +BENCHMARK_DECLARE (async_pummel_2) +BENCHMARK_DECLARE (async_pummel_4) +BENCHMARK_DECLARE (async_pummel_8) +BENCHMARK_DECLARE (spawn) +BENCHMARK_DECLARE (thread_create) +BENCHMARK_DECLARE (million_async) +BENCHMARK_DECLARE (million_timers) +HELPER_DECLARE (tcp4_blackhole_server) +HELPER_DECLARE (tcp_pump_server) +HELPER_DECLARE (pipe_pump_server) +HELPER_DECLARE (tcp4_echo_server) +HELPER_DECLARE (pipe_echo_server) +HELPER_DECLARE (dns_server) + +TASK_LIST_START + BENCHMARK_ENTRY (sizes) + BENCHMARK_ENTRY (loop_count) + BENCHMARK_ENTRY (loop_count_timed) + + BENCHMARK_ENTRY (ping_pongs) + BENCHMARK_HELPER (ping_pongs, tcp4_echo_server) + + BENCHMARK_ENTRY (tcp_write_batch) + BENCHMARK_HELPER (tcp_write_batch, tcp4_blackhole_server) + + BENCHMARK_ENTRY (tcp_pump100_client) + BENCHMARK_HELPER (tcp_pump100_client, tcp_pump_server) + + BENCHMARK_ENTRY (tcp_pump1_client) + BENCHMARK_HELPER (tcp_pump1_client, tcp_pump_server) + + BENCHMARK_ENTRY (tcp4_pound_100) + BENCHMARK_HELPER (tcp4_pound_100, tcp4_echo_server) + + BENCHMARK_ENTRY (tcp4_pound_1000) + BENCHMARK_HELPER (tcp4_pound_1000, tcp4_echo_server) + + BENCHMARK_ENTRY (pipe_pump100_client) + BENCHMARK_HELPER (pipe_pump100_client, pipe_pump_server) + + BENCHMARK_ENTRY (pipe_pump1_client) + BENCHMARK_HELPER (pipe_pump1_client, pipe_pump_server) + + BENCHMARK_ENTRY (pipe_pound_100) + BENCHMARK_HELPER (pipe_pound_100, pipe_echo_server) + + BENCHMARK_ENTRY (pipe_pound_1000) + BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server) + + BENCHMARK_ENTRY (tcp_multi_accept2) + BENCHMARK_ENTRY (tcp_multi_accept4) + BENCHMARK_ENTRY (tcp_multi_accept8) + + BENCHMARK_ENTRY (udp_pummel_1v1) + BENCHMARK_ENTRY (udp_pummel_1v10) + BENCHMARK_ENTRY (udp_pummel_1v100) + BENCHMARK_ENTRY (udp_pummel_1v1000) + BENCHMARK_ENTRY (udp_pummel_10v10) + BENCHMARK_ENTRY (udp_pummel_10v100) + BENCHMARK_ENTRY (udp_pummel_10v1000) + BENCHMARK_ENTRY (udp_pummel_100v100) + BENCHMARK_ENTRY (udp_pummel_100v1000) + BENCHMARK_ENTRY (udp_pummel_1000v1000) + + BENCHMARK_ENTRY (udp_timed_pummel_1v1) + BENCHMARK_ENTRY (udp_timed_pummel_1v10) + BENCHMARK_ENTRY (udp_timed_pummel_1v100) + BENCHMARK_ENTRY (udp_timed_pummel_1v1000) + BENCHMARK_ENTRY (udp_timed_pummel_10v10) + BENCHMARK_ENTRY (udp_timed_pummel_10v100) + BENCHMARK_ENTRY (udp_timed_pummel_10v1000) + BENCHMARK_ENTRY (udp_timed_pummel_100v100) + BENCHMARK_ENTRY (udp_timed_pummel_100v1000) + BENCHMARK_ENTRY (udp_timed_pummel_1000v1000) + + BENCHMARK_ENTRY (getaddrinfo) + + BENCHMARK_ENTRY (fs_stat) + + BENCHMARK_ENTRY (async1) + BENCHMARK_ENTRY (async2) + BENCHMARK_ENTRY (async4) + BENCHMARK_ENTRY (async8) + BENCHMARK_ENTRY (async_pummel_1) + BENCHMARK_ENTRY (async_pummel_2) + BENCHMARK_ENTRY (async_pummel_4) + BENCHMARK_ENTRY (async_pummel_8) + + BENCHMARK_ENTRY (spawn) + BENCHMARK_ENTRY (thread_create) + BENCHMARK_ENTRY (million_async) + BENCHMARK_ENTRY (million_timers) +TASK_LIST_END diff --git a/test/benchmark-loop-count.c b/test/benchmark-loop-count.c new file mode 100644 index 0000000000..b4ee0ed5ff --- /dev/null +++ b/test/benchmark-loop-count.c @@ -0,0 +1,90 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include + +#define NUM_TICKS (2 * 1000 * 1000) + +static unsigned long ticks; +static uv_idle_t idle_handle; +static uv_timer_t timer_handle; + + +static void idle_cb(uv_idle_t* handle, int status) { + if (++ticks == NUM_TICKS) + uv_idle_stop(handle); +} + + +static void idle2_cb(uv_idle_t* handle, int status) { + ticks++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_idle_stop(&idle_handle); + uv_timer_stop(&timer_handle); +} + + +BENCHMARK_IMPL(loop_count) { + uv_loop_t* loop = uv_default_loop(); + uint64_t ns; + + uv_idle_init(loop, &idle_handle); + uv_idle_start(&idle_handle, idle_cb); + + ns = uv_hrtime(); + uv_run(loop, UV_RUN_DEFAULT); + ns = uv_hrtime() - ns; + + ASSERT(ticks == NUM_TICKS); + + LOGF("loop_count: %d ticks in %.2fs (%.0f/s)\n", + NUM_TICKS, + ns / 1e9, + NUM_TICKS / (ns / 1e9)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +BENCHMARK_IMPL(loop_count_timed) { + uv_loop_t* loop = uv_default_loop(); + + uv_idle_init(loop, &idle_handle); + uv_idle_start(&idle_handle, idle2_cb); + + uv_timer_init(loop, &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 5000, 0); + + uv_run(loop, UV_RUN_DEFAULT); + + LOGF("loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-million-async.c b/test/benchmark-million-async.c new file mode 100644 index 0000000000..69cc803436 --- /dev/null +++ b/test/benchmark-million-async.c @@ -0,0 +1,112 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +struct async_container { + unsigned async_events; + unsigned handles_seen; + uv_async_t async_handles[1024 * 1024]; +}; + +static volatile int done; +static uv_thread_t thread_id; +static struct async_container* container; + + +static unsigned fastrand(void) { + static unsigned g = 0; + g = g * 214013 + 2531011; + return g; +} + + +static void thread_cb(void* arg) { + unsigned i; + + while (done == 0) { + i = fastrand() % ARRAY_SIZE(container->async_handles); + uv_async_send(container->async_handles + i); + } +} + + +static void async_cb(uv_async_t* handle, int status) { + container->async_events++; + handle->data = handle; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + unsigned i; + + done = 1; + ASSERT(0 == uv_thread_join(&thread_id)); + + for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) { + uv_async_t* handle = container->async_handles + i; + + if (handle->data != NULL) + container->handles_seen++; + + uv_close((uv_handle_t*) handle, NULL); + } + + uv_close((uv_handle_t*) handle, NULL); +} + + +BENCHMARK_IMPL(million_async) { + uv_timer_t timer_handle; + uv_async_t* handle; + uv_loop_t* loop; + int timeout; + unsigned i; + + loop = uv_default_loop(); + timeout = 5000; + + container = malloc(sizeof(*container)); + ASSERT(container != NULL); + container->async_events = 0; + container->handles_seen = 0; + + for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) { + handle = container->async_handles + i; + ASSERT(0 == uv_async_init(loop, handle, async_cb)); + handle->data = NULL; + } + + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0)); + ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n", + fmt(container->async_events), + timeout / 1000., + fmt(container->async_events / (timeout / 1000.)), + fmt(container->handles_seen)); + free(container); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-million-timers.c b/test/benchmark-million-timers.c new file mode 100644 index 0000000000..64f4a1038e --- /dev/null +++ b/test/benchmark-million-timers.c @@ -0,0 +1,85 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#define NUM_TIMERS (10 * 1000 * 1000) + +static int timer_cb_called; +static int close_cb_called; + + +static void timer_cb(uv_timer_t* handle, int status) { + timer_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +BENCHMARK_IMPL(million_timers) { + uv_timer_t* timers; + uv_loop_t* loop; + uint64_t before_all; + uint64_t before_run; + uint64_t after_run; + uint64_t after_all; + int timeout; + int i; + + timers = malloc(NUM_TIMERS * sizeof(timers[0])); + ASSERT(timers != NULL); + + loop = uv_default_loop(); + timeout = 0; + + before_all = uv_hrtime(); + for (i = 0; i < NUM_TIMERS; i++) { + if (i % 1000 == 0) timeout++; + ASSERT(0 == uv_timer_init(loop, timers + i)); + ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0)); + } + + before_run = uv_hrtime(); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + after_run = uv_hrtime(); + + for (i = 0; i < NUM_TIMERS; i++) + uv_close((uv_handle_t*) (timers + i), close_cb); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + after_all = uv_hrtime(); + + ASSERT(timer_cb_called == NUM_TIMERS); + ASSERT(close_cb_called == NUM_TIMERS); + free(timers); + + LOGF("%.2f seconds total\n", (after_all - before_all) / 1e9); + LOGF("%.2f seconds init\n", (before_run - before_all) / 1e9); + LOGF("%.2f seconds dispatch\n", (after_run - before_run) / 1e9); + LOGF("%.2f seconds cleanup\n", (after_all - after_run) / 1e9); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-multi-accept.c b/test/benchmark-multi-accept.c new file mode 100644 index 0000000000..d71235ef3b --- /dev/null +++ b/test/benchmark-multi-accept.c @@ -0,0 +1,445 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#define IPC_PIPE_NAME TEST_PIPENAME +#define NUM_CONNECTS (250 * 1000) + +union stream_handle { + uv_pipe_t pipe; + uv_tcp_t tcp; +}; + +/* Use as (uv_stream_t *) &handle_storage -- it's kind of clunky but it + * avoids aliasing warnings. + */ +typedef unsigned char handle_storage_t[sizeof(union stream_handle)]; + +/* Used for passing around the listen handle, not part of the benchmark proper. + * We have an overabundance of server types here. It works like this: + * + * 1. The main thread starts an IPC pipe server. + * 2. The worker threads connect to the IPC server and obtain a listen handle. + * 3. The worker threads start accepting requests on the listen handle. + * 4. The main thread starts connecting repeatedly. + * + * Step #4 should perhaps be farmed out over several threads. + */ +struct ipc_server_ctx { + handle_storage_t server_handle; + unsigned int num_connects; + uv_pipe_t ipc_pipe; +}; + +struct ipc_peer_ctx { + handle_storage_t peer_handle; + uv_write_t write_req; +}; + +struct ipc_client_ctx { + uv_connect_t connect_req; + uv_stream_t* server_handle; + uv_pipe_t ipc_pipe; + char scratch[16]; +}; + +/* Used in the actual benchmark. */ +struct server_ctx { + handle_storage_t server_handle; + unsigned int num_connects; + uv_async_t async_handle; + uv_thread_t thread_id; + uv_sem_t semaphore; +}; + +struct client_ctx { + handle_storage_t client_handle; + unsigned int num_connects; + uv_connect_t connect_req; + uv_idle_t idle_handle; +}; + +static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status); +static void ipc_write_cb(uv_write_t* req, int status); +static void ipc_close_cb(uv_handle_t* handle); +static void ipc_connect_cb(uv_connect_t* req, int status); +static void ipc_read2_cb(uv_pipe_t* ipc_pipe, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type type); +static void ipc_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); + +static void sv_async_cb(uv_async_t* handle, int status); +static void sv_connection_cb(uv_stream_t* server_handle, int status); +static void sv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf); +static void sv_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); + +static void cl_connect_cb(uv_connect_t* req, int status); +static void cl_idle_cb(uv_idle_t* handle, int status); +static void cl_close_cb(uv_handle_t* handle); + +static struct sockaddr_in listen_addr; + + +static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) { + struct ipc_server_ctx* sc; + struct ipc_peer_ctx* pc; + uv_loop_t* loop; + uv_buf_t buf; + + loop = ipc_pipe->loop; + buf = uv_buf_init("PING", 4); + sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe); + pc = calloc(1, sizeof(*pc)); + ASSERT(pc != NULL); + + if (ipc_pipe->type == UV_TCP) + ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle)); + else if (ipc_pipe->type == UV_NAMED_PIPE) + ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1)); + else + ASSERT(0); + + ASSERT(0 == uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle)); + ASSERT(0 == uv_write2(&pc->write_req, + (uv_stream_t*) &pc->peer_handle, + &buf, + 1, + (uv_stream_t*) &sc->server_handle, + ipc_write_cb)); + + if (--sc->num_connects == 0) + uv_close((uv_handle_t*) ipc_pipe, NULL); +} + + +static void ipc_write_cb(uv_write_t* req, int status) { + struct ipc_peer_ctx* ctx; + ctx = container_of(req, struct ipc_peer_ctx, write_req); + uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb); +} + + +static void ipc_close_cb(uv_handle_t* handle) { + struct ipc_peer_ctx* ctx; + ctx = container_of(handle, struct ipc_peer_ctx, peer_handle); + free(ctx); +} + + +static void ipc_connect_cb(uv_connect_t* req, int status) { + struct ipc_client_ctx* ctx; + ctx = container_of(req, struct ipc_client_ctx, connect_req); + ASSERT(0 == status); + ASSERT(0 == uv_read2_start((uv_stream_t*) &ctx->ipc_pipe, + ipc_alloc_cb, + ipc_read2_cb)); +} + + +static void ipc_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + struct ipc_client_ctx* ctx; + ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe); + buf->base = ctx->scratch; + buf->len = sizeof(ctx->scratch); +} + + +static void ipc_read2_cb(uv_pipe_t* ipc_pipe, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type type) { + struct ipc_client_ctx* ctx; + uv_loop_t* loop; + + ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe); + loop = ipc_pipe->loop; + + if (type == UV_TCP) + ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle)); + else if (type == UV_NAMED_PIPE) + ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0)); + else + ASSERT(0); + + ASSERT(0 == uv_accept((uv_stream_t*) &ctx->ipc_pipe, ctx->server_handle)); + uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL); +} + + +/* Set up an IPC pipe server that hands out listen sockets to the worker + * threads. It's kind of cumbersome for such a simple operation, maybe we + * should revive uv_import() and uv_export(). + */ +static void send_listen_handles(uv_handle_type type, + unsigned int num_servers, + struct server_ctx* servers) { + struct ipc_server_ctx ctx; + uv_loop_t* loop; + unsigned int i; + + loop = uv_default_loop(); + ctx.num_connects = num_servers; + + if (type == UV_TCP) { + ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle)); + ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, + (const struct sockaddr*) &listen_addr, + 0)); + } + else + ASSERT(0); + + ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1)); + ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME)); + ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb)); + + for (i = 0; i < num_servers; i++) + uv_sem_post(&servers[i].semaphore); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + uv_close((uv_handle_t*) &ctx.server_handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + for (i = 0; i < num_servers; i++) + uv_sem_wait(&servers[i].semaphore); +} + + +static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) { + struct ipc_client_ctx ctx; + + ctx.server_handle = server_handle; + ctx.server_handle->data = "server handle"; + + ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1)); + uv_pipe_connect(&ctx.connect_req, + &ctx.ipc_pipe, + IPC_PIPE_NAME, + ipc_connect_cb); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); +} + + +static void server_cb(void *arg) { + struct server_ctx *ctx; + uv_loop_t* loop; + + ctx = arg; + loop = uv_loop_new(); + ASSERT(loop != NULL); + + ASSERT(0 == uv_async_init(loop, &ctx->async_handle, sv_async_cb)); + uv_unref((uv_handle_t*) &ctx->async_handle); + + /* Wait until the main thread is ready. */ + uv_sem_wait(&ctx->semaphore); + get_listen_handle(loop, (uv_stream_t*) &ctx->server_handle); + uv_sem_post(&ctx->semaphore); + + /* Now start the actual benchmark. */ + ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle, + 128, + sv_connection_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + uv_loop_delete(loop); +} + + +static void sv_async_cb(uv_async_t* handle, int status) { + struct server_ctx* ctx; + ctx = container_of(handle, struct server_ctx, async_handle); + uv_close((uv_handle_t*) &ctx->server_handle, NULL); + uv_close((uv_handle_t*) &ctx->async_handle, NULL); +} + + +static void sv_connection_cb(uv_stream_t* server_handle, int status) { + handle_storage_t* storage; + struct server_ctx* ctx; + + ctx = container_of(server_handle, struct server_ctx, server_handle); + ASSERT(status == 0); + + storage = malloc(sizeof(*storage)); + ASSERT(storage != NULL); + + if (server_handle->type == UV_TCP) + ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage)); + else if (server_handle->type == UV_NAMED_PIPE) + ASSERT(0 == uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0)); + else + ASSERT(0); + + ASSERT(0 == uv_accept(server_handle, (uv_stream_t*) storage)); + ASSERT(0 == uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb)); + ctx->num_connects++; +} + + +static void sv_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[32]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void sv_read_cb(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t*) handle, (uv_close_cb) free); +} + + +static void cl_connect_cb(uv_connect_t* req, int status) { + struct client_ctx* ctx = container_of(req, struct client_ctx, connect_req); + uv_idle_start(&ctx->idle_handle, cl_idle_cb); + ASSERT(0 == status); +} + + +static void cl_idle_cb(uv_idle_t* handle, int status) { + struct client_ctx* ctx = container_of(handle, struct client_ctx, idle_handle); + uv_close((uv_handle_t*) &ctx->client_handle, cl_close_cb); + uv_idle_stop(&ctx->idle_handle); +} + + +static void cl_close_cb(uv_handle_t* handle) { + struct client_ctx* ctx; + + ctx = container_of(handle, struct client_ctx, client_handle); + + if (--ctx->num_connects == 0) { + uv_close((uv_handle_t*) &ctx->idle_handle, NULL); + return; + } + + ASSERT(0 == uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle)); + ASSERT(0 == uv_tcp_connect(&ctx->connect_req, + (uv_tcp_t*) &ctx->client_handle, + (const struct sockaddr*) &listen_addr, + cl_connect_cb)); +} + + +static int test_tcp(unsigned int num_servers, unsigned int num_clients) { + struct server_ctx* servers; + struct client_ctx* clients; + uv_loop_t* loop; + uv_tcp_t* handle; + unsigned int i; + double time; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr)); + loop = uv_default_loop(); + + servers = calloc(num_servers, sizeof(servers[0])); + clients = calloc(num_clients, sizeof(clients[0])); + ASSERT(servers != NULL); + ASSERT(clients != NULL); + + /* We're making the assumption here that from the perspective of the + * OS scheduler, threads are functionally equivalent to and interchangeable + * with full-blown processes. + */ + for (i = 0; i < num_servers; i++) { + struct server_ctx* ctx = servers + i; + ASSERT(0 == uv_sem_init(&ctx->semaphore, 0)); + ASSERT(0 == uv_thread_create(&ctx->thread_id, server_cb, ctx)); + } + + send_listen_handles(UV_TCP, num_servers, servers); + + for (i = 0; i < num_clients; i++) { + struct client_ctx* ctx = clients + i; + ctx->num_connects = NUM_CONNECTS / num_clients; + handle = (uv_tcp_t*) &ctx->client_handle; + handle->data = "client handle"; + ASSERT(0 == uv_tcp_init(loop, handle)); + ASSERT(0 == uv_tcp_connect(&ctx->connect_req, + handle, + (const struct sockaddr*) &listen_addr, + cl_connect_cb)); + ASSERT(0 == uv_idle_init(loop, &ctx->idle_handle)); + } + + { + uint64_t t = uv_hrtime(); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + t = uv_hrtime() - t; + time = t / 1e9; + } + + for (i = 0; i < num_servers; i++) { + struct server_ctx* ctx = servers + i; + uv_async_send(&ctx->async_handle); + ASSERT(0 == uv_thread_join(&ctx->thread_id)); + uv_sem_destroy(&ctx->semaphore); + } + + printf("accept%u: %.0f accepts/sec (%u total)\n", + num_servers, + NUM_CONNECTS / time, + NUM_CONNECTS); + + for (i = 0; i < num_servers; i++) { + struct server_ctx* ctx = servers + i; + printf(" thread #%u: %.0f accepts/sec (%u total, %.1f%%)\n", + i, + ctx->num_connects / time, + ctx->num_connects, + ctx->num_connects * 100.0 / NUM_CONNECTS); + } + + free(clients); + free(servers); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +BENCHMARK_IMPL(tcp_multi_accept2) { + return test_tcp(2, 40); +} + + +BENCHMARK_IMPL(tcp_multi_accept4) { + return test_tcp(4, 40); +} + + +BENCHMARK_IMPL(tcp_multi_accept8) { + return test_tcp(8, 40); +} diff --git a/test/benchmark-ping-pongs.c b/test/benchmark-ping-pongs.c new file mode 100644 index 0000000000..bb560d7d21 --- /dev/null +++ b/test/benchmark-ping-pongs.c @@ -0,0 +1,220 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +/* Run the benchmark for this many ms */ +#define TIME 5000 + + +typedef struct { + int pongs; + int state; + uv_tcp_t tcp; + uv_connect_t connect_req; + uv_shutdown_t shutdown_req; +} pinger_t; + +typedef struct buf_s { + uv_buf_t uv_buf_t; + struct buf_s* next; +} buf_t; + + +static char PING[] = "PING\n"; + +static uv_loop_t* loop; + +static buf_t* buf_freelist = NULL; +static int pinger_shutdown_cb_called; +static int completed_pingers = 0; +static int64_t start_time; + + +static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) { + buf_t* ab; + + ab = buf_freelist; + if (ab != NULL) + buf_freelist = ab->next; + else { + ab = malloc(size + sizeof(*ab)); + ab->uv_buf_t.len = size; + ab->uv_buf_t.base = (char*) (ab + 1); + } + + *buf = ab->uv_buf_t; +} + + +static void buf_free(const uv_buf_t* buf) { + buf_t* ab = (buf_t*) buf->base - 1; + ab->next = buf_freelist; + buf_freelist = ab; +} + + +static void pinger_close_cb(uv_handle_t* handle) { + pinger_t* pinger; + + pinger = (pinger_t*)handle->data; + LOGF("ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME); + + free(pinger); + + completed_pingers++; +} + + +static void pinger_write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + + free(req); +} + + +static void pinger_write_ping(pinger_t* pinger) { + uv_write_t* req; + uv_buf_t buf; + + buf = uv_buf_init(PING, sizeof(PING) - 1); + + req = malloc(sizeof *req); + if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) { + FATAL("uv_write failed"); + } +} + + +static void pinger_shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(status == 0); + pinger_shutdown_cb_called++; + + /* + * The close callback has not been triggered yet. We must wait for EOF + * until we close the connection. + */ + ASSERT(completed_pingers == 0); +} + + +static void pinger_read_cb(uv_stream_t* tcp, + ssize_t nread, + const uv_buf_t* buf) { + ssize_t i; + pinger_t* pinger; + + pinger = (pinger_t*)tcp->data; + + if (nread < 0) { + ASSERT(nread == UV_EOF); + + if (buf->base) { + buf_free(buf); + } + + ASSERT(pinger_shutdown_cb_called == 1); + uv_close((uv_handle_t*)tcp, pinger_close_cb); + + return; + } + + /* Now we count the pings */ + for (i = 0; i < nread; i++) { + ASSERT(buf->base[i] == PING[pinger->state]); + pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); + if (pinger->state == 0) { + pinger->pongs++; + if (uv_now(loop) - start_time > TIME) { + uv_shutdown(&pinger->shutdown_req, + (uv_stream_t*) tcp, + pinger_shutdown_cb); + break; + } else { + pinger_write_ping(pinger); + } + } + } + + buf_free(buf); +} + + +static void pinger_connect_cb(uv_connect_t* req, int status) { + pinger_t *pinger = (pinger_t*)req->handle->data; + + ASSERT(status == 0); + + pinger_write_ping(pinger); + + if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) { + FATAL("uv_read_start failed"); + } +} + + +static void pinger_new(void) { + struct sockaddr_in client_addr; + struct sockaddr_in server_addr; + pinger_t *pinger; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr)); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + pinger = malloc(sizeof(*pinger)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ + r = uv_tcp_init(loop, &pinger->tcp); + ASSERT(!r); + + pinger->tcp.data = pinger; + + ASSERT(0 == uv_tcp_bind(&pinger->tcp, + (const struct sockaddr*) &client_addr, + 0)); + + r = uv_tcp_connect(&pinger->connect_req, + &pinger->tcp, + (const struct sockaddr*) &server_addr, + pinger_connect_cb); + ASSERT(!r); +} + + +BENCHMARK_IMPL(ping_pongs) { + loop = uv_default_loop(); + + start_time = uv_now(loop); + + pinger_new(); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(completed_pingers == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-pound.c b/test/benchmark-pound.c new file mode 100644 index 0000000000..587928549e --- /dev/null +++ b/test/benchmark-pound.c @@ -0,0 +1,350 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +/* Update this is you're going to run > 1000 concurrent requests. */ +#define MAX_CONNS 1000 + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +#undef DEBUG +#define DEBUG 0 + +struct conn_rec_s; + +typedef void (*setup_fn)(int num, void* arg); +typedef void (*make_connect_fn)(struct conn_rec_s* conn); +typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg); + +/* Base class for tcp_conn_rec and pipe_conn_rec. + * The ordering of fields matters! + */ +typedef struct conn_rec_s { + int i; + uv_connect_t conn_req; + uv_write_t write_req; + make_connect_fn make_connect; + uv_stream_t stream; +} conn_rec; + +typedef struct { + int i; + uv_connect_t conn_req; + uv_write_t write_req; + make_connect_fn make_connect; + uv_tcp_t stream; +} tcp_conn_rec; + +typedef struct { + int i; + uv_connect_t conn_req; + uv_write_t write_req; + make_connect_fn make_connect; + uv_pipe_t stream; +} pipe_conn_rec; + +static char buffer[] = "QS"; + +static uv_loop_t* loop; + +static tcp_conn_rec tcp_conns[MAX_CONNS]; +static pipe_conn_rec pipe_conns[MAX_CONNS]; + +static uint64_t start; /* in ms */ +static int closed_streams; +static int conns_failed; + +static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); +static void connect_cb(uv_connect_t* conn_req, int status); +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); +static void close_cb(uv_handle_t* handle); + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void after_write(uv_write_t* req, int status) { + if (status != 0) { + fprintf(stderr, "write error %s\n", uv_err_name(status)); + uv_close((uv_handle_t*)req->handle, close_cb); + conns_failed++; + return; + } +} + + +static void connect_cb(uv_connect_t* req, int status) { + conn_rec* conn; + uv_buf_t buf; + int r; + + if (status != 0) { +#if DEBUG + fprintf(stderr, "connect error %s\n", uv_err_name(status)); +#endif + uv_close((uv_handle_t*)req->handle, close_cb); + conns_failed++; + return; + } + + ASSERT(req != NULL); + ASSERT(status == 0); + + conn = (conn_rec*)req->data; + ASSERT(conn != NULL); + +#if DEBUG + printf("connect_cb %d\n", conn->i); +#endif + + r = uv_read_start(&conn->stream, alloc_cb, read_cb); + ASSERT(r == 0); + + buf.base = buffer; + buf.len = sizeof(buffer) - 1; + + r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write); + ASSERT(r == 0); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + + ASSERT(stream != NULL); + +#if DEBUG + printf("read_cb %d\n", p->i); +#endif + + uv_close((uv_handle_t*)stream, close_cb); + + if (nread < 0) { + if (nread == UV_EOF) { + ; + } else if (nread == UV_ECONNRESET) { + conns_failed++; + } else { + fprintf(stderr, "read error %s\n", uv_err_name(nread)); + ASSERT(0); + } + } +} + + +static void close_cb(uv_handle_t* handle) { + conn_rec* p = (conn_rec*)handle->data; + + ASSERT(handle != NULL); + closed_streams++; + +#if DEBUG + printf("close_cb %d\n", p->i); +#endif + + if (uv_now(loop) - start < 10000) { + p->make_connect(p); + } +} + + +static void tcp_do_setup(int num, void* arg) { + int i; + + for (i = 0; i < num; i++) { + tcp_conns[i].i = i; + } +} + + +static void pipe_do_setup(int num, void* arg) { + int i; + + for (i = 0; i < num; i++) { + pipe_conns[i].i = i; + } +} + + +static void tcp_make_connect(conn_rec* p) { + struct sockaddr_in addr; + tcp_conn_rec* tp; + int r; + + tp = (tcp_conn_rec*) p; + + r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_connect(&tp->conn_req, + (uv_tcp_t*) &p->stream, + (const struct sockaddr*) &addr, + connect_cb); + if (r) { + fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r)); + ASSERT(0); + } + +#if DEBUG + printf("make connect %d\n", p->i); +#endif + + p->conn_req.data = p; + p->write_req.data = p; + p->stream.data = p; +} + + +static void pipe_make_connect(conn_rec* p) { + int r; + + r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0); + ASSERT(r == 0); + + uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req, + (uv_pipe_t*) &p->stream, + TEST_PIPENAME, + connect_cb); + +#if DEBUG + printf("make connect %d\n", p->i); +#endif + + p->conn_req.data = p; + p->write_req.data = p; + p->stream.data = p; +} + + +static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) { + int i; + + for (i = 0; i < num; i++) { + tcp_make_connect((conn_rec*)&tcp_conns[i]); + tcp_conns[i].make_connect = make_connect; + } + + return 0; +} + + +static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) { + int i; + + for (i = 0; i < num; i++) { + pipe_make_connect((conn_rec*)&pipe_conns[i]); + pipe_conns[i].make_connect = make_connect; + } + + return 0; +} + + +static int pound_it(int concurrency, + const char* type, + setup_fn do_setup, + connect_fn do_connect, + make_connect_fn make_connect, + void* arg) { + double secs; + int r; + uint64_t start_time; /* in ns */ + uint64_t end_time; + + loop = uv_default_loop(); + + uv_update_time(loop); + start = uv_now(loop); + + /* Run benchmark for at least five seconds. */ + start_time = uv_hrtime(); + + do_setup(concurrency, arg); + + r = do_connect(concurrency, make_connect, arg); + ASSERT(!r); + + uv_run(loop, UV_RUN_DEFAULT); + + end_time = uv_hrtime(); + + /* Number of fractional seconds it took to run the benchmark. */ + secs = (double)(end_time - start_time) / NANOSEC; + + LOGF("%s-conn-pound-%d: %.0f accepts/s (%d failed)\n", + type, + concurrency, + closed_streams / secs, + conns_failed); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +BENCHMARK_IMPL(tcp4_pound_100) { + return pound_it(100, + "tcp", + tcp_do_setup, + tcp_do_connect, + tcp_make_connect, + NULL); +} + + +BENCHMARK_IMPL(tcp4_pound_1000) { + return pound_it(1000, + "tcp", + tcp_do_setup, + tcp_do_connect, + tcp_make_connect, + NULL); +} + + +BENCHMARK_IMPL(pipe_pound_100) { + return pound_it(100, + "pipe", + pipe_do_setup, + pipe_do_connect, + pipe_make_connect, + NULL); +} + + +BENCHMARK_IMPL(pipe_pound_1000) { + return pound_it(1000, + "pipe", + pipe_do_setup, + pipe_do_connect, + pipe_make_connect, + NULL); +} diff --git a/test/benchmark-pump.c b/test/benchmark-pump.c new file mode 100644 index 0000000000..678634ff71 --- /dev/null +++ b/test/benchmark-pump.c @@ -0,0 +1,470 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include + + +static int TARGET_CONNECTIONS; +#define WRITE_BUFFER_SIZE 8192 +#define MAX_SIMULTANEOUS_CONNECTS 100 + +#define PRINT_STATS 0 +#define STATS_INTERVAL 1000 /* msec */ +#define STATS_COUNT 5 + + +static void do_write(uv_stream_t*); +static void maybe_connect_some(); + +static uv_req_t* req_alloc(); +static void req_free(uv_req_t* uv_req); + +static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); +static void buf_free(const uv_buf_t* buf); + +static uv_loop_t* loop; + +static uv_tcp_t tcpServer; +static uv_pipe_t pipeServer; +static uv_stream_t* server; +static struct sockaddr_in listen_addr; +static struct sockaddr_in connect_addr; + +static int64_t start_time; + +static int max_connect_socket = 0; +static int max_read_sockets = 0; +static int read_sockets = 0; +static int write_sockets = 0; + +static int64_t nrecv = 0; +static int64_t nrecv_total = 0; +static int64_t nsent = 0; +static int64_t nsent_total = 0; + +static int stats_left = 0; + +static char write_buffer[WRITE_BUFFER_SIZE]; + +/* Make this as large as you need. */ +#define MAX_WRITE_HANDLES 1000 + +static stream_type type; + +static uv_tcp_t tcp_write_handles[MAX_WRITE_HANDLES]; +static uv_pipe_t pipe_write_handles[MAX_WRITE_HANDLES]; + +static uv_timer_t timer_handle; + + +static double gbit(int64_t bytes, int64_t passed_ms) { + double gbits = ((double)bytes / (1024 * 1024 * 1024)) * 8; + return gbits / ((double)passed_ms / 1000); +} + + +static void show_stats(uv_timer_t* handle, int status) { + int64_t diff; + int i; + +#if PRINT_STATS + LOGF("connections: %d, write: %.1f gbit/s\n", + write_sockets, + gbit(nsent, STATS_INTERVAL)); +#endif + + /* Exit if the show is over */ + if (!--stats_left) { + + uv_update_time(loop); + diff = uv_now(loop) - start_time; + + LOGF("%s_pump%d_client: %.1f gbit/s\n", + type == TCP ? "tcp" : "pipe", + write_sockets, + gbit(nsent_total, diff)); + + for (i = 0; i < write_sockets; i++) { + if (type == TCP) + uv_close((uv_handle_t*) &tcp_write_handles[i], NULL); + else + uv_close((uv_handle_t*) &pipe_write_handles[i], NULL); + } + + exit(0); + } + + /* Reset read and write counters */ + nrecv = 0; + nsent = 0; +} + + +static void read_show_stats(void) { + int64_t diff; + + uv_update_time(loop); + diff = uv_now(loop) - start_time; + + LOGF("%s_pump%d_server: %.1f gbit/s\n", + type == TCP ? "tcp" : "pipe", + max_read_sockets, + gbit(nrecv_total, diff)); +} + + + +static void read_sockets_close_cb(uv_handle_t* handle) { + free(handle); + read_sockets--; + + /* If it's past the first second and everyone has closed their connection + * Then print stats. + */ + if (uv_now(loop) - start_time > 1000 && read_sockets == 0) { + read_show_stats(); + uv_close((uv_handle_t*)server, NULL); + } +} + + +static void start_stats_collection(void) { + int r; + + /* Show-stats timer */ + stats_left = STATS_COUNT; + r = uv_timer_init(loop, &timer_handle); + ASSERT(r == 0); + r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL); + ASSERT(r == 0); + + uv_update_time(loop); + start_time = uv_now(loop); +} + + +static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) { + if (nrecv_total == 0) { + ASSERT(start_time == 0); + uv_update_time(loop); + start_time = uv_now(loop); + } + + if (bytes < 0) { + uv_close((uv_handle_t*)stream, read_sockets_close_cb); + return; + } + + buf_free(buf); + + nrecv += bytes; + nrecv_total += bytes; +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + + req_free((uv_req_t*) req); + + nsent += sizeof write_buffer; + nsent_total += sizeof write_buffer; + + do_write((uv_stream_t*) req->handle); +} + + +static void do_write(uv_stream_t* stream) { + uv_write_t* req; + uv_buf_t buf; + int r; + + buf.base = (char*) &write_buffer; + buf.len = sizeof write_buffer; + + req = (uv_write_t*) req_alloc(); + r = uv_write(req, stream, &buf, 1, write_cb); + ASSERT(r == 0); +} + + +static void connect_cb(uv_connect_t* req, int status) { + int i; + + if (status) LOG(uv_strerror(status)); + ASSERT(status == 0); + + write_sockets++; + req_free((uv_req_t*) req); + + maybe_connect_some(); + + if (write_sockets == TARGET_CONNECTIONS) { + start_stats_collection(); + + /* Yay! start writing */ + for (i = 0; i < write_sockets; i++) { + if (type == TCP) + do_write((uv_stream_t*) &tcp_write_handles[i]); + else + do_write((uv_stream_t*) &pipe_write_handles[i]); + } + } +} + + +static void maybe_connect_some(void) { + uv_connect_t* req; + uv_tcp_t* tcp; + uv_pipe_t* pipe; + int r; + + while (max_connect_socket < TARGET_CONNECTIONS && + max_connect_socket < write_sockets + MAX_SIMULTANEOUS_CONNECTS) { + if (type == TCP) { + tcp = &tcp_write_handles[max_connect_socket++]; + + r = uv_tcp_init(loop, tcp); + ASSERT(r == 0); + + req = (uv_connect_t*) req_alloc(); + r = uv_tcp_connect(req, + tcp, + (const struct sockaddr*) &connect_addr, + connect_cb); + ASSERT(r == 0); + } else { + pipe = &pipe_write_handles[max_connect_socket++]; + + r = uv_pipe_init(loop, pipe, 0); + ASSERT(r == 0); + + req = (uv_connect_t*) req_alloc(); + uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb); + } + } +} + + +static void connection_cb(uv_stream_t* s, int status) { + uv_stream_t* stream; + int r; + + ASSERT(server == s); + ASSERT(status == 0); + + if (type == TCP) { + stream = (uv_stream_t*)malloc(sizeof(uv_tcp_t)); + r = uv_tcp_init(loop, (uv_tcp_t*)stream); + ASSERT(r == 0); + } else { + stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t)); + r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0); + ASSERT(r == 0); + } + + r = uv_accept(s, stream); + ASSERT(r == 0); + + r = uv_read_start(stream, buf_alloc, read_cb); + ASSERT(r == 0); + + read_sockets++; + max_read_sockets++; +} + + +/* + * Request allocator + */ + +typedef struct req_list_s { + union uv_any_req uv_req; + struct req_list_s* next; +} req_list_t; + + +static req_list_t* req_freelist = NULL; + + +static uv_req_t* req_alloc(void) { + req_list_t* req; + + req = req_freelist; + if (req != NULL) { + req_freelist = req->next; + return (uv_req_t*) req; + } + + req = (req_list_t*) malloc(sizeof *req); + return (uv_req_t*) req; +} + + +static void req_free(uv_req_t* uv_req) { + req_list_t* req = (req_list_t*) uv_req; + + req->next = req_freelist; + req_freelist = req; +} + + +/* + * Buffer allocator + */ + +typedef struct buf_list_s { + uv_buf_t uv_buf_t; + struct buf_list_s* next; +} buf_list_t; + + +static buf_list_t* buf_freelist = NULL; + + +static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf_list_t* ab; + + ab = buf_freelist; + if (ab != NULL) + buf_freelist = ab->next; + else { + ab = malloc(size + sizeof(*ab)); + ab->uv_buf_t.len = size; + ab->uv_buf_t.base = (char*) (ab + 1); + } + + *buf = ab->uv_buf_t; +} + + +static void buf_free(const uv_buf_t* buf) { + buf_list_t* ab = (buf_list_t*) buf->base - 1; + ab->next = buf_freelist; + buf_freelist = ab; +} + + +HELPER_IMPL(tcp_pump_server) { + int r; + + type = TCP; + loop = uv_default_loop(); + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr)); + + /* Server */ + server = (uv_stream_t*)&tcpServer; + r = uv_tcp_init(loop, &tcpServer); + ASSERT(r == 0); + r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + return 0; +} + + +HELPER_IMPL(pipe_pump_server) { + int r; + type = PIPE; + + loop = uv_default_loop(); + + /* Server */ + server = (uv_stream_t*)&pipeServer; + r = uv_pipe_init(loop, &pipeServer, 0); + ASSERT(r == 0); + r = uv_pipe_bind(&pipeServer, TEST_PIPENAME); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void tcp_pump(int n) { + ASSERT(n <= MAX_WRITE_HANDLES); + TARGET_CONNECTIONS = n; + type = TCP; + + loop = uv_default_loop(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr)); + + /* Start making connections */ + maybe_connect_some(); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); +} + + +static void pipe_pump(int n) { + ASSERT(n <= MAX_WRITE_HANDLES); + TARGET_CONNECTIONS = n; + type = PIPE; + + loop = uv_default_loop(); + + /* Start making connections */ + maybe_connect_some(); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); +} + + +BENCHMARK_IMPL(tcp_pump100_client) { + tcp_pump(100); + return 0; +} + + +BENCHMARK_IMPL(tcp_pump1_client) { + tcp_pump(1); + return 0; +} + + +BENCHMARK_IMPL(pipe_pump100_client) { + pipe_pump(100); + return 0; +} + + +BENCHMARK_IMPL(pipe_pump1_client) { + pipe_pump(1); + return 0; +} diff --git a/test/benchmark-sizes.c b/test/benchmark-sizes.c new file mode 100644 index 0000000000..8ccf10ee47 --- /dev/null +++ b/test/benchmark-sizes.c @@ -0,0 +1,45 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + + +BENCHMARK_IMPL(sizes) { + LOGF("uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t)); + LOGF("uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t)); + LOGF("uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t)); + LOGF("uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t)); + LOGF("uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t)); + LOGF("uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t)); + LOGF("uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t)); + LOGF("uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t)); + LOGF("uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t)); + LOGF("uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t)); + LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t)); + LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t)); + LOGF("uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t)); + LOGF("uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t)); + LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t)); + LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t)); + LOGF("uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t)); + return 0; +} diff --git a/test/benchmark-spawn.c b/test/benchmark-spawn.c new file mode 100644 index 0000000000..9cae41a83a --- /dev/null +++ b/test/benchmark-spawn.c @@ -0,0 +1,163 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* This benchmark spawns itself 1000 times. */ + +#include "task.h" +#include "uv.h" + +static uv_loop_t* loop; + +static int N = 1000; +static int done; + +static uv_process_t process; +static uv_process_options_t options; +static char exepath[1024]; +static size_t exepath_size = 1024; +static char* args[3]; +static uv_pipe_t out; + +#define OUTPUT_SIZE 1024 +static char output[OUTPUT_SIZE]; +static int output_used; + +static int process_open; +static int pipe_open; + + +static void spawn(void); + + +static void maybe_spawn(void) { + if (process_open == 0 && pipe_open == 0) { + done++; + if (done < N) { + spawn(); + } + } +} + + +static void process_close_cb(uv_handle_t* handle) { + ASSERT(process_open == 1); + process_open = 0; + maybe_spawn(); +} + + +static void exit_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + ASSERT(exit_status == 42); + ASSERT(term_signal == 0); + uv_close((uv_handle_t*)process, process_close_cb); +} + + +static void on_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = output + output_used; + buf->len = OUTPUT_SIZE - output_used; +} + + +static void pipe_close_cb(uv_handle_t* pipe) { + ASSERT(pipe_open == 1); + pipe_open = 0; + maybe_spawn(); +} + + +static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + ASSERT(pipe_open == 1); + output_used += nread; + } else if (nread < 0) { + if (nread == UV_EOF) { + uv_close((uv_handle_t*)pipe, pipe_close_cb); + } + } +} + + +static void spawn(void) { + uv_stdio_container_t stdio[2]; + int r; + + ASSERT(process_open == 0); + ASSERT(pipe_open == 0); + + args[0] = exepath; + args[1] = "spawn_helper"; + args[2] = NULL; + options.file = exepath; + options.args = args; + options.exit_cb = exit_cb; + + uv_pipe_init(loop, &out, 0); + + options.stdio = stdio; + options.stdio_count = 2; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + + r = uv_spawn(loop, &process, &options); + ASSERT(r == 0); + + process_open = 1; + pipe_open = 1; + output_used = 0; + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); +} + + +BENCHMARK_IMPL(spawn) { + int r; + static int64_t start_time, end_time; + + loop = uv_default_loop(); + + r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + exepath[exepath_size] = '\0'; + + uv_update_time(loop); + start_time = uv_now(loop); + + spawn(); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + uv_update_time(loop); + end_time = uv_now(loop); + + LOGF("spawn: %.0f spawns/s\n", + (double) N / (double) (end_time - start_time) * 1000.0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-tcp-write-batch.c b/test/benchmark-tcp-write-batch.c new file mode 100644 index 0000000000..96921b70db --- /dev/null +++ b/test/benchmark-tcp-write-batch.c @@ -0,0 +1,144 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +#define WRITE_REQ_DATA "Hello, world." +#define NUM_WRITE_REQS (1000 * 1000) + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req; + + +static write_req* write_reqs; +static uv_tcp_t tcp_client; +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; + +static int shutdown_cb_called = 0; +static int connect_cb_called = 0; +static int write_cb_called = 0; +static int close_cb_called = 0; + +static void connect_cb(uv_connect_t* req, int status); +static void write_cb(uv_write_t* req, int status); +static void shutdown_cb(uv_shutdown_t* req, int status); +static void close_cb(uv_handle_t* handle); + + +static void connect_cb(uv_connect_t* req, int status) { + write_req* w; + int i; + int r; + + ASSERT(req->handle == (uv_stream_t*)&tcp_client); + + for (i = 0; i < NUM_WRITE_REQS; i++) { + w = &write_reqs[i]; + r = uv_write(&w->req, req->handle, &w->buf, 1, write_cb); + ASSERT(r == 0); + } + + r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + ASSERT(r == 0); + + connect_cb_called++; +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + write_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req->handle == (uv_stream_t*)&tcp_client); + ASSERT(req->handle->write_queue_size == 0); + + uv_close((uv_handle_t*)req->handle, close_cb); + free(write_reqs); + + shutdown_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*)&tcp_client); + close_cb_called++; +} + + +BENCHMARK_IMPL(tcp_write_batch) { + struct sockaddr_in addr; + uv_loop_t* loop; + uint64_t start; + uint64_t stop; + int i; + int r; + + write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS); + ASSERT(write_reqs != NULL); + + /* Prepare the data to write out. */ + for (i = 0; i < NUM_WRITE_REQS; i++) { + write_reqs[i].buf = uv_buf_init(WRITE_REQ_DATA, + sizeof(WRITE_REQ_DATA) - 1); + } + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, &tcp_client); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + start = uv_hrtime(); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + stop = uv_hrtime(); + + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == NUM_WRITE_REQS); + ASSERT(shutdown_cb_called == 1); + ASSERT(close_cb_called == 1); + + printf("%ld write requests in %.2fs.\n", + (long)NUM_WRITE_REQS, + (stop - start) / 1e9); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/benchmark-thread.c b/test/benchmark-thread.c new file mode 100644 index 0000000000..b37a7fd6d0 --- /dev/null +++ b/test/benchmark-thread.c @@ -0,0 +1,64 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +#define NUM_THREADS (20 * 1000) + +static volatile int num_threads; + + +static void thread_entry(void* arg) { + ASSERT(arg == (void *) 42); + num_threads++; + /* FIXME write barrier? */ +} + + +BENCHMARK_IMPL(thread_create) { + uint64_t start_time; + double duration; + uv_thread_t tid; + int i, r; + + start_time = uv_hrtime(); + + for (i = 0; i < NUM_THREADS; i++) { + r = uv_thread_create(&tid, thread_entry, (void *) 42); + ASSERT(r == 0); + + r = uv_thread_join(&tid); + ASSERT(r == 0); + } + + duration = (uv_hrtime() - start_time) / 1e9; + + ASSERT(num_threads == NUM_THREADS); + + printf("%d threads created in %.2f seconds (%.0f/s)\n", + NUM_THREADS, duration, NUM_THREADS / duration); + + return 0; +} diff --git a/test/benchmark-udp-pummel.c b/test/benchmark-udp-pummel.c new file mode 100644 index 0000000000..d99250affc --- /dev/null +++ b/test/benchmark-udp-pummel.c @@ -0,0 +1,243 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +#include +#include +#include + +#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN" + +#define TEST_DURATION 5000 /* ms */ + +#define BASE_PORT 12345 + +struct sender_state { + struct sockaddr_in addr; + uv_udp_send_t send_req; + uv_udp_t udp_handle; +}; + +struct receiver_state { + struct sockaddr_in addr; + uv_udp_t udp_handle; +}; + +/* not used in timed mode */ +static unsigned int packet_counter = (unsigned int) 1e6; + +static int n_senders_; +static int n_receivers_; +static uv_buf_t bufs[5]; +static struct sender_state senders[1024]; +static struct receiver_state receivers[1024]; + +static unsigned int send_cb_called; +static unsigned int recv_cb_called; +static unsigned int close_cb_called; +static int timed; +static int exiting; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + struct sender_state* s; + + ASSERT(req != NULL); + + if (status != 0) { + ASSERT(status == UV_ECANCELED); + return; + } + + if (exiting) + return; + + s = container_of(req, struct sender_state, send_req); + ASSERT(req->handle == &s->udp_handle); + + if (timed) + goto send; + + if (packet_counter == 0) { + uv_close((uv_handle_t*)&s->udp_handle, NULL); + return; + } + + packet_counter--; + +send: + ASSERT(0 == uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + (const struct sockaddr*) &s->addr, + send_cb)); + send_cb_called++; +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + if (nread == 0) + return; + + if (nread < 0) { + ASSERT(nread == UV_ECANCELED); + return; + } + + ASSERT(addr->sa_family == AF_INET); + ASSERT(!memcmp(buf->base, EXPECTED, nread)); + + recv_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void timeout_cb(uv_timer_t* timer, int status) { + int i; + + exiting = 1; + + for (i = 0; i < n_senders_; i++) + uv_close((uv_handle_t*)&senders[i].udp_handle, close_cb); + + for (i = 0; i < n_receivers_; i++) + uv_close((uv_handle_t*)&receivers[i].udp_handle, close_cb); +} + + +static int pummel(unsigned int n_senders, + unsigned int n_receivers, + unsigned long timeout) { + uv_timer_t timer_handle; + uint64_t duration; + uv_loop_t* loop; + unsigned int i; + + ASSERT(n_senders <= ARRAY_SIZE(senders)); + ASSERT(n_receivers <= ARRAY_SIZE(receivers)); + + loop = uv_default_loop(); + + n_senders_ = n_senders; + n_receivers_ = n_receivers; + + if (timeout) { + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0)); + /* Timer should not keep loop alive. */ + uv_unref((uv_handle_t*)&timer_handle); + timed = 1; + } + + for (i = 0; i < n_receivers; i++) { + struct receiver_state* s = receivers + i; + struct sockaddr_in addr; + ASSERT(0 == uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr)); + ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); + ASSERT(0 == uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb)); + uv_unref((uv_handle_t*)&s->udp_handle); + } + + bufs[0] = uv_buf_init(EXPECTED + 0, 10); + bufs[1] = uv_buf_init(EXPECTED + 10, 10); + bufs[2] = uv_buf_init(EXPECTED + 20, 10); + bufs[3] = uv_buf_init(EXPECTED + 30, 10); + bufs[4] = uv_buf_init(EXPECTED + 40, 5); + + for (i = 0; i < n_senders; i++) { + struct sender_state* s = senders + i; + ASSERT(0 == uv_ip4_addr("127.0.0.1", + BASE_PORT + (i % n_receivers), + &s->addr)); + ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); + ASSERT(0 == uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + (const struct sockaddr*) &s->addr, + send_cb)); + } + + duration = uv_hrtime(); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + duration = uv_hrtime() - duration; + /* convert from nanoseconds to milliseconds */ + duration = duration / (uint64_t) 1e6; + + printf("udp_pummel_%dv%d: %.0f/s received, %.0f/s sent. " + "%u received, %u sent in %.1f seconds.\n", + n_receivers, + n_senders, + recv_cb_called / (duration / 1000.0), + send_cb_called / (duration / 1000.0), + recv_cb_called, + send_cb_called, + duration / 1000.0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#define X(a, b) \ + BENCHMARK_IMPL(udp_pummel_##a##v##b) { \ + return pummel(a, b, 0); \ + } \ + BENCHMARK_IMPL(udp_timed_pummel_##a##v##b) { \ + return pummel(a, b, TEST_DURATION); \ + } + +X(1, 1) +X(1, 10) +X(1, 100) +X(1, 1000) +X(10, 10) +X(10, 100) +X(10, 1000) +X(100, 10) +X(100, 100) +X(100, 1000) +X(1000, 1000) + +#undef X diff --git a/test/blackhole-server.c b/test/blackhole-server.c new file mode 100644 index 0000000000..ad878b35c6 --- /dev/null +++ b/test/blackhole-server.c @@ -0,0 +1,121 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +typedef struct { + uv_tcp_t handle; + uv_shutdown_t shutdown_req; +} conn_rec; + +static uv_tcp_t tcp_server; + +static void connection_cb(uv_stream_t* stream, int status); +static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); +static void shutdown_cb(uv_shutdown_t* req, int status); +static void close_cb(uv_handle_t* handle); + + +static void connection_cb(uv_stream_t* stream, int status) { + conn_rec* conn; + int r; + + ASSERT(status == 0); + ASSERT(stream == (uv_stream_t*)&tcp_server); + + conn = malloc(sizeof *conn); + ASSERT(conn != NULL); + + r = uv_tcp_init(stream->loop, &conn->handle); + ASSERT(r == 0); + + r = uv_accept(stream, (uv_stream_t*)&conn->handle); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&conn->handle, alloc_cb, read_cb); + ASSERT(r == 0); +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + conn_rec* conn; + int r; + + if (nread >= 0) + return; + + ASSERT(nread == UV_EOF); + + conn = container_of(stream, conn_rec, handle); + + r = uv_shutdown(&conn->shutdown_req, stream, shutdown_cb); + ASSERT(r == 0); +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + conn_rec* conn = container_of(req, conn_rec, shutdown_req); + uv_close((uv_handle_t*)&conn->handle, close_cb); +} + + +static void close_cb(uv_handle_t* handle) { + conn_rec* conn = container_of(handle, conn_rec, handle); + free(conn); +} + + +HELPER_IMPL(tcp4_blackhole_server) { + struct sockaddr_in addr; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, &tcp_server); + ASSERT(r == 0); + + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb); + ASSERT(r == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(0 && "Blackhole server dropped out of event loop."); + + return 0; +} diff --git a/test/dns-server.c b/test/dns-server.c new file mode 100644 index 0000000000..80052c7039 --- /dev/null +++ b/test/dns-server.c @@ -0,0 +1,340 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include + + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + + +/* used to track multiple DNS requests received */ +typedef struct { + char* prevbuf_ptr; + int prevbuf_pos; + int prevbuf_rem; +} dnsstate; + + +/* modify handle to append dnsstate */ +typedef struct { + uv_tcp_t handle; + dnsstate state; +} dnshandle; + + +static uv_loop_t* loop; + + +static uv_tcp_t server; + + +static void after_write(uv_write_t* req, int status); +static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf); +static void on_close(uv_handle_t* peer); +static void on_connection(uv_stream_t*, int status); + +#define WRITE_BUF_LEN (64*1024) +#define DNSREC_LEN (4) + +#define LEN_OFFSET 0 +#define QUERYID_OFFSET 2 + +static unsigned char DNSRsp[] = { + 0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0 +}; + +static unsigned char qrecord[] = { + 5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1 +}; + +static unsigned char arecord[] = { + 0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1 +}; + + +static void after_write(uv_write_t* req, int status) { + write_req_t* wr; + + if (status) { + fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); + ASSERT(0); + } + + wr = (write_req_t*) req; + + /* Free the read/write buffer and the request */ + free(wr->buf.base); + free(wr); +} + + +static void after_shutdown(uv_shutdown_t* req, int status) { + uv_close((uv_handle_t*) req->handle, on_close); + free(req); +} + + +static void addrsp(write_req_t* wr, char* hdr) { + char * dnsrsp; + short int rsplen; + short int* reclen; + + rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord); + + ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN); + + dnsrsp = wr->buf.base + wr->buf.len; + + /* copy stock response */ + memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp)); + memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord)); + memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord)); + + /* overwrite with network order length and id from request header */ + reclen = (short int*)dnsrsp; + *reclen = htons(rsplen-2); + dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET]; + dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1]; + + wr->buf.len += rsplen; +} + +static void process_req(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + write_req_t* wr; + dnshandle* dns = (dnshandle*)handle; + char hdrbuf[DNSREC_LEN]; + int hdrbuf_remaining = DNSREC_LEN; + int rec_remaining = 0; + int readbuf_remaining; + char* dnsreq; + char* hdrstart; + int usingprev = 0; + + wr = (write_req_t*) malloc(sizeof *wr); + wr->buf.base = (char*)malloc(WRITE_BUF_LEN); + wr->buf.len = 0; + + if (dns->state.prevbuf_ptr != NULL) { + dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos; + readbuf_remaining = dns->state.prevbuf_rem; + usingprev = 1; + } else { + dnsreq = buf->base; + readbuf_remaining = nread; + } + hdrstart = dnsreq; + + while (dnsreq != NULL) { + /* something to process */ + while (readbuf_remaining > 0) { + /* something to process in current buffer */ + if (hdrbuf_remaining > 0) { + /* process len and id */ + if (readbuf_remaining < hdrbuf_remaining) { + /* too little to get request header. save for next buffer */ + memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], + dnsreq, + readbuf_remaining); + hdrbuf_remaining = DNSREC_LEN - readbuf_remaining; + break; + } else { + /* save header */ + memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], + dnsreq, + hdrbuf_remaining); + dnsreq += hdrbuf_remaining; + readbuf_remaining -= hdrbuf_remaining; + hdrbuf_remaining = 0; + + /* get record length */ + rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1]; + rec_remaining -= (DNSREC_LEN - 2); + } + } + + if (rec_remaining <= readbuf_remaining) { + /* prepare reply */ + addrsp(wr, hdrbuf); + + /* move to next record */ + dnsreq += rec_remaining; + hdrstart = dnsreq; + readbuf_remaining -= rec_remaining; + rec_remaining = 0; + hdrbuf_remaining = DNSREC_LEN; + } else { + /* otherwise this buffer is done. */ + rec_remaining -= readbuf_remaining; + break; + } + } + + /* If we had to use bytes from prev buffer, start processing the current + * one. + */ + if (usingprev == 1) { + /* free previous buffer */ + free(dns->state.prevbuf_ptr); + dnsreq = buf->base; + readbuf_remaining = nread; + usingprev = 0; + } else { + dnsreq = NULL; + } + } + + /* send write buffer */ + if (wr->buf.len > 0) { + if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) { + FATAL("uv_write failed"); + } + } + + if (readbuf_remaining > 0) { + /* save start of record position, so we can continue on next read */ + dns->state.prevbuf_ptr = buf->base; + dns->state.prevbuf_pos = hdrstart - buf->base; + dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos; + } else { + /* nothing left in this buffer */ + dns->state.prevbuf_ptr = NULL; + dns->state.prevbuf_pos = 0; + dns->state.prevbuf_rem = 0; + free(buf->base); + } +} + +static void after_read(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + uv_shutdown_t* req; + + if (nread < 0) { + /* Error or EOF */ + ASSERT(nread == UV_EOF); + + if (buf->base) { + free(buf->base); + } + + req = malloc(sizeof *req); + uv_shutdown(req, handle, after_shutdown); + + return; + } + + if (nread == 0) { + /* Everything OK, but nothing read. */ + free(buf->base); + return; + } + /* process requests and send responses */ + process_req(handle, nread, buf); +} + + +static void on_close(uv_handle_t* peer) { + free(peer); +} + + +static void buf_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +static void on_connection(uv_stream_t* server, int status) { + dnshandle* handle; + int r; + + ASSERT(status == 0); + + handle = (dnshandle*) malloc(sizeof *handle); + ASSERT(handle != NULL); + + /* initialize read buffer state */ + handle->state.prevbuf_ptr = 0; + handle->state.prevbuf_pos = 0; + handle->state.prevbuf_rem = 0; + + r = uv_tcp_init(loop, (uv_tcp_t*)handle); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)handle); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read); + ASSERT(r == 0); +} + + +static int dns_start(int port) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr)); + + r = uv_tcp_init(loop, &server); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Bind error\n"); + return 1; + } + + r = uv_listen((uv_stream_t*)&server, 128, on_connection); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Listen error\n"); + return 1; + } + + return 0; +} + + +HELPER_IMPL(dns_server) { + loop = uv_default_loop(); + + if (dns_start(TEST_PORT_2)) + return 1; + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/test/echo-server.c b/test/echo-server.c new file mode 100644 index 0000000000..e5201b9f4c --- /dev/null +++ b/test/echo-server.c @@ -0,0 +1,384 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +static uv_loop_t* loop; + +static int server_closed; +static stream_type serverType; +static uv_tcp_t tcpServer; +static uv_udp_t udpServer; +static uv_pipe_t pipeServer; +static uv_handle_t* server; + +static void after_write(uv_write_t* req, int status); +static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf); +static void on_close(uv_handle_t* peer); +static void on_server_close(uv_handle_t* handle); +static void on_connection(uv_stream_t*, int status); + + +static void after_write(uv_write_t* req, int status) { + write_req_t* wr; + + /* Free the read/write buffer and the request */ + wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); + + if (status == 0) + return; + + fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); + + if (status == UV_ECANCELED) + return; + + ASSERT(status == UV_EPIPE); + uv_close((uv_handle_t*)req->handle, on_close); +} + + +static void after_shutdown(uv_shutdown_t* req, int status) { + uv_close((uv_handle_t*)req->handle, on_close); + free(req); +} + + +static void after_read(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + int i; + write_req_t *wr; + uv_shutdown_t* req; + + if (nread < 0) { + /* Error or EOF */ + ASSERT(nread == UV_EOF); + + if (buf->base) { + free(buf->base); + } + + req = (uv_shutdown_t*) malloc(sizeof *req); + uv_shutdown(req, handle, after_shutdown); + + return; + } + + if (nread == 0) { + /* Everything OK, but nothing read. */ + free(buf->base); + return; + } + + /* + * Scan for the letter Q which signals that we should quit the server. + * If we get QS it means close the stream. + */ + if (!server_closed) { + for (i = 0; i < nread; i++) { + if (buf->base[i] == 'Q') { + if (i + 1 < nread && buf->base[i + 1] == 'S') { + free(buf->base); + uv_close((uv_handle_t*)handle, on_close); + return; + } else { + uv_close(server, on_server_close); + server_closed = 1; + } + } + } + } + + wr = (write_req_t*) malloc(sizeof *wr); + + wr->buf = uv_buf_init(buf->base, nread); + if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { + FATAL("uv_write failed"); + } +} + + +static void on_close(uv_handle_t* peer) { + free(peer); +} + + +static void echo_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +static void on_connection(uv_stream_t* server, int status) { + uv_stream_t* stream; + int r; + + if (status != 0) { + fprintf(stderr, "Connect error %s\n", uv_err_name(status)); + } + ASSERT(status == 0); + + switch (serverType) { + case TCP: + stream = malloc(sizeof(uv_tcp_t)); + ASSERT(stream != NULL); + r = uv_tcp_init(loop, (uv_tcp_t*)stream); + ASSERT(r == 0); + break; + + case PIPE: + stream = malloc(sizeof(uv_pipe_t)); + ASSERT(stream != NULL); + r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0); + ASSERT(r == 0); + break; + + default: + ASSERT(0 && "Bad serverType"); + abort(); + } + + /* associate server with stream */ + stream->data = server; + + r = uv_accept(server, stream); + ASSERT(r == 0); + + r = uv_read_start(stream, echo_alloc, after_read); + ASSERT(r == 0); +} + + +static void on_server_close(uv_handle_t* handle) { + ASSERT(handle == server); +} + + +static void on_send(uv_udp_send_t* req, int status); + + +static void on_recv(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + uv_udp_send_t* req; + uv_buf_t sndbuf; + + ASSERT(nread > 0); + ASSERT(addr->sa_family == AF_INET); + + req = malloc(sizeof(*req)); + ASSERT(req != NULL); + + sndbuf = *rcvbuf; + ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); +} + + +static void on_send(uv_udp_send_t* req, int status) { + ASSERT(status == 0); + free(req); +} + + +static int tcp4_echo_start(int port) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr)); + + server = (uv_handle_t*)&tcpServer; + serverType = TCP; + + r = uv_tcp_init(loop, &tcpServer); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Bind error\n"); + return 1; + } + + r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 1; + } + + return 0; +} + + +static int tcp6_echo_start(int port) { + struct sockaddr_in6 addr6; + int r; + + ASSERT(0 == uv_ip6_addr("::1", port, &addr6)); + + server = (uv_handle_t*)&tcpServer; + serverType = TCP; + + r = uv_tcp_init(loop, &tcpServer); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + /* IPv6 is optional as not all platforms support it */ + r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0); + if (r) { + /* show message but return OK */ + fprintf(stderr, "IPv6 not supported\n"); + return 0; + } + + r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection); + if (r) { + /* TODO: Error codes */ + fprintf(stderr, "Listen error\n"); + return 1; + } + + return 0; +} + + +static int udp4_echo_start(int port) { + int r; + + server = (uv_handle_t*)&udpServer; + serverType = UDP; + + r = uv_udp_init(loop, &udpServer); + if (r) { + fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r)); + return 1; + } + + r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv); + if (r) { + fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r)); + return 1; + } + + return 0; +} + + +static int pipe_echo_start(char* pipeName) { + int r; + +#ifndef _WIN32 + { + uv_fs_t req; + uv_fs_unlink(uv_default_loop(), &req, pipeName, NULL); + uv_fs_req_cleanup(&req); + } +#endif + + server = (uv_handle_t*)&pipeServer; + serverType = PIPE; + + r = uv_pipe_init(loop, &pipeServer, 0); + if (r) { + fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r)); + return 1; + } + + r = uv_pipe_bind(&pipeServer, pipeName); + if (r) { + fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r)); + return 1; + } + + r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection); + if (r) { + fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r)); + return 1; + } + + return 0; +} + + +HELPER_IMPL(tcp4_echo_server) { + loop = uv_default_loop(); + + if (tcp4_echo_start(TEST_PORT)) + return 1; + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} + + +HELPER_IMPL(tcp6_echo_server) { + loop = uv_default_loop(); + + if (tcp6_echo_start(TEST_PORT)) + return 1; + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} + + +HELPER_IMPL(pipe_echo_server) { + loop = uv_default_loop(); + + if (pipe_echo_start(TEST_PIPENAME)) + return 1; + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} + + +HELPER_IMPL(udp4_echo_server) { + loop = uv_default_loop(); + + if (udp4_echo_start(TEST_PORT)) + return 1; + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/test/fixtures/empty_file b/test/fixtures/empty_file new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/fixtures/load_error.node b/test/fixtures/load_error.node new file mode 100644 index 0000000000..323fae03f4 --- /dev/null +++ b/test/fixtures/load_error.node @@ -0,0 +1 @@ +foobar diff --git a/test/run-benchmarks.c b/test/run-benchmarks.c new file mode 100644 index 0000000000..06732b71d3 --- /dev/null +++ b/test/run-benchmarks.c @@ -0,0 +1,64 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "runner.h" +#include "task.h" + +/* Actual benchmarks and helpers are defined in benchmark-list.h */ +#include "benchmark-list.h" + + +/* The time in milliseconds after which a single benchmark times out. */ +#define BENCHMARK_TIMEOUT 60000 + +static int maybe_run_test(int argc, char **argv); + + +int main(int argc, char **argv) { + platform_init(argc, argv); + + switch (argc) { + case 1: return run_tests(BENCHMARK_TIMEOUT, 1); + case 2: return maybe_run_test(argc, argv); + case 3: return run_test_part(argv[1], argv[2]); + default: + LOGF("Too many arguments.\n"); + return 1; + } +} + + +static int maybe_run_test(int argc, char **argv) { + if (strcmp(argv[1], "--list") == 0) { + print_tests(stdout); + return 0; + } + + if (strcmp(argv[1], "spawn_helper") == 0) { + printf("hello world\n"); + return 42; + } + + return run_test(argv[1], BENCHMARK_TIMEOUT, 1, 1); +} diff --git a/test/run-tests.c b/test/run-tests.c new file mode 100644 index 0000000000..d84be6a1a5 --- /dev/null +++ b/test/run-tests.c @@ -0,0 +1,159 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include + +#ifdef _WIN32 +# include +#else +# include +#endif + +#include "uv.h" +#include "runner.h" +#include "task.h" + +/* Actual tests and helpers are defined in test-list.h */ +#include "test-list.h" + +/* The time in milliseconds after which a single test times out. */ +#define TEST_TIMEOUT 5000 + +int ipc_helper(int listen_after_write); +int ipc_helper_tcp_connection(void); +int ipc_send_recv_helper(void); +int stdio_over_pipes_helper(void); + +static int maybe_run_test(int argc, char **argv); + + +int main(int argc, char **argv) { + platform_init(argc, argv); + + argv = uv_setup_args(argc, argv); + + switch (argc) { + case 1: return run_tests(TEST_TIMEOUT, 0); + case 2: return maybe_run_test(argc, argv); + case 3: return run_test_part(argv[1], argv[2]); + default: + LOGF("Too many arguments.\n"); + return 1; + } +} + + +static int maybe_run_test(int argc, char **argv) { + if (strcmp(argv[1], "--list") == 0) { + print_tests(stdout); + return 0; + } + + if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) { + return ipc_helper(0); + } + + if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) { + return ipc_helper(1); + } + + if (strcmp(argv[1], "ipc_send_recv_helper") == 0) { + return ipc_send_recv_helper(); + } + + if (strcmp(argv[1], "ipc_helper_tcp_connection") == 0) { + return ipc_helper_tcp_connection(); + } + + if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { + return stdio_over_pipes_helper(); + } + + if (strcmp(argv[1], "spawn_helper1") == 0) { + return 1; + } + + if (strcmp(argv[1], "spawn_helper2") == 0) { + printf("hello world\n"); + return 1; + } + + if (strcmp(argv[1], "spawn_helper3") == 0) { + char buffer[256]; + ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin)); + buffer[sizeof(buffer) - 1] = '\0'; + fputs(buffer, stdout); + return 1; + } + + if (strcmp(argv[1], "spawn_helper4") == 0) { + /* Never surrender, never return! */ + while (1) uv_sleep(10000); + } + + if (strcmp(argv[1], "spawn_helper5") == 0) { + const char out[] = "fourth stdio!\n"; +#ifdef _WIN32 + DWORD bytes; + WriteFile((HANDLE) _get_osfhandle(3), out, sizeof(out) - 1, &bytes, NULL); +#else + { + ssize_t r; + + do + r = write(3, out, sizeof(out) - 1); + while (r == -1 && errno == EINTR); + + fsync(3); + } +#endif + return 1; + } + + if (strcmp(argv[1], "spawn_helper6") == 0) { + int r; + + r = fprintf(stdout, "hello world\n"); + ASSERT(r > 0); + + r = fprintf(stderr, "hello errworld\n"); + ASSERT(r > 0); + + return 1; + } + + if (strcmp(argv[1], "spawn_helper7") == 0) { + int r; + char *test; + /* Test if the test value from the parent is still set */ + test = getenv("ENV_TEST"); + ASSERT(test != NULL); + + r = fprintf(stdout, "%s", test); + ASSERT(r > 0); + + return 1; + } + + return run_test(argv[1], TEST_TIMEOUT, 0, 1); +} diff --git a/test/runner-unix.c b/test/runner-unix.c new file mode 100644 index 0000000000..9afcd1e488 --- /dev/null +++ b/test/runner-unix.c @@ -0,0 +1,356 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "runner-unix.h" +#include "runner.h" + +#include /* uintptr_t */ + +#include +#include /* usleep */ +#include /* strdup */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* Do platform-specific initialization. */ +void platform_init(int argc, char **argv) { + const char* tap; + + tap = getenv("UV_TAP_OUTPUT"); + tap_output = (tap != NULL && atoi(tap) > 0); + + /* Disable stdio output buffering. */ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + strncpy(executable_path, argv[0], sizeof(executable_path) - 1); + signal(SIGPIPE, SIG_IGN); +} + + +/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */ +/* Make sure that all stdio output of the processes is buffered up. */ +int process_start(char* name, char* part, process_info_t* p, int is_helper) { + FILE* stdout_file; + const char* arg; + char* args[16]; + int n; + + stdout_file = tmpfile(); + if (!stdout_file) { + perror("tmpfile"); + return -1; + } + + p->terminated = 0; + p->status = 0; + + pid_t pid = fork(); + + if (pid < 0) { + perror("fork"); + return -1; + } + + if (pid == 0) { + /* child */ + arg = getenv("UV_USE_VALGRIND"); + n = 0; + + /* Disable valgrind for helpers, it complains about helpers leaking memory. + * They're killed after the test and as such never get a chance to clean up. + */ + if (is_helper == 0 && arg != NULL && atoi(arg) != 0) { + args[n++] = "valgrind"; + args[n++] = "--quiet"; + args[n++] = "--leak-check=full"; + args[n++] = "--show-reachable=yes"; + args[n++] = "--error-exitcode=125"; + } + + args[n++] = executable_path; + args[n++] = name; + args[n++] = part; + args[n++] = NULL; + + dup2(fileno(stdout_file), STDOUT_FILENO); + dup2(fileno(stdout_file), STDERR_FILENO); + execvp(args[0], args); + perror("execvp()"); + _exit(127); + } + + /* parent */ + p->pid = pid; + p->name = strdup(name); + p->stdout_file = stdout_file; + + return 0; +} + + +typedef struct { + int pipe[2]; + process_info_t* vec; + int n; +} dowait_args; + + +/* This function is run inside a pthread. We do this so that we can possibly + * timeout. + */ +static void* dowait(void* data) { + dowait_args* args = data; + + int i, r; + process_info_t* p; + + for (i = 0; i < args->n; i++) { + p = (process_info_t*)(args->vec + i * sizeof(process_info_t)); + if (p->terminated) continue; + r = waitpid(p->pid, &p->status, 0); + if (r < 0) { + perror("waitpid"); + return NULL; + } + p->terminated = 1; + } + + if (args->pipe[1] >= 0) { + /* Write a character to the main thread to notify it about this. */ + ssize_t r; + + do + r = write(args->pipe[1], "", 1); + while (r == -1 && errno == EINTR); + } + + return NULL; +} + + +/* Wait for all `n` processes in `vec` to terminate. */ +/* Time out after `timeout` msec, or never if timeout == -1 */ +/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ +int process_wait(process_info_t* vec, int n, int timeout) { + int i; + process_info_t* p; + dowait_args args; + args.vec = vec; + args.n = n; + args.pipe[0] = -1; + args.pipe[1] = -1; + + /* The simple case is where there is no timeout */ + if (timeout == -1) { + dowait(&args); + return 0; + } + + /* Hard case. Do the wait with a timeout. + * + * Assumption: we are the only ones making this call right now. Otherwise + * we'd need to lock vec. + */ + + pthread_t tid; + int retval; + + int r = pipe((int*)&(args.pipe)); + if (r) { + perror("pipe()"); + return -1; + } + + r = pthread_create(&tid, NULL, dowait, &args); + if (r) { + perror("pthread_create()"); + retval = -1; + goto terminate; + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = 0; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(args.pipe[0], &fds); + + r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv); + + if (r == -1) { + perror("select()"); + retval = -1; + + } else if (r) { + /* The thread completed successfully. */ + retval = 0; + + } else { + /* Timeout. Kill all the children. */ + for (i = 0; i < n; i++) { + p = (process_info_t*)(vec + i * sizeof(process_info_t)); + kill(p->pid, SIGTERM); + } + retval = -2; + + /* Wait for thread to finish. */ + r = pthread_join(tid, NULL); + if (r) { + perror("pthread_join"); + retval = -1; + } + } + +terminate: + close(args.pipe[0]); + close(args.pipe[1]); + return retval; +} + + +/* Returns the number of bytes in the stdio output buffer for process `p`. */ +long int process_output_size(process_info_t *p) { + /* Size of the p->stdout_file */ + struct stat buf; + + int r = fstat(fileno(p->stdout_file), &buf); + if (r < 0) { + return -1; + } + + return (long)buf.st_size; +} + + +/* Copy the contents of the stdio output buffer to `fd`. */ +int process_copy_output(process_info_t *p, int fd) { + int r = fseek(p->stdout_file, 0, SEEK_SET); + if (r < 0) { + perror("fseek"); + return -1; + } + + ssize_t nwritten; + char buf[1024]; + + /* TODO: what if the line is longer than buf */ + while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) { + /* TODO: what if write doesn't write the whole buffer... */ + nwritten = 0; + + if (tap_output) + nwritten += write(fd, "#", 1); + + nwritten += write(fd, buf, strlen(buf)); + + if (nwritten < 0) { + perror("write"); + return -1; + } + } + + if (ferror(p->stdout_file)) { + perror("read"); + return -1; + } + + return 0; +} + + +/* Copy the last line of the stdio output buffer to `buffer` */ +int process_read_last_line(process_info_t *p, + char* buffer, + size_t buffer_len) { + char* ptr; + + int r = fseek(p->stdout_file, 0, SEEK_SET); + if (r < 0) { + perror("fseek"); + return -1; + } + + buffer[0] = '\0'; + + while (fgets(buffer, buffer_len, p->stdout_file) != NULL) { + for (ptr = buffer; *ptr && *ptr != '\r' && *ptr != '\n'; ptr++); + *ptr = '\0'; + } + + if (ferror(p->stdout_file)) { + perror("read"); + buffer[0] = '\0'; + return -1; + } + return 0; +} + + +/* Return the name that was specified when `p` was started by process_start */ +char* process_get_name(process_info_t *p) { + return p->name; +} + + +/* Terminate process `p`. */ +int process_terminate(process_info_t *p) { + return kill(p->pid, SIGTERM); +} + + +/* Return the exit code of process p. */ +/* On error, return -1. */ +int process_reap(process_info_t *p) { + if (WIFEXITED(p->status)) { + return WEXITSTATUS(p->status); + } else { + return p->status; /* ? */ + } +} + + +/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */ +void process_cleanup(process_info_t *p) { + fclose(p->stdout_file); + free(p->name); +} + + +/* Move the console cursor one line up and back to the first column. */ +void rewind_cursor(void) { + fprintf(stderr, "\033[2K\r"); +} + + +/* Pause the calling thread for a number of milliseconds. */ +void uv_sleep(int msec) { + usleep(msec * 1000); +} diff --git a/test/runner-unix.h b/test/runner-unix.h new file mode 100644 index 0000000000..e21847f92c --- /dev/null +++ b/test/runner-unix.h @@ -0,0 +1,36 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef TEST_RUNNER_UNIX_H +#define TEST_RUNNER_UNIX_H + +#include +#include /* FILE */ + +typedef struct { + FILE* stdout_file; + pid_t pid; + char* name; + int status; + int terminated; +} process_info_t; + +#endif /* TEST_RUNNER_UNIX_H */ diff --git a/test/runner-win.c b/test/runner-win.c new file mode 100644 index 0000000000..83d76783f6 --- /dev/null +++ b/test/runner-win.c @@ -0,0 +1,369 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#if !defined(__MINGW32__) +# include +#endif + + +#include "task.h" +#include "runner.h" + + +/* + * Define the stuff that MinGW doesn't have + */ +#ifndef GetFileSizeEx + WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, + PLARGE_INTEGER lpFileSize); +#endif + + +/* Do platform-specific initialization. */ +void platform_init(int argc, char **argv) { + const char* tap; + + tap = getenv("UV_TAP_OUTPUT"); + tap_output = (tap != NULL && atoi(tap) > 0); + + /* Disable the "application crashed" popup. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); +#if !defined(__MINGW32__) + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif + + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); + + /* Disable stdio output buffering. */ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + strcpy(executable_path, argv[0]); +} + + +int process_start(char *name, char *part, process_info_t *p, int is_helper) { + HANDLE file = INVALID_HANDLE_VALUE; + HANDLE nul = INVALID_HANDLE_VALUE; + WCHAR path[MAX_PATH], filename[MAX_PATH]; + WCHAR image[MAX_PATH + 1]; + WCHAR args[MAX_PATH * 2]; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + DWORD result; + + if (GetTempPathW(sizeof(path) / sizeof(WCHAR), (WCHAR*)&path) == 0) + goto error; + if (GetTempFileNameW((WCHAR*)&path, L"uv", 0, (WCHAR*)&filename) == 0) + goto error; + + file = CreateFileW((WCHAR*)filename, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (file == INVALID_HANDLE_VALUE) + goto error; + + if (!SetHandleInformation(file, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) + goto error; + + nul = CreateFileA("nul", + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (nul == INVALID_HANDLE_VALUE) + goto error; + + if (!SetHandleInformation(nul, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) + goto error; + + result = GetModuleFileNameW(NULL, + (WCHAR*) &image, + sizeof(image) / sizeof(WCHAR)); + if (result == 0 || result == sizeof(image)) + goto error; + + if (part) { + if (_snwprintf((WCHAR*)args, + sizeof(args) / sizeof(WCHAR), + L"\"%s\" %S %S", + image, + name, + part) < 0) { + goto error; + } + } else { + if (_snwprintf((WCHAR*)args, + sizeof(args) / sizeof(WCHAR), + L"\"%s\" %S", + image, + name) < 0) { + goto error; + } + } + + memset((void*)&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = nul; + si.hStdOutput = file; + si.hStdError = file; + + if (!CreateProcessW(image, args, NULL, NULL, TRUE, + 0, NULL, NULL, &si, &pi)) + goto error; + + CloseHandle(pi.hThread); + + SetHandleInformation(nul, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(file, HANDLE_FLAG_INHERIT, 0); + + p->stdio_in = nul; + p->stdio_out = file; + p->process = pi.hProcess; + p->name = part; + + return 0; + +error: + if (file != INVALID_HANDLE_VALUE) + CloseHandle(file); + if (nul != INVALID_HANDLE_VALUE) + CloseHandle(nul); + + return -1; +} + + +/* Timeout is is msecs. Set timeout < 0 to never time out. */ +/* Returns 0 when all processes are terminated, -2 on timeout. */ +int process_wait(process_info_t *vec, int n, int timeout) { + int i; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + DWORD timeout_api, result; + + /* If there's nothing to wait for, return immediately. */ + if (n == 0) + return 0; + + ASSERT(n <= MAXIMUM_WAIT_OBJECTS); + + for (i = 0; i < n; i++) + handles[i] = vec[i].process; + + if (timeout >= 0) { + timeout_api = (DWORD)timeout; + } else { + timeout_api = INFINITE; + } + + result = WaitForMultipleObjects(n, handles, TRUE, timeout_api); + + if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n) { + /* All processes are terminated. */ + return 0; + } + if (result == WAIT_TIMEOUT) { + return -2; + } + return -1; +} + + +long int process_output_size(process_info_t *p) { + LARGE_INTEGER size; + if (!GetFileSizeEx(p->stdio_out, &size)) + return -1; + return (long int)size.QuadPart; +} + + +int process_copy_output(process_info_t *p, int fd) { + DWORD read; + char buf[1024]; + char *line, *start; + + if (SetFilePointer(p->stdio_out, + 0, + 0, + FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + return -1; + } + + if (tap_output) + write(fd, "#", 1); + + while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) && + read > 0) { + if (tap_output) { + start = buf; + + while ((line = strchr(start, '\n')) != NULL) { + write(fd, start, line - start + 1); + write(fd, "#", 1); + start = line + 1; + } + + if (start < buf + read) + write(fd, start, buf + read - start); + } else { + write(fd, buf, read); + } + } + + if (tap_output) + write(fd, "\n", 1); + + if (GetLastError() != ERROR_HANDLE_EOF) + return -1; + + return 0; +} + + +int process_read_last_line(process_info_t *p, + char * buffer, + size_t buffer_len) { + DWORD size; + DWORD read; + DWORD start; + OVERLAPPED overlapped; + + ASSERT(buffer_len > 0); + + size = GetFileSize(p->stdio_out, NULL); + if (size == INVALID_FILE_SIZE) + return -1; + + if (size == 0) { + buffer[0] = '\0'; + return 1; + } + + memset(&overlapped, 0, sizeof overlapped); + if (size >= buffer_len) + overlapped.Offset = size - buffer_len - 1; + + if (!ReadFile(p->stdio_out, buffer, buffer_len - 1, &read, &overlapped)) + return -1; + + for (start = read - 1; start >= 0; start--) { + if (buffer[start] == '\n' || buffer[start] == '\r') + break; + } + + if (start > 0) + memmove(buffer, buffer + start, read - start); + + buffer[read - start] = '\0'; + + return 0; +} + + +char* process_get_name(process_info_t *p) { + return p->name; +} + + +int process_terminate(process_info_t *p) { + if (!TerminateProcess(p->process, 1)) + return -1; + return 0; +} + + +int process_reap(process_info_t *p) { + DWORD exitCode; + if (!GetExitCodeProcess(p->process, &exitCode)) + return -1; + return (int)exitCode; +} + + +void process_cleanup(process_info_t *p) { + CloseHandle(p->process); + CloseHandle(p->stdio_in); + CloseHandle(p->stdio_out); +} + + +static int clear_line() { + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO info; + COORD coord; + DWORD written; + + handle = (HANDLE)_get_osfhandle(fileno(stderr)); + if (handle == INVALID_HANDLE_VALUE) + return -1; + + if (!GetConsoleScreenBufferInfo(handle, &info)) + return -1; + + coord = info.dwCursorPosition; + if (coord.Y <= 0) + return -1; + + coord.X = 0; + + if (!SetConsoleCursorPosition(handle, coord)) + return -1; + + if (!FillConsoleOutputCharacterW(handle, + 0x20, + info.dwSize.X, + coord, + &written)) { + return -1; + } + + return 0; +} + + +void rewind_cursor() { + if (clear_line() == -1) { + /* If clear_line fails (stdout is not a console), print a newline. */ + fprintf(stderr, "\n"); + } +} + + +/* Pause the calling thread for a number of milliseconds. */ +void uv_sleep(int msec) { + Sleep(msec); +} diff --git a/test/runner-win.h b/test/runner-win.h new file mode 100644 index 0000000000..c94b89bd5e --- /dev/null +++ b/test/runner-win.h @@ -0,0 +1,43 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Don't complain about _snprintf being insecure. */ +#define _CRT_SECURE_NO_WARNINGS + +/* Don't complain about write(), fileno() etc. being deprecated. */ +#pragma warning(disable : 4996) + + +#include +#include +#include + + +/* Windows has no snprintf, only _snprintf. */ +#define snprintf _snprintf + + +typedef struct { + HANDLE process; + HANDLE stdio_in; + HANDLE stdio_out; + char *name; +} process_info_t; diff --git a/test/runner.c b/test/runner.c new file mode 100644 index 0000000000..f4d982c5b6 --- /dev/null +++ b/test/runner.c @@ -0,0 +1,455 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "runner.h" +#include "task.h" +#include "uv.h" + +char executable_path[PATHMAX] = { '\0' }; + +int tap_output = 0; + + +static void log_progress(int total, + int passed, + int failed, + int todos, + int skipped, + const char* name) { + int progress; + + if (total == 0) + total = 1; + + progress = 100 * (passed + failed + skipped + todos) / total; + LOGF("[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s", + progress, + passed, + failed, + todos, + skipped, + name); +} + + +const char* fmt(double d) { + static char buf[1024]; + static char* p; + uint64_t v; + + if (p == NULL) + p = buf; + + p += 31; + + if (p >= buf + sizeof(buf)) + return ""; + + v = (uint64_t) d; + +#if 0 /* works but we don't care about fractional precision */ + if (d - v >= 0.01) { + *--p = '0' + (uint64_t) (d * 100) % 10; + *--p = '0' + (uint64_t) (d * 10) % 10; + *--p = '.'; + } +#endif + + if (v == 0) + *--p = '0'; + + while (v) { + if (v) *--p = '0' + (v % 10), v /= 10; + if (v) *--p = '0' + (v % 10), v /= 10; + if (v) *--p = '0' + (v % 10), v /= 10; + if (v) *--p = ','; + } + + return p; +} + + +int run_tests(int timeout, int benchmark_output) { + int total; + int passed; + int failed; + int todos; + int skipped; + int current; + int test_result; + task_entry_t* task; + + /* Count the number of tests. */ + total = 0; + for (task = TASKS; task->main; task++) { + if (!task->is_helper) { + total++; + } + } + + if (tap_output) { + LOGF("1..%d\n", total); + } + + /* Run all tests. */ + passed = 0; + failed = 0; + todos = 0; + skipped = 0; + current = 1; + for (task = TASKS; task->main; task++) { + if (task->is_helper) { + continue; + } + + if (!tap_output) + rewind_cursor(); + + if (!benchmark_output && !tap_output) { + log_progress(total, passed, failed, todos, skipped, task->task_name); + } + + test_result = run_test(task->task_name, timeout, benchmark_output, current); + switch (test_result) { + case TEST_OK: passed++; break; + case TEST_TODO: todos++; break; + case TEST_SKIP: skipped++; break; + default: failed++; + } + current++; + } + + if (!tap_output) + rewind_cursor(); + + if (!benchmark_output && !tap_output) { + log_progress(total, passed, failed, todos, skipped, "Done.\n"); + } + + return failed; +} + + +void log_tap_result(int test_count, + const char* test, + int status, + process_info_t* process) { + const char* result; + const char* directive; + char reason[1024]; + + switch (status) { + case TEST_OK: + result = "ok"; + directive = ""; + break; + case TEST_TODO: + result = "not ok"; + directive = " # TODO "; + break; + case TEST_SKIP: + result = "ok"; + directive = " # SKIP "; + break; + default: + result = "not ok"; + directive = ""; + } + + if ((status == TEST_SKIP || status == TEST_TODO) && + process_output_size(process) > 0) { + process_read_last_line(process, reason, sizeof reason); + } else { + reason[0] = '\0'; + } + + LOGF("%s %d - %s%s%s\n", result, test_count, test, directive, reason); +} + + +int run_test(const char* test, + int timeout, + int benchmark_output, + int test_count) { + char errmsg[1024] = "no error"; + process_info_t processes[1024]; + process_info_t *main_proc; + task_entry_t* task; + int process_count; + int result; + int status; + int i; + + status = 255; + main_proc = NULL; + process_count = 0; + +#ifndef _WIN32 + /* Clean up stale socket from previous run. */ + remove(TEST_PIPENAME); +#endif + + /* If it's a helper the user asks for, start it directly. */ + for (task = TASKS; task->main; task++) { + if (task->is_helper && strcmp(test, task->process_name) == 0) { + return task->main(); + } + } + + /* Start the helpers first. */ + for (task = TASKS; task->main; task++) { + if (strcmp(test, task->task_name) != 0) { + continue; + } + + /* Skip the test itself. */ + if (!task->is_helper) { + continue; + } + + if (process_start(task->task_name, + task->process_name, + &processes[process_count], + 1 /* is_helper */) == -1) { + snprintf(errmsg, + sizeof errmsg, + "Process `%s` failed to start.", + task->process_name); + goto out; + } + + process_count++; + } + + /* Give the helpers time to settle. Race-y, fix this. */ + uv_sleep(250); + + /* Now start the test itself. */ + for (task = TASKS; task->main; task++) { + if (strcmp(test, task->task_name) != 0) { + continue; + } + + if (task->is_helper) { + continue; + } + + if (process_start(task->task_name, + task->process_name, + &processes[process_count], + 0 /* !is_helper */) == -1) { + snprintf(errmsg, + sizeof errmsg, + "Process `%s` failed to start.", + task->process_name); + goto out; + } + + main_proc = &processes[process_count]; + process_count++; + break; + } + + if (main_proc == NULL) { + snprintf(errmsg, + sizeof errmsg, + "No test with that name: %s", + test); + goto out; + } + + result = process_wait(main_proc, 1, timeout); + if (result == -1) { + FATAL("process_wait failed"); + } else if (result == -2) { + /* Don't have to clean up the process, process_wait() has killed it. */ + snprintf(errmsg, + sizeof errmsg, + "timeout"); + goto out; + } + + status = process_reap(main_proc); + if (status != TEST_OK) { + snprintf(errmsg, + sizeof errmsg, + "exit code %d", + status); + goto out; + } + + if (benchmark_output) { + /* Give the helpers time to clean up their act. */ + uv_sleep(1000); + } + +out: + /* Reap running processes except the main process, it's already dead. */ + for (i = 0; i < process_count - 1; i++) { + process_terminate(&processes[i]); + } + + if (process_count > 0 && + process_wait(processes, process_count - 1, -1) < 0) { + FATAL("process_wait failed"); + } + + if (tap_output) + log_tap_result(test_count, test, status, &processes[i]); + + /* Show error and output from processes if the test failed. */ + if (status != 0 || task->show_output) { + if (tap_output) { + LOGF("#"); + } else if (status == TEST_TODO) { + LOGF("\n`%s` todo\n", test); + } else if (status == TEST_SKIP) { + LOGF("\n`%s` skipped\n", test); + } else if (status != 0) { + LOGF("\n`%s` failed: %s\n", test, errmsg); + } else { + LOGF("\n"); + } + + for (i = 0; i < process_count; i++) { + switch (process_output_size(&processes[i])) { + case -1: + LOGF("Output from process `%s`: (unavailable)\n", + process_get_name(&processes[i])); + break; + + case 0: + LOGF("Output from process `%s`: (no output)\n", + process_get_name(&processes[i])); + break; + + default: + LOGF("Output from process `%s`:\n", process_get_name(&processes[i])); + process_copy_output(&processes[i], fileno(stderr)); + break; + } + } + + if (!tap_output) { + LOG("=============================================================\n"); + } + + /* In benchmark mode show concise output from the main process. */ + } else if (benchmark_output) { + switch (process_output_size(main_proc)) { + case -1: + LOGF("%s: (unavailable)\n", test); + break; + + case 0: + LOGF("%s: (no output)\n", test); + break; + + default: + for (i = 0; i < process_count; i++) { + process_copy_output(&processes[i], fileno(stderr)); + } + break; + } + } + + /* Clean up all process handles. */ + for (i = 0; i < process_count; i++) { + process_cleanup(&processes[i]); + } + + return status; +} + + +/* Returns the status code of the task part + * or 255 if no matching task was not found. + */ +int run_test_part(const char* test, const char* part) { + task_entry_t* task; + int r; + + for (task = TASKS; task->main; task++) { + if (strcmp(test, task->task_name) == 0 && + strcmp(part, task->process_name) == 0) { + r = task->main(); + return r; + } + } + + LOGF("No test part with that name: %s:%s\n", test, part); + return 255; +} + + +static int compare_task(const void* va, const void* vb) { + const task_entry_t* a = va; + const task_entry_t* b = vb; + return strcmp(a->task_name, b->task_name); +} + + +static int find_helpers(const task_entry_t* task, + const task_entry_t** helpers) { + const task_entry_t* helper; + int n_helpers; + + for (n_helpers = 0, helper = TASKS; helper->main; helper++) { + if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) { + *helpers++ = helper; + n_helpers++; + } + } + + return n_helpers; +} + + +void print_tests(FILE* stream) { + const task_entry_t* helpers[1024]; + const task_entry_t* task; + int n_helpers; + int n_tasks; + int i; + + for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++); + qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task); + + for (task = TASKS; task->main; task++) { + if (task->is_helper) { + continue; + } + + n_helpers = find_helpers(task, helpers); + if (n_helpers) { + printf("%-25s (helpers:", task->task_name); + for (i = 0; i < n_helpers; i++) { + printf(" %s", helpers[i]->process_name); + } + printf(")\n"); + } else { + printf("%s\n", task->task_name); + } + } +} diff --git a/test/runner.h b/test/runner.h new file mode 100644 index 0000000000..aa7f205407 --- /dev/null +++ b/test/runner.h @@ -0,0 +1,170 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef RUNNER_H_ +#define RUNNER_H_ + +#include /* FILE */ + + +/* + * The maximum number of processes (main + helpers) that a test / benchmark + * can have. + */ +#define MAX_PROCESSES 8 + + +/* + * Struct to store both tests and to define helper processes for tasks. + */ +typedef struct { + char *task_name; + char *process_name; + int (*main)(void); + int is_helper; + int show_output; +} task_entry_t, bench_entry_t; + + +/* + * Macros used by test-list.h and benchmark-list.h. + */ +#define TASK_LIST_START \ + task_entry_t TASKS[] = { + +#define TASK_LIST_END \ + { 0, 0, 0, 0, 0 } \ + }; + +#define TEST_DECLARE(name) \ + int run_test_##name(void); + +#define TEST_ENTRY(name) \ + { #name, #name, &run_test_##name, 0, 0 }, + +#define TEST_OUTPUT_ENTRY(name) \ + { #name, #name, &run_test_##name, 0, 1 }, + +#define BENCHMARK_DECLARE(name) \ + int run_benchmark_##name(void); + +#define BENCHMARK_ENTRY(name) \ + { #name, #name, &run_benchmark_##name, 0, 0 }, + +#define HELPER_DECLARE(name) \ + int run_helper_##name(void); + +#define HELPER_ENTRY(task_name, name) \ + { #task_name, #name, &run_helper_##name, 1, 0 }, + +#define TEST_HELPER HELPER_ENTRY +#define BENCHMARK_HELPER HELPER_ENTRY + +#define PATHMAX 1024 +extern char executable_path[PATHMAX]; + +/* + * Include platform-dependent definitions + */ +#ifdef _WIN32 +# include "runner-win.h" +#else +# include "runner-unix.h" +#endif + + +/* The array that is filled by test-list.h or benchmark-list.h */ +extern task_entry_t TASKS[]; + +/* + * Run all tests. + */ +int run_tests(int timeout, int benchmark_output); + +/* + * Run a single test. Starts up any helpers. + */ +int run_test(const char* test, + int timeout, + int benchmark_output, + int test_count); + +/* + * Run a test part, i.e. the test or one of its helpers. + */ +int run_test_part(const char* test, const char* part); + + +/* + * Print tests in sorted order to `stream`. Used by `./run-tests --list`. + */ +void print_tests(FILE* stream); + + +/* + * Stuff that should be implemented by test-runner-.h + * All functions return 0 on success, -1 on failure, unless specified + * otherwise. + */ + +/* Do platform-specific initialization. */ +void platform_init(int argc, char** argv); + +/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */ +/* Make sure that all stdio output of the processes is buffered up. */ +int process_start(char *name, char* part, process_info_t *p, int is_helper); + +/* Wait for all `n` processes in `vec` to terminate. */ +/* Time out after `timeout` msec, or never if timeout == -1 */ +/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ +int process_wait(process_info_t *vec, int n, int timeout); + +/* Returns the number of bytes in the stdio output buffer for process `p`. */ +long int process_output_size(process_info_t *p); + +/* Copy the contents of the stdio output buffer to `fd`. */ +int process_copy_output(process_info_t *p, int fd); + +/* Copy the last line of the stdio output buffer to `buffer` */ +int process_read_last_line(process_info_t *p, + char * buffer, + size_t buffer_len); + +/* Return the name that was specified when `p` was started by process_start */ +char* process_get_name(process_info_t *p); + +/* Terminate process `p`. */ +int process_terminate(process_info_t *p); + +/* Return the exit code of process p. */ +/* On error, return -1. */ +int process_reap(process_info_t *p); + +/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */ +void process_cleanup(process_info_t *p); + +/* Move the console cursor one line up and back to the first column. */ +void rewind_cursor(void); + +/* trigger output as tap */ +extern int tap_output; + +#endif /* RUNNER_H_ */ diff --git a/test/task.h b/test/task.h new file mode 100644 index 0000000000..b736c375c7 --- /dev/null +++ b/test/task.h @@ -0,0 +1,207 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef TASK_H_ +#define TASK_H_ + +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if !defined(_WIN32) +# include +# include /* setrlimit() */ +#endif + +#define TEST_PORT 9123 +#define TEST_PORT_2 9124 + +#ifdef _WIN32 +# define TEST_PIPENAME "\\\\.\\pipe\\uv-test" +# define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2" +#else +# define TEST_PIPENAME "/tmp/uv-test-sock" +# define TEST_PIPENAME_2 "/tmp/uv-test-sock2" +#endif + +#ifdef _WIN32 +# include +# ifndef S_IRUSR +# define S_IRUSR _S_IREAD +# endif +# ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +# endif +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +typedef enum { + TCP = 0, + UDP, + PIPE +} stream_type; + +/* Log to stderr. */ +#define LOG(...) \ + do { \ + fprintf(stderr, "%s", __VA_ARGS__); \ + fflush(stderr); \ + } while (0) + +#define LOGF(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } while (0) + +/* Die with fatal error. */ +#define FATAL(msg) \ + do { \ + fprintf(stderr, \ + "Fatal error in %s on line %d: %s\n", \ + __FILE__, \ + __LINE__, \ + msg); \ + fflush(stderr); \ + abort(); \ + } while (0) + +/* Have our own assert, so we are sure it does not get optimized away in + * a release build. + */ +#define ASSERT(expr) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: %s\n", \ + __FILE__, \ + __LINE__, \ + #expr); \ + abort(); \ + } \ + } while (0) + +/* This macro cleans up the main loop. This is used to avoid valgrind + * warnings about memory being "leaked" by the main event loop. + */ +#define MAKE_VALGRIND_HAPPY() \ + uv_loop_delete(uv_default_loop()) + +/* Just sugar for wrapping the main() for a task or helper. */ +#define TEST_IMPL(name) \ + int run_test_##name(void); \ + int run_test_##name(void) + +#define BENCHMARK_IMPL(name) \ + int run_benchmark_##name(void); \ + int run_benchmark_##name(void) + +#define HELPER_IMPL(name) \ + int run_helper_##name(void); \ + int run_helper_##name(void) + +/* Pause the calling thread for a number of milliseconds. */ +void uv_sleep(int msec); + +/* Format big numbers nicely. WARNING: leaks memory. */ +const char* fmt(double d); + +/* Reserved test exit codes. */ +enum test_status { + TEST_OK = 0, + TEST_TODO, + TEST_SKIP +}; + +#define RETURN_OK() \ + do { \ + return TEST_OK; \ + } while (0) + +#define RETURN_TODO(explanation) \ + do { \ + LOGF("%s\n", explanation); \ + return TEST_TODO; \ + } while (0) + +#define RETURN_SKIP(explanation) \ + do { \ + LOGF("%s\n", explanation); \ + return TEST_SKIP; \ + } while (0) + +#if !defined(_WIN32) + +# define TEST_FILE_LIMIT(num) \ + do { \ + struct rlimit lim; \ + lim.rlim_cur = (num); \ + lim.rlim_max = lim.rlim_cur; \ + if (setrlimit(RLIMIT_NOFILE, &lim)) \ + RETURN_SKIP("File descriptor limit too low."); \ + } while (0) + +#else /* defined(_WIN32) */ + +# define TEST_FILE_LIMIT(num) do {} while (0) + +#endif + + +#if defined _WIN32 && ! defined __GNUC__ + +#include + +/* Emulate snprintf() on Windows, _snprintf() doesn't zero-terminate the buffer + * on overflow... + */ +static int snprintf(char* buf, size_t len, const char* fmt, ...) { + va_list ap; + int n; + + va_start(ap, fmt); + n = _vsprintf_p(buf, len, fmt, ap); + va_end(ap); + + /* It's a sad fact of life that no one ever checks the return value of + * snprintf(). Zero-terminating the buffer hopefully reduces the risk + * of gaping security holes. + */ + if (n < 0) + if (len > 0) + buf[0] = '\0'; + + return n; +} + +#endif + +#endif /* TASK_H_ */ diff --git a/test/test-active.c b/test/test-active.c new file mode 100644 index 0000000000..0fae23cdb1 --- /dev/null +++ b/test/test-active.c @@ -0,0 +1,84 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(0 && "timer_cb should not have been called"); +} + + +TEST_IMPL(active) { + int r; + uv_timer_t timer; + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + /* uv_is_active() and uv_is_closing() should always return either 0 or 1. */ + ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + + r = uv_timer_start(&timer, timer_cb, 1000, 0); + ASSERT(r == 0); + + ASSERT(1 == uv_is_active((uv_handle_t*) &timer)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + + r = uv_timer_stop(&timer); + ASSERT(r == 0); + + ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + + r = uv_timer_start(&timer, timer_cb, 1000, 0); + ASSERT(r == 0); + + ASSERT(1 == uv_is_active((uv_handle_t*) &timer)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + + uv_close((uv_handle_t*) &timer, close_cb); + + ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); + ASSERT(1 == uv_is_closing((uv_handle_t*) &timer)); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-async-null-cb.c b/test/test-async-null-cb.c new file mode 100644 index 0000000000..d654884268 --- /dev/null +++ b/test/test-async-null-cb.c @@ -0,0 +1,55 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_async_t async_handle; +static uv_check_t check_handle; +static int check_cb_called; +static uv_thread_t thread; + + +static void thread_cb(void* dummy) { + (void) &dummy; + uv_async_send(&async_handle); +} + + +static void check_cb(uv_check_t* handle, int status) { + ASSERT(check_cb_called == 0); + uv_close((uv_handle_t*) &async_handle, NULL); + uv_close((uv_handle_t*) &check_handle, NULL); + check_cb_called++; +} + + +TEST_IMPL(async_null_cb) { + ASSERT(0 == uv_async_init(uv_default_loop(), &async_handle, NULL)); + ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle)); + ASSERT(0 == uv_check_start(&check_handle, check_cb)); + ASSERT(0 == uv_thread_create(&thread, thread_cb, NULL)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == uv_thread_join(&thread)); + ASSERT(1 == check_cb_called); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-async.c b/test/test-async.c new file mode 100644 index 0000000000..d4d94d5fa0 --- /dev/null +++ b/test/test-async.c @@ -0,0 +1,136 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static uv_thread_t thread; +static uv_mutex_t mutex; + +static uv_prepare_t prepare; +static uv_async_t async; + +static volatile int async_cb_called; +static int prepare_cb_called; +static int close_cb_called; + + +static void thread_cb(void *arg) { + int n; + int r; + + for (;;) { + uv_mutex_lock(&mutex); + n = async_cb_called; + uv_mutex_unlock(&mutex); + + if (n == 3) { + break; + } + + r = uv_async_send(&async); + ASSERT(r == 0); + + /* Work around a bug in Valgrind. + * + * Valgrind runs threads not in parallel but sequentially, i.e. one after + * the other. It also doesn't preempt them, instead it depends on threads + * yielding voluntarily by making a syscall. + * + * That never happens here: the pipe that is associated with the async + * handle is written to once but that's too early for Valgrind's scheduler + * to kick in. Afterwards, the thread busy-loops, starving the main thread. + * Therefore, we yield. + * + * This behavior has been observed with Valgrind 3.7.0 and 3.9.0. + */ + uv_sleep(0); + } +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void async_cb(uv_async_t* handle, int status) { + int n; + + ASSERT(handle == &async); + ASSERT(status == 0); + + uv_mutex_lock(&mutex); + n = ++async_cb_called; + uv_mutex_unlock(&mutex); + + if (n == 3) { + uv_close((uv_handle_t*)&async, close_cb); + uv_close((uv_handle_t*)&prepare, close_cb); + } +} + + +static void prepare_cb(uv_prepare_t* handle, int status) { + int r; + + ASSERT(handle == &prepare); + ASSERT(status == 0); + + if (prepare_cb_called++) + return; + + r = uv_thread_create(&thread, thread_cb, NULL); + ASSERT(r == 0); + uv_mutex_unlock(&mutex); +} + + +TEST_IMPL(async) { + int r; + + r = uv_mutex_init(&mutex); + ASSERT(r == 0); + uv_mutex_lock(&mutex); + + r = uv_prepare_init(uv_default_loop(), &prepare); + ASSERT(r == 0); + r = uv_prepare_start(&prepare, prepare_cb); + ASSERT(r == 0); + + r = uv_async_init(uv_default_loop(), &async, async_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(prepare_cb_called > 0); + ASSERT(async_cb_called == 3); + ASSERT(close_cb_called == 2); + + ASSERT(0 == uv_thread_join(&thread)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-barrier.c b/test/test-barrier.c new file mode 100644 index 0000000000..97df704c0e --- /dev/null +++ b/test/test-barrier.c @@ -0,0 +1,98 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +typedef struct { + uv_barrier_t barrier; + int delay; + volatile int posted; +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + + if (c->delay) + uv_sleep(c->delay); + + uv_barrier_wait(&c->barrier); +} + + +TEST_IMPL(barrier_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + + ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_sleep(100); + uv_barrier_wait(&wc.barrier); + + ASSERT(0 == uv_thread_join(&thread)); + uv_barrier_destroy(&wc.barrier); + + return 0; +} + + +TEST_IMPL(barrier_2) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_barrier_wait(&wc.barrier); + + ASSERT(0 == uv_thread_join(&thread)); + uv_barrier_destroy(&wc.barrier); + + return 0; +} + + +TEST_IMPL(barrier_3) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + + ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_barrier_wait(&wc.barrier); + + ASSERT(0 == uv_thread_join(&thread)); + uv_barrier_destroy(&wc.barrier); + + return 0; +} diff --git a/test/test-callback-order.c b/test/test-callback-order.c new file mode 100644 index 0000000000..84231e1b6b --- /dev/null +++ b/test/test-callback-order.c @@ -0,0 +1,77 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static int idle_cb_called; +static int timer_cb_called; + +static uv_idle_t idle_handle; +static uv_timer_t timer_handle; + + +/* idle_cb should run before timer_cb */ +static void idle_cb(uv_idle_t* handle, int status) { + ASSERT(idle_cb_called == 0); + ASSERT(timer_cb_called == 0); + uv_idle_stop(handle); + idle_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(idle_cb_called == 1); + ASSERT(timer_cb_called == 0); + uv_timer_stop(handle); + timer_cb_called++; +} + + +static void next_tick(uv_idle_t* handle, int status) { + uv_loop_t* loop = handle->loop; + uv_idle_stop(handle); + uv_idle_init(loop, &idle_handle); + uv_idle_start(&idle_handle, idle_cb); + uv_timer_init(loop, &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 0, 0); +} + + +TEST_IMPL(callback_order) { + uv_loop_t* loop; + uv_idle_t idle; + + loop = uv_default_loop(); + uv_idle_init(loop, &idle); + uv_idle_start(&idle, next_tick); + + ASSERT(idle_cb_called == 0); + ASSERT(timer_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(idle_cb_called == 1); + ASSERT(timer_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-callback-stack.c b/test/test-callback-stack.c new file mode 100644 index 0000000000..accd549697 --- /dev/null +++ b/test/test-callback-stack.c @@ -0,0 +1,206 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * TODO: Add explanation of why we want on_close to be called from fresh + * stack. + */ + +#include "uv.h" +#include "task.h" + + +static const char MESSAGE[] = "Failure is for the weak. Everyone dies alone."; + +static uv_tcp_t client; +static uv_timer_t timer; +static uv_connect_t connect_req; +static uv_write_t write_req; +static uv_shutdown_t shutdown_req; + +static int nested = 0; +static int close_cb_called = 0; +static int connect_cb_called = 0; +static int write_cb_called = 0; +static int timer_cb_called = 0; +static int bytes_received = 0; +static int shutdown_cb_called = 0; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->len = size; + buf->base = malloc(size); + ASSERT(buf->base != NULL); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(nested == 0 && "close_cb must be called from a fresh stack"); + + close_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(status == 0); + ASSERT(nested == 0 && "shutdown_cb must be called from a fresh stack"); + + shutdown_cb_called++; +} + + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + ASSERT(nested == 0 && "read_cb must be called from a fresh stack"); + + printf("Read. nread == %d\n", (int)nread); + free(buf->base); + + if (nread == 0) { + return; + + } else if (nread < 0) { + ASSERT(nread == UV_EOF); + + nested++; + uv_close((uv_handle_t*)tcp, close_cb); + nested--; + + return; + } + + bytes_received += nread; + + /* We call shutdown here because when bytes_received == sizeof MESSAGE */ + /* there will be no more data sent nor received, so here it would be */ + /* possible for a backend to to call shutdown_cb immediately and *not* */ + /* from a fresh stack. */ + if (bytes_received == sizeof MESSAGE) { + nested++; + + puts("Shutdown"); + + if (uv_shutdown(&shutdown_req, (uv_stream_t*)tcp, shutdown_cb)) { + FATAL("uv_shutdown failed"); + } + nested--; + } +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer); + ASSERT(status == 0); + ASSERT(nested == 0 && "timer_cb must be called from a fresh stack"); + + puts("Timeout complete. Now read data..."); + + nested++; + if (uv_read_start((uv_stream_t*)&client, alloc_cb, read_cb)) { + FATAL("uv_read_start failed"); + } + nested--; + + timer_cb_called++; + + uv_close((uv_handle_t*)handle, close_cb); +} + + +static void write_cb(uv_write_t* req, int status) { + int r; + + ASSERT(status == 0); + ASSERT(nested == 0 && "write_cb must be called from a fresh stack"); + + puts("Data written. 500ms timeout..."); + + /* After the data has been sent, we're going to wait for a while, then */ + /* start reading. This makes us certain that the message has been echoed */ + /* back to our receive buffer when we start reading. This maximizes the */ + /* temptation for the backend to use dirty stack for calling read_cb. */ + nested++; + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb, 500, 0); + ASSERT(r == 0); + nested--; + + write_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + uv_buf_t buf; + + puts("Connected. Write some data to echo server..."); + + ASSERT(status == 0); + ASSERT(nested == 0 && "connect_cb must be called from a fresh stack"); + + nested++; + + buf.base = (char*) &MESSAGE; + buf.len = sizeof MESSAGE; + + if (uv_write(&write_req, (uv_stream_t*)req->handle, &buf, 1, write_cb)) { + FATAL("uv_write failed"); + } + + nested--; + + connect_cb_called++; +} + + +TEST_IMPL(callback_stack) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + if (uv_tcp_init(uv_default_loop(), &client)) { + FATAL("uv_tcp_init failed"); + } + + puts("Connecting..."); + + nested++; + + if (uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + connect_cb)) { + FATAL("uv_tcp_connect failed"); + } + nested--; + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(nested == 0); + ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once"); + ASSERT(write_cb_called == 1 && "write_cb must be called exactly once"); + ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once"); + ASSERT(bytes_received == sizeof MESSAGE); + ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once"); + ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-close-fd.c b/test/test-close-fd.c new file mode 100644 index 0000000000..0d17f07661 --- /dev/null +++ b/test/test-close-fd.c @@ -0,0 +1,77 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#if !defined(_WIN32) + +#include "uv.h" +#include "task.h" +#include +#include + +static unsigned int read_cb_called; + +static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { + static char slab[1]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { + switch (++read_cb_called) { + case 1: + ASSERT(nread == 1); + uv_read_stop(handle); + break; + case 2: + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t *) handle, NULL); + break; + default: + ASSERT(!"read_cb_called > 2"); + } +} + +TEST_IMPL(close_fd) { + uv_pipe_t pipe_handle; + int fd[2]; + + ASSERT(0 == pipe(fd)); + ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK)); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); + ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0])); + fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */ + ASSERT(1 == write(fd[1], "", 1)); + ASSERT(0 == close(fd[1])); + fd[1] = -1; + ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == read_cb_called); + ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle)); + ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(2 == read_cb_called); + ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !defined(_WIN32) */ diff --git a/test/test-close-order.c b/test/test-close-order.c new file mode 100644 index 0000000000..e2f25f987d --- /dev/null +++ b/test/test-close-order.c @@ -0,0 +1,80 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static int check_cb_called; +static int timer_cb_called; +static int close_cb_called; + +static uv_check_t check_handle; +static uv_timer_t timer_handle1; +static uv_timer_t timer_handle2; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +/* check_cb should run before any close_cb */ +static void check_cb(uv_check_t* handle, int status) { + ASSERT(check_cb_called == 0); + ASSERT(timer_cb_called == 1); + ASSERT(close_cb_called == 0); + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &timer_handle2, close_cb); + check_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_close((uv_handle_t*) handle, close_cb); + timer_cb_called++; +} + + +TEST_IMPL(close_order) { + uv_loop_t* loop; + loop = uv_default_loop(); + + uv_check_init(loop, &check_handle); + uv_check_start(&check_handle, check_cb); + uv_timer_init(loop, &timer_handle1); + uv_timer_start(&timer_handle1, timer_cb, 0, 0); + uv_timer_init(loop, &timer_handle2); + uv_timer_start(&timer_handle2, timer_cb, 100000, 0); + + ASSERT(check_cb_called == 0); + ASSERT(close_cb_called == 0); + ASSERT(timer_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(check_cb_called == 1); + ASSERT(close_cb_called == 3); + ASSERT(timer_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-condvar.c b/test/test-condvar.c new file mode 100644 index 0000000000..dbacdba384 --- /dev/null +++ b/test/test-condvar.c @@ -0,0 +1,173 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +typedef struct { + uv_mutex_t mutex; + uv_cond_t cond; + int delay; + int use_broadcast; + volatile int posted; +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + + if (c->delay) + uv_sleep(c->delay); + + uv_mutex_lock(&c->mutex); + ASSERT(c->posted == 0); + c->posted = 1; + if (c->use_broadcast) + uv_cond_broadcast(&c->cond); + else + uv_cond_signal(&c->cond); + uv_mutex_unlock(&c->mutex); +} + + +TEST_IMPL(condvar_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_mutex_lock(&wc.mutex); + uv_sleep(100); + uv_cond_wait(&wc.cond, &wc.mutex); + ASSERT(wc.posted == 1); + uv_mutex_unlock(&wc.mutex); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +TEST_IMPL(condvar_2) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_mutex_lock(&wc.mutex); + uv_cond_wait(&wc.cond, &wc.mutex); + uv_mutex_unlock(&wc.mutex); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +TEST_IMPL(condvar_3) { + uv_thread_t thread; + worker_config wc; + int r; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_mutex_lock(&wc.mutex); + r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6)); + ASSERT(r == UV_ETIMEDOUT); + uv_mutex_unlock(&wc.mutex); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +TEST_IMPL(condvar_4) { + uv_thread_t thread; + worker_config wc; + int r; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_mutex_lock(&wc.mutex); + r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0); + uv_mutex_unlock(&wc.mutex); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +TEST_IMPL(condvar_5) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.use_broadcast = 1; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_mutex_lock(&wc.mutex); + uv_sleep(100); + uv_cond_wait(&wc.cond, &wc.mutex); + ASSERT(wc.posted == 1); + uv_mutex_unlock(&wc.mutex); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} diff --git a/test/test-connection-fail.c b/test/test-connection-fail.c new file mode 100644 index 0000000000..5700140130 --- /dev/null +++ b/test/test-connection-fail.c @@ -0,0 +1,152 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +static uv_tcp_t tcp; +static uv_connect_t req; +static int connect_cb_calls; +static int close_cb_calls; + +static uv_timer_t timer; +static int timer_close_cb_calls; +static int timer_cb_calls; + + +static void on_close(uv_handle_t* handle) { + close_cb_calls++; +} + + +static void timer_close_cb(uv_handle_t* handle) { + timer_close_cb_calls++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(status == 0); + timer_cb_calls++; + + /* + * These are the important asserts. The connection callback has been made, + * but libuv hasn't automatically closed the socket. The user must + * uv_close the handle manually. + */ + ASSERT(close_cb_calls == 0); + ASSERT(connect_cb_calls == 1); + + /* Close the tcp handle. */ + uv_close((uv_handle_t*)&tcp, on_close); + + /* Close the timer. */ + uv_close((uv_handle_t*)handle, timer_close_cb); +} + + +static void on_connect_with_close(uv_connect_t *req, int status) { + ASSERT((uv_stream_t*) &tcp == req->handle); + ASSERT(status == UV_ECONNREFUSED); + connect_cb_calls++; + + ASSERT(close_cb_calls == 0); + uv_close((uv_handle_t*)req->handle, on_close); +} + + +static void on_connect_without_close(uv_connect_t *req, int status) { + ASSERT(status == UV_ECONNREFUSED); + connect_cb_calls++; + + uv_timer_start(&timer, timer_cb, 100, 0); + + ASSERT(close_cb_calls == 0); +} + + +static void connection_fail(uv_connect_cb connect_cb) { + struct sockaddr_in client_addr, server_addr; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr)); + + /* There should be no servers listening on this port. */ + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT(!r); + + /* We are never doing multiple reads/connects at a time anyway. */ + /* so these handles can be pre-initialized. */ + ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0)); + + r = uv_tcp_connect(&req, + &tcp, + (const struct sockaddr*) &server_addr, + connect_cb); + ASSERT(!r); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(connect_cb_calls == 1); + ASSERT(close_cb_calls == 1); +} + + +/* + * This test attempts to connect to a port where no server is running. We + * expect an error. + */ +TEST_IMPL(connection_fail) { + connection_fail(on_connect_with_close); + + ASSERT(timer_close_cb_calls == 0); + ASSERT(timer_cb_calls == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +/* + * This test is the same as the first except it check that the close + * callback of the tcp handle hasn't been made after the failed connection + * attempt. + */ +TEST_IMPL(connection_fail_doesnt_auto_close) { + int r; + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + connection_fail(on_connect_without_close); + + ASSERT(timer_close_cb_calls == 1); + ASSERT(timer_cb_calls == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-cwd-and-chdir.c b/test/test-cwd-and-chdir.c new file mode 100644 index 0000000000..f1082ac47f --- /dev/null +++ b/test/test-cwd-and-chdir.c @@ -0,0 +1,64 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +extern char executable_path[]; + +TEST_IMPL(cwd_and_chdir) { + char buffer_orig[PATHMAX]; + char buffer_new[PATHMAX]; + size_t size; + char* last_slash; + int err; + + size = sizeof(buffer_orig) / sizeof(buffer_orig[0]); + err = uv_cwd(buffer_orig, size); + ASSERT(err == 0); + + /* Remove trailing slash unless at a root directory. */ +#ifdef _WIN32 + last_slash = strrchr(buffer_orig, '\\'); + ASSERT(last_slash); + if (last_slash > buffer_orig && *(last_slash - 1) != ':') { + *last_slash = '\0'; + } +#else /* Unix */ + last_slash = strrchr(buffer_orig, '/'); + ASSERT(last_slash); + if (last_slash != buffer_orig) { + *last_slash = '\0'; + } +#endif + + err = uv_chdir(buffer_orig); + ASSERT(err == 0); + + err = uv_cwd(buffer_new, size); + ASSERT(err == 0); + + ASSERT(strcmp(buffer_orig, buffer_new) == 0); + + return 0; +} diff --git a/test/test-delayed-accept.c b/test/test-delayed-accept.c new file mode 100644 index 0000000000..b45100d625 --- /dev/null +++ b/test/test-delayed-accept.c @@ -0,0 +1,190 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static int connection_cb_called = 0; +static int do_accept_called = 0; +static int close_cb_called = 0; +static int connect_cb_called = 0; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + + free(handle); + + close_cb_called++; +} + + +static void do_accept(uv_timer_t* timer_handle, int status) { + uv_tcp_t* server; + uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle); + int r; + + ASSERT(timer_handle != NULL); + ASSERT(status == 0); + ASSERT(accepted_handle != NULL); + + r = uv_tcp_init(uv_default_loop(), accepted_handle); + ASSERT(r == 0); + + server = (uv_tcp_t*)timer_handle->data; + r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle); + ASSERT(r == 0); + + do_accept_called++; + + /* Immediately close the accepted handle. */ + uv_close((uv_handle_t*)accepted_handle, close_cb); + + /* After accepting the two clients close the server handle */ + if (do_accept_called == 2) { + uv_close((uv_handle_t*)server, close_cb); + } + + /* Dispose the timer. */ + uv_close((uv_handle_t*)timer_handle, close_cb); +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + int r; + uv_timer_t* timer_handle; + + ASSERT(status == 0); + + timer_handle = (uv_timer_t*)malloc(sizeof *timer_handle); + ASSERT(timer_handle != NULL); + + /* Accept the client after 1 second */ + r = uv_timer_init(uv_default_loop(), timer_handle); + ASSERT(r == 0); + + timer_handle->data = tcp; + + r = uv_timer_start(timer_handle, do_accept, 1000, 0); + ASSERT(r == 0); + + connection_cb_called++; +} + + +static void start_server(void) { + struct sockaddr_in addr; + uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server); + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT(server != NULL); + + r = uv_tcp_init(uv_default_loop(), server); + ASSERT(r == 0); + r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)server, 128, connection_cb); + ASSERT(r == 0); +} + + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + /* The server will not send anything, it should close gracefully. */ + + if (buf->base) { + free(buf->base); + } + + if (nread >= 0) { + ASSERT(nread == 0); + } else { + ASSERT(tcp != NULL); + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t*)tcp, close_cb); + } +} + + +static void connect_cb(uv_connect_t* req, int status) { + int r; + + ASSERT(req != NULL); + ASSERT(status == 0); + + /* Not that the server will send anything, but otherwise we'll never know */ + /* when the server closes the connection. */ + r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb); + ASSERT(r == 0); + + connect_cb_called++; + + free(req); +} + + +static void client_connect(void) { + struct sockaddr_in addr; + uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof *client); + uv_connect_t* connect_req = malloc(sizeof *connect_req); + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(client != NULL); + ASSERT(connect_req != NULL); + + r = uv_tcp_init(uv_default_loop(), client); + ASSERT(r == 0); + + r = uv_tcp_connect(connect_req, + client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); +} + + + +TEST_IMPL(delayed_accept) { + start_server(); + + client_connect(); + client_connect(); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(connection_cb_called == 2); + ASSERT(do_accept_called == 2); + ASSERT(connect_cb_called == 2); + ASSERT(close_cb_called == 7); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-dlerror.c b/test/test-dlerror.c new file mode 100644 index 0000000000..877ebf3712 --- /dev/null +++ b/test/test-dlerror.c @@ -0,0 +1,58 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + + +TEST_IMPL(dlerror) { + const char* path = "test/fixtures/load_error.node"; + const char* msg; + uv_lib_t lib; + int r; + +#ifdef __linux__ + const char* dlerror_desc = "file too short"; +#elif defined (__sun__) + const char* dlerror_desc = "unknown file type"; +#elif defined (_WIN32) + const char* dlerror_desc = "%1 is not a valid Win32 application"; +#else + const char* dlerror_desc = ""; +#endif + + r = uv_dlopen(path, &lib); + ASSERT(r == -1); + + msg = uv_dlerror(&lib); + ASSERT(msg != NULL); + ASSERT(strstr(msg, dlerror_desc) != NULL); + + /* Should return the same error twice in a row. */ + msg = uv_dlerror(&lib); + ASSERT(msg != NULL); + ASSERT(strstr(msg, dlerror_desc) != NULL); + + uv_dlclose(&lib); + + return 0; +} diff --git a/test/test-embed.c b/test/test-embed.c new file mode 100644 index 0000000000..ac1b3b6750 --- /dev/null +++ b/test/test-embed.c @@ -0,0 +1,139 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_KQUEUE 1 +# endif +#endif + +#ifndef HAVE_EPOLL +# if defined(__linux__) +# define HAVE_EPOLL 1 +# endif +#endif + +#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) + +#if defined(HAVE_KQUEUE) +# include +# include +# include +#endif + +#if defined(HAVE_EPOLL) +# include +#endif + +static uv_thread_t embed_thread; +static uv_sem_t embed_sem; +static uv_timer_t embed_timer; +static uv_async_t embed_async; +static volatile int embed_closed; + +static int embed_timer_called; + + +static void embed_thread_runner(void* arg) { + int r; + int fd; + int timeout; + + while (!embed_closed) { + fd = uv_backend_fd(uv_default_loop()); + timeout = uv_backend_timeout(uv_default_loop()); + + do { +#if defined(HAVE_KQUEUE) + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + r = kevent(fd, NULL, 0, NULL, 0, &ts); +#elif defined(HAVE_EPOLL) + { + struct epoll_event ev; + r = epoll_wait(fd, &ev, 1, timeout); + } +#endif + } while (r == -1 && errno == EINTR); + uv_async_send(&embed_async); + uv_sem_wait(&embed_sem); + } +} + + +static void embed_cb(uv_async_t* async, int status) { + uv_run(uv_default_loop(), UV_RUN_ONCE); + + uv_sem_post(&embed_sem); +} + + +static void embed_timer_cb(uv_timer_t* timer, int status) { + embed_timer_called++; + embed_closed = 1; + + uv_close((uv_handle_t*) &embed_async, NULL); +} +#endif + + +TEST_IMPL(embed) { +#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) + uv_loop_t* external; + + external = uv_loop_new(); + ASSERT(external != NULL); + + embed_timer_called = 0; + embed_closed = 0; + + uv_async_init(external, &embed_async, embed_cb); + + /* Start timer in default loop */ + uv_timer_init(uv_default_loop(), &embed_timer); + uv_timer_start(&embed_timer, embed_timer_cb, 250, 0); + + /* Start worker that will interrupt external loop */ + uv_sem_init(&embed_sem, 0); + uv_thread_create(&embed_thread, embed_thread_runner, NULL); + + /* But run external loop */ + uv_run(external, UV_RUN_DEFAULT); + + uv_thread_join(&embed_thread); + uv_loop_delete(external); + + ASSERT(embed_timer_called == 1); +#endif + + return 0; +} diff --git a/test/test-emfile.c b/test/test-emfile.c new file mode 100644 index 0000000000..453bfe4cf5 --- /dev/null +++ b/test/test-emfile.c @@ -0,0 +1,111 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#if !defined(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include + +static void connection_cb(uv_stream_t* server_handle, int status); +static void connect_cb(uv_connect_t* req, int status); + +static const int maxfd = 31; +static unsigned connect_cb_called; +static uv_tcp_t server_handle; +static uv_tcp_t client_handle; + + +TEST_IMPL(emfile) { + struct sockaddr_in addr; + struct rlimit limits; + uv_connect_t connect_req; + uv_loop_t* loop; + int first_fd; + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(0 == uv_tcp_init(loop, &server_handle)); + ASSERT(0 == uv_tcp_init(loop, &client_handle)); + ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); + + /* Lower the file descriptor limit and use up all fds save one. */ + limits.rlim_cur = limits.rlim_max = maxfd + 1; + if (setrlimit(RLIMIT_NOFILE, &limits)) { + perror("setrlimit(RLIMIT_NOFILE)"); + ASSERT(0); + } + + /* Remember the first one so we can clean up afterwards. */ + do + first_fd = dup(0); + while (first_fd == -1 && errno == EINTR); + ASSERT(first_fd > 0); + + while (dup(0) != -1 || errno == EINTR); + ASSERT(errno == EMFILE); + close(maxfd); + + /* Now connect and use up the last available file descriptor. The EMFILE + * handling logic in src/unix/stream.c should ensure that connect_cb() runs + * whereas connection_cb() should *not* run. + */ + ASSERT(0 == uv_tcp_connect(&connect_req, + &client_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == connect_cb_called); + + /* Close the dups again. Ignore errors in the unlikely event that the + * file descriptors were not contiguous. + */ + while (first_fd < maxfd) { + close(first_fd); + first_fd += 1; + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void connection_cb(uv_stream_t* server_handle, int status) { + ASSERT(0 && "connection_cb should not be called."); +} + + +static void connect_cb(uv_connect_t* req, int status) { + /* |status| should equal 0 because the connection should have been accepted, + * it's just that the server immediately closes it again. + */ + ASSERT(0 == status); + connect_cb_called += 1; + uv_close((uv_handle_t*) &server_handle, NULL); + uv_close((uv_handle_t*) &client_handle, NULL); +} + +#endif /* !defined(_WIN32) */ diff --git a/test/test-error.c b/test/test-error.c new file mode 100644 index 0000000000..eb337e66f3 --- /dev/null +++ b/test/test-error.c @@ -0,0 +1,50 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + + +/* + * Synthetic errors (errors that originate from within libuv, not the system) + * should produce sensible error messages when run through uv_strerror(). + * + * See https://github.com/joyent/libuv/issues/210 + */ +TEST_IMPL(error_message) { + /* Cop out. Can't do proper checks on systems with + * i18n-ized error messages... + */ + if (strcmp(uv_strerror(0), "Success") != 0) { + printf("i18n error messages detected, skipping test.\n"); + return 0; + } + + ASSERT(strstr(uv_strerror(UV_EINVAL), "Success") == NULL); + ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0); + ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0); + + return 0; +} diff --git a/test/test-fail-always.c b/test/test-fail-always.c new file mode 100644 index 0000000000..0008459eac --- /dev/null +++ b/test/test-fail-always.c @@ -0,0 +1,29 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" + + +TEST_IMPL(fail_always) { + /* This test always fails. It is used to test the test runner. */ + FATAL("Yes, it always fails"); + return 2; +} diff --git a/test/test-fs-event.c b/test/test-fs-event.c new file mode 100644 index 0000000000..3286de51f9 --- /dev/null +++ b/test/test-fs-event.c @@ -0,0 +1,730 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_KQUEUE 1 +# endif +#endif + +static uv_fs_event_t fs_event; +static const char file_prefix[] = "fsevent-"; +static uv_timer_t timer; +static int timer_cb_called; +static int close_cb_called; +static const int fs_event_file_count = 128; +static int fs_event_created; +static int fs_event_cb_called; +#if defined(PATH_MAX) +static char fs_event_filename[PATH_MAX]; +#else +static char fs_event_filename[1024]; +#endif /* defined(PATH_MAX) */ +static int timer_cb_touch_called; + +static void fs_event_unlink_files(uv_timer_t* handle, int status); + +static void create_dir(uv_loop_t* loop, const char* name) { + int r; + uv_fs_t req; + r = uv_fs_mkdir(loop, &req, name, 0755, NULL); + ASSERT(r == 0 || r == UV_EEXIST); + uv_fs_req_cleanup(&req); +} + +static void create_file(uv_loop_t* loop, const char* name) { + int r; + uv_file file; + uv_fs_t req; + + r = uv_fs_open(loop, &req, name, O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + file = r; + uv_fs_req_cleanup(&req); + r = uv_fs_close(loop, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +} + +static void touch_file(uv_loop_t* loop, const char* name) { + int r; + uv_file file; + uv_fs_t req; + + r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL); + ASSERT(r >= 0); + file = r; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, "foo", 4, -1, NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_close(loop, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +} + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + +static void fail_cb(uv_fs_event_t* handle, + const char* path, + int events, + int status) { + ASSERT(0 && "fail_cb called"); +} + +static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ++fs_event_cb_called; + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_RENAME); + ASSERT(filename == NULL || strcmp(filename, "file1") == 0); + ASSERT(0 == uv_fs_event_stop(handle)); + uv_close((uv_handle_t*)handle, close_cb); +} + +static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, + const char* filename, + int events, + int status) { + fs_event_cb_called++; + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_RENAME); + ASSERT(filename == NULL || + strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + + /* Stop watching dir when received events about all files: + * both create and close events */ + if (fs_event_cb_called == 2 * fs_event_file_count) { + ASSERT(0 == uv_fs_event_stop(handle)); + uv_close((uv_handle_t*) handle, close_cb); + } +} + +static const char* fs_event_get_filename(int i) { + snprintf(fs_event_filename, + sizeof(fs_event_filename), + "watch_dir/%s%d", + file_prefix, + i); + return fs_event_filename; +} + +static void fs_event_create_files(uv_timer_t* handle, int status) { + int i; + + /* Already created all files */ + if (fs_event_created == fs_event_file_count) { + uv_close((uv_handle_t*) &timer, close_cb); + return; + } + + /* Create all files */ + for (i = 0; i < 16; i++, fs_event_created++) + create_file(handle->loop, fs_event_get_filename(i)); + + /* And unlink them */ + ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0)); +} + +void fs_event_unlink_files(uv_timer_t* handle, int status) { + int r; + int i; + + /* NOTE: handle might be NULL if invoked not as timer callback */ + + /* Unlink all files */ + for (i = 0; i < 16; i++) { + r = remove(fs_event_get_filename(i)); + if (handle != NULL) + ASSERT(r == 0); + } + + /* And create them again */ + if (handle != NULL) + ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0)); +} + +static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ++fs_event_cb_called; + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_CHANGE); + ASSERT(filename == NULL || strcmp(filename, "file2") == 0); + ASSERT(0 == uv_fs_event_stop(handle)); + uv_close((uv_handle_t*)handle, close_cb); +} + +static void timer_cb_close_handle(uv_timer_t* timer, int status) { + uv_handle_t* handle; + + ASSERT(timer != NULL); + ASSERT(status == 0); + handle = timer->data; + + uv_close((uv_handle_t*)timer, NULL); + uv_close((uv_handle_t*)handle, close_cb); +} + +static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, + const char* filename, int events, int status) { + ASSERT(fs_event_cb_called == 0); + ++fs_event_cb_called; + + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_CHANGE); + ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); + + /* Regression test for SunOS: touch should generate just one event. */ + { + static uv_timer_t timer; + uv_timer_init(handle->loop, &timer); + timer.data = handle; + uv_timer_start(&timer, timer_cb_close_handle, 250, 0); + } +} + +static void timer_cb_file(uv_timer_t* handle, int status) { + ++timer_cb_called; + + if (timer_cb_called == 1) { + touch_file(handle->loop, "watch_dir/file1"); + } else { + touch_file(handle->loop, "watch_dir/file2"); + uv_close((uv_handle_t*)handle, close_cb); + } +} + +static void timer_cb_touch(uv_timer_t* timer, int status) { + ASSERT(status == 0); + uv_close((uv_handle_t*)timer, NULL); + touch_file(timer->loop, "watch_file"); + timer_cb_touch_called++; +} + +static void timer_cb_watch_twice(uv_timer_t* handle, int status) { + uv_fs_event_t* handles = handle->data; + uv_close((uv_handle_t*) (handles + 0), NULL); + uv_close((uv_handle_t*) (handles + 1), NULL); + uv_close((uv_handle_t*) handle, NULL); +} + +TEST_IMPL(fs_event_watch_dir) { + uv_loop_t* loop = uv_default_loop(); + int r; + + /* Setup */ + fs_event_unlink_files(NULL, 0); + remove("watch_dir/file2"); + remove("watch_dir/file1"); + remove("watch_dir/"); + create_dir(loop, "watch_dir"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, fs_event_create_files, 100, 0); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(fs_event_cb_called == 2 * fs_event_file_count); + ASSERT(fs_event_created == fs_event_file_count); + ASSERT(close_cb_called == 2); + + /* Cleanup */ + fs_event_unlink_files(NULL, 0); + remove("watch_dir/file2"); + remove("watch_dir/file1"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_watch_file) { + uv_loop_t* loop = uv_default_loop(); + int r; + + /* Setup */ + remove("watch_dir/file2"); + remove("watch_dir/file1"); + remove("watch_dir/"); + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file1"); + create_file(loop, "watch_dir/file2"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_file, 100, 100); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(fs_event_cb_called == 1); + ASSERT(timer_cb_called == 2); + ASSERT(close_cb_called == 2); + + /* Cleanup */ + remove("watch_dir/file2"); + remove("watch_dir/file1"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_watch_file_twice) { + const char path[] = "test/fixtures/empty_file"; + uv_fs_event_t watchers[2]; + uv_timer_t timer; + uv_loop_t* loop; + + loop = uv_default_loop(); + timer.data = watchers; + + ASSERT(0 == uv_fs_event_init(loop, watchers + 0)); + ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0)); + ASSERT(0 == uv_fs_event_init(loop, watchers + 1)); + ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0)); + ASSERT(0 == uv_timer_init(loop, &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_watch_file_current_dir) { + uv_timer_t timer; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_file"); + create_file(loop, "watch_file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, + fs_event_cb_file_current_dir, + "watch_file", + 0); + ASSERT(r == 0); + + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb_touch, 1, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + ASSERT(close_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + ASSERT(close_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_no_callback_after_close) { + uv_loop_t* loop = uv_default_loop(); + int r; + + /* Setup */ + remove("watch_dir/file1"); + remove("watch_dir/"); + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file1"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, + fs_event_cb_file, + "watch_dir/file1", + 0); + ASSERT(r == 0); + + + uv_close((uv_handle_t*)&fs_event, close_cb); + touch_file(loop, "watch_dir/file1"); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(fs_event_cb_called == 0); + ASSERT(close_cb_called == 1); + + /* Cleanup */ + remove("watch_dir/file1"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_no_callback_on_close) { + uv_loop_t* loop = uv_default_loop(); + int r; + + /* Setup */ + remove("watch_dir/file1"); + remove("watch_dir/"); + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file1"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, + fs_event_cb_file, + "watch_dir/file1", + 0); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&fs_event, close_cb); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(fs_event_cb_called == 0); + ASSERT(close_cb_called == 1); + + /* Cleanup */ + remove("watch_dir/file1"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void fs_event_fail(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ASSERT(0 && "should never be called"); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + int r; + + ASSERT(status == 0); + + r = uv_fs_event_init(handle->loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&fs_event, close_cb); + uv_close((uv_handle_t*)handle, close_cb); +} + + +TEST_IMPL(fs_event_immediate_close) { + uv_timer_t timer; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 1, 0); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_event_close_with_pending_event) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0); + ASSERT(r == 0); + + /* Generate an fs event. */ + touch_file(loop, "watch_dir/file"); + + uv_close((uv_handle_t*)&fs_event, close_cb); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + /* Clean up */ + remove("watch_dir/file"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#if defined(HAVE_KQUEUE) + +/* kqueue doesn't register fs events if you don't have an active watcher. + * The file descriptor needs to be part of the kqueue set of interest and + * that's not the case until we actually enter the event loop. + */ +TEST_IMPL(fs_event_close_in_callback) { + fprintf(stderr, "Skipping test, doesn't work with kqueue.\n"); + return 0; +} + +#else /* !HAVE_KQUEUE */ + +static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ASSERT(status == 0); + + ASSERT(fs_event_cb_called < 3); + ++fs_event_cb_called; + + if (fs_event_cb_called == 3) { + uv_close((uv_handle_t*) handle, close_cb); + } +} + + +TEST_IMPL(fs_event_close_in_callback) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + create_dir(loop, "watch_dir"); + create_file(loop, "watch_dir/file1"); + create_file(loop, "watch_dir/file2"); + create_file(loop, "watch_dir/file3"); + create_file(loop, "watch_dir/file4"); + create_file(loop, "watch_dir/file5"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0); + ASSERT(r == 0); + + /* Generate a couple of fs events. */ + touch_file(loop, "watch_dir/file1"); + touch_file(loop, "watch_dir/file2"); + touch_file(loop, "watch_dir/file3"); + touch_file(loop, "watch_dir/file4"); + touch_file(loop, "watch_dir/file5"); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + ASSERT(fs_event_cb_called == 3); + + /* Clean up */ + remove("watch_dir/file1"); + remove("watch_dir/file2"); + remove("watch_dir/file3"); + remove("watch_dir/file4"); + remove("watch_dir/file5"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* HAVE_KQUEUE */ + +TEST_IMPL(fs_event_start_and_close) { + uv_loop_t* loop; + uv_fs_event_t fs_event1; + uv_fs_event_t fs_event2; + int r; + + loop = uv_default_loop(); + + create_dir(loop, "watch_dir"); + + r = uv_fs_event_init(loop, &fs_event1); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0); + ASSERT(r == 0); + + r = uv_fs_event_init(loop, &fs_event2); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &fs_event2, close_cb); + uv_close((uv_handle_t*) &fs_event1, close_cb); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + + remove("watch_dir/"); + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#if defined(__APPLE__) + +static int fs_event_error_reported; + +static void fs_event_error_report_cb(uv_fs_event_t* handle, + const char* filename, + int events, + int status) { + if (status != 0) + fs_event_error_reported = status; +} + +static void timer_cb_nop(uv_timer_t* handle, int status) { + ++timer_cb_called; + uv_close((uv_handle_t*) handle, close_cb); +} + +static void fs_event_error_report_close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; + + /* handle is allocated on-stack, no need to free it */ +} + + +TEST_IMPL(fs_event_error_reporting) { + unsigned int i; + uv_loop_t* loops[1024]; + uv_fs_event_t events[ARRAY_SIZE(loops)]; + uv_loop_t* loop; + uv_fs_event_t* event; + + TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3); + + remove("watch_dir/"); + create_dir(uv_default_loop(), "watch_dir"); + + /* Create a lot of loops, and start FSEventStream in each of them. + * Eventually, this should create enough streams to make FSEventStreamStart() + * fail. + */ + for (i = 0; i < ARRAY_SIZE(loops); i++) { + loop = uv_loop_new(); + event = &events[i]; + ASSERT(loop != NULL); + + loops[i] = loop; + timer_cb_called = 0; + close_cb_called = 0; + ASSERT(0 == uv_fs_event_init(loop, event)); + ASSERT(0 == uv_fs_event_start(event, + fs_event_error_report_cb, + "watch_dir", + 0)); + uv_unref((uv_handle_t*) event); + + /* Let loop run for some time */ + ASSERT(0 == uv_timer_init(loop, &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0)); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(1 == timer_cb_called); + ASSERT(1 == close_cb_called); + if (fs_event_error_reported != 0) + break; + } + + /* At least one loop should fail */ + ASSERT(fs_event_error_reported == UV_EMFILE); + + /* Stop and close all events, and destroy loops */ + do { + loop = loops[i]; + event = &events[i]; + + ASSERT(0 == uv_fs_event_stop(event)); + uv_ref((uv_handle_t*) event); + uv_close((uv_handle_t*) event, fs_event_error_report_close_cb); + + close_cb_called = 0; + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(close_cb_called == 1); + + uv_loop_delete(loop); + + loops[i] = NULL; + } while (i-- != 0); + + remove("watch_dir/"); + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#else /* !defined(__APPLE__) */ + +TEST_IMPL(fs_event_error_reporting) { + /* No-op, needed only for FSEvents backend */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* defined(__APPLE__) */ diff --git a/test/test-fs-poll.c b/test/test-fs-poll.c new file mode 100644 index 0000000000..9213f04b34 --- /dev/null +++ b/test/test-fs-poll.c @@ -0,0 +1,146 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include + +#define FIXTURE "testfile" + +static void timer_cb(uv_timer_t* handle, int status); +static void close_cb(uv_handle_t* handle); +static void poll_cb(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr); + +static uv_fs_poll_t poll_handle; +static uv_timer_t timer_handle; +static uv_loop_t* loop; + +static int poll_cb_called; +static int timer_cb_called; +static int close_cb_called; + + +static void touch_file(const char* path) { + static int count; + FILE* fp; + int i; + + ASSERT((fp = fopen(FIXTURE, "w+"))); + + /* Need to change the file size because the poller may not pick up + * sub-second mtime changes. + */ + i = ++count; + + while (i--) + fputc('*', fp); + + fclose(fp); +} + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + touch_file(FIXTURE); + timer_cb_called++; +} + + +static void poll_cb(uv_fs_poll_t* handle, + int status, + const uv_stat_t* prev, + const uv_stat_t* curr) { + uv_stat_t zero_statbuf; + + memset(&zero_statbuf, 0, sizeof(zero_statbuf)); + + ASSERT(handle == &poll_handle); + ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + ASSERT(prev != NULL); + ASSERT(curr != NULL); + + switch (poll_cb_called++) { + case 0: + ASSERT(status == UV_ENOENT); + ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + touch_file(FIXTURE); + break; + + case 1: + ASSERT(status == 0); + ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0)); + break; + + case 2: + ASSERT(status == 0); + ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0)); + break; + + case 3: + ASSERT(status == 0); + ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + remove(FIXTURE); + break; + + case 4: + ASSERT(status == UV_ENOENT); + ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + uv_close((uv_handle_t*)handle, close_cb); + break; + + default: + ASSERT(0); + } +} + + +TEST_IMPL(fs_poll) { + loop = uv_default_loop(); + + remove(FIXTURE); + + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); + ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(poll_cb_called == 5); + ASSERT(timer_cb_called == 2); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-fs.c b/test/test-fs.c new file mode 100644 index 0000000000..f0ff824f40 --- /dev/null +++ b/test/test-fs.c @@ -0,0 +1,1955 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include /* memset */ +#include +#include + +/* FIXME we shouldn't need to branch in this file */ +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) +#include /* unlink, rmdir, etc. */ +#else +# include +# include +# define unlink _unlink +# define rmdir _rmdir +# define stat _stati64 +# define open _open +# define write _write +# define lseek _lseek +# define close _close +#endif + +#define TOO_LONG_NAME_LENGTH 65536 +#define PATHMAX 1024 + +typedef struct { + const char* path; + double atime; + double mtime; +} utime_check_t; + + +static int dummy_cb_count; +static int close_cb_count; +static int create_cb_count; +static int open_cb_count; +static int read_cb_count; +static int write_cb_count; +static int unlink_cb_count; +static int mkdir_cb_count; +static int rmdir_cb_count; +static int readdir_cb_count; +static int stat_cb_count; +static int rename_cb_count; +static int fsync_cb_count; +static int fdatasync_cb_count; +static int ftruncate_cb_count; +static int sendfile_cb_count; +static int fstat_cb_count; +static int chmod_cb_count; +static int fchmod_cb_count; +static int chown_cb_count; +static int fchown_cb_count; +static int link_cb_count; +static int symlink_cb_count; +static int readlink_cb_count; +static int utime_cb_count; +static int futime_cb_count; + +static uv_loop_t* loop; + +static uv_fs_t open_req1; +static uv_fs_t open_req2; +static uv_fs_t read_req; +static uv_fs_t write_req; +static uv_fs_t unlink_req; +static uv_fs_t close_req; +static uv_fs_t mkdir_req; +static uv_fs_t rmdir_req; +static uv_fs_t readdir_req; +static uv_fs_t stat_req; +static uv_fs_t rename_req; +static uv_fs_t fsync_req; +static uv_fs_t fdatasync_req; +static uv_fs_t ftruncate_req; +static uv_fs_t sendfile_req; +static uv_fs_t utime_req; +static uv_fs_t futime_req; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; + + +static void check_permission(const char* filename, unsigned int mode) { + int r; + uv_fs_t req; + uv_stat_t* s; + + r = uv_fs_stat(uv_default_loop(), &req, filename, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + + s = &req.statbuf; +#ifdef _WIN32 + /* + * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit, + * so only testing for the specified flags. + */ + ASSERT((s->st_mode & 0777) & mode); +#else + ASSERT((s->st_mode & 0777) == mode); +#endif + + uv_fs_req_cleanup(&req); +} + + +static void dummy_cb(uv_fs_t* req) { + (void) req; + dummy_cb_count++; +} + + +static void link_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_LINK); + ASSERT(req->result == 0); + link_cb_count++; + uv_fs_req_cleanup(req); +} + + +static void symlink_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_SYMLINK); + ASSERT(req->result == 0); + symlink_cb_count++; + uv_fs_req_cleanup(req); +} + +static void readlink_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_READLINK); + ASSERT(req->result == 0); + ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0); + readlink_cb_count++; + uv_fs_req_cleanup(req); +} + +static void fchmod_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_FCHMOD); + ASSERT(req->result == 0); + fchmod_cb_count++; + uv_fs_req_cleanup(req); + check_permission("test_file", *(int*)req->data); +} + + +static void chmod_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_CHMOD); + ASSERT(req->result == 0); + chmod_cb_count++; + uv_fs_req_cleanup(req); + check_permission("test_file", *(int*)req->data); +} + + +static void fchown_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_FCHOWN); + ASSERT(req->result == 0); + fchown_cb_count++; + uv_fs_req_cleanup(req); +} + + +static void chown_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_CHOWN); + ASSERT(req->result == 0); + chown_cb_count++; + uv_fs_req_cleanup(req); +} + +static void chown_root_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_CHOWN); +#ifdef _WIN32 + /* On windows, chown is a no-op and always succeeds. */ + ASSERT(req->result == 0); +#else + /* On unix, chown'ing the root directory is not allowed - + * unless you're root, of course. + */ + if (geteuid() == 0) + ASSERT(req->result == 0); + else + ASSERT(req->result == UV_EPERM); +#endif + chown_cb_count++; + uv_fs_req_cleanup(req); +} + +static void unlink_cb(uv_fs_t* req) { + ASSERT(req == &unlink_req); + ASSERT(req->fs_type == UV_FS_UNLINK); + ASSERT(req->result == 0); + unlink_cb_count++; + uv_fs_req_cleanup(req); +} + +static void fstat_cb(uv_fs_t* req) { + uv_stat_t* s = req->ptr; + ASSERT(req->fs_type == UV_FS_FSTAT); + ASSERT(req->result == 0); + ASSERT(s->st_size == sizeof(test_buf)); + uv_fs_req_cleanup(req); + fstat_cb_count++; +} + + +static void close_cb(uv_fs_t* req) { + int r; + ASSERT(req == &close_req); + ASSERT(req->fs_type == UV_FS_CLOSE); + ASSERT(req->result == 0); + close_cb_count++; + uv_fs_req_cleanup(req); + if (close_cb_count == 3) { + r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb); + ASSERT(r == 0); + } +} + + +static void ftruncate_cb(uv_fs_t* req) { + int r; + ASSERT(req == &ftruncate_req); + ASSERT(req->fs_type == UV_FS_FTRUNCATE); + ASSERT(req->result == 0); + ftruncate_cb_count++; + uv_fs_req_cleanup(req); + r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); + ASSERT(r == 0); +} + + +static void read_cb(uv_fs_t* req) { + int r; + ASSERT(req == &read_req); + ASSERT(req->fs_type == UV_FS_READ); + ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */ + read_cb_count++; + uv_fs_req_cleanup(req); + if (read_cb_count == 1) { + ASSERT(strcmp(buf, test_buf) == 0); + r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7, + ftruncate_cb); + } else { + ASSERT(strcmp(buf, "test-bu") == 0); + r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); + } + ASSERT(r == 0); +} + + +static void open_cb(uv_fs_t* req) { + int r; + ASSERT(req == &open_req1); + ASSERT(req->fs_type == UV_FS_OPEN); + if (req->result < 0) { + fprintf(stderr, "async open error: %d\n", (int) req->result); + ASSERT(0); + } + open_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_file2\0", 11) == 0); + uv_fs_req_cleanup(req); + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + read_cb); + ASSERT(r == 0); +} + + +static void open_cb_simple(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + if (req->result < 0) { + fprintf(stderr, "async open error: %d\n", (int) req->result); + ASSERT(0); + } + open_cb_count++; + ASSERT(req->path); + uv_fs_req_cleanup(req); +} + + +static void fsync_cb(uv_fs_t* req) { + int r; + ASSERT(req == &fsync_req); + ASSERT(req->fs_type == UV_FS_FSYNC); + ASSERT(req->result == 0); + fsync_cb_count++; + uv_fs_req_cleanup(req); + r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); + ASSERT(r == 0); +} + + +static void fdatasync_cb(uv_fs_t* req) { + int r; + ASSERT(req == &fdatasync_req); + ASSERT(req->fs_type == UV_FS_FDATASYNC); + ASSERT(req->result == 0); + fdatasync_cb_count++; + uv_fs_req_cleanup(req); + r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb); + ASSERT(r == 0); +} + + +static void write_cb(uv_fs_t* req) { + int r; + ASSERT(req == &write_req); + ASSERT(req->fs_type == UV_FS_WRITE); + ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */ + write_cb_count++; + uv_fs_req_cleanup(req); + r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb); + ASSERT(r == 0); +} + + +static void create_cb(uv_fs_t* req) { + int r; + ASSERT(req == &open_req1); + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->result >= 0); + create_cb_count++; + uv_fs_req_cleanup(req); + r = uv_fs_write(loop, &write_req, req->result, test_buf, sizeof(test_buf), + -1, write_cb); + ASSERT(r == 0); +} + + +static void rename_cb(uv_fs_t* req) { + ASSERT(req == &rename_req); + ASSERT(req->fs_type == UV_FS_RENAME); + ASSERT(req->result == 0); + rename_cb_count++; + uv_fs_req_cleanup(req); +} + + +static void mkdir_cb(uv_fs_t* req) { + ASSERT(req == &mkdir_req); + ASSERT(req->fs_type == UV_FS_MKDIR); + ASSERT(req->result == 0); + mkdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + uv_fs_req_cleanup(req); +} + + +static void rmdir_cb(uv_fs_t* req) { + ASSERT(req == &rmdir_req); + ASSERT(req->fs_type == UV_FS_RMDIR); + ASSERT(req->result == 0); + rmdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + uv_fs_req_cleanup(req); +} + + +static void readdir_cb(uv_fs_t* req) { + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT(req->result == 2); + ASSERT(req->ptr); + ASSERT(memcmp(req->ptr, "file1\0file2\0", 12) == 0 + || memcmp(req->ptr, "file2\0file1\0", 12) == 0); + readdir_cb_count++; + ASSERT(req->path); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + uv_fs_req_cleanup(req); + ASSERT(!req->ptr); +} + + +static void empty_readdir_cb(uv_fs_t* req) { + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT(req->result == 0); + ASSERT(req->ptr == NULL); + uv_fs_req_cleanup(req); + readdir_cb_count++; +} + + +static void file_readdir_cb(uv_fs_t* req) { + ASSERT(req == &readdir_req); + ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT(req->result == UV_ENOTDIR); + ASSERT(req->ptr == NULL); + uv_fs_req_cleanup(req); + readdir_cb_count++; +} + + +static void stat_cb(uv_fs_t* req) { + ASSERT(req == &stat_req); + ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT); + ASSERT(req->result == 0); + ASSERT(req->ptr); + stat_cb_count++; + uv_fs_req_cleanup(req); + ASSERT(!req->ptr); +} + + +static void sendfile_cb(uv_fs_t* req) { + ASSERT(req == &sendfile_req); + ASSERT(req->fs_type == UV_FS_SENDFILE); + ASSERT(req->result == 65546); + sendfile_cb_count++; + uv_fs_req_cleanup(req); +} + + +static void open_noent_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->result == UV_ENOENT); + open_cb_count++; + uv_fs_req_cleanup(req); +} + +static void open_nametoolong_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->result == UV_ENAMETOOLONG); + open_cb_count++; + uv_fs_req_cleanup(req); +} + +static void open_loop_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->result == UV_ELOOP); + open_cb_count++; + uv_fs_req_cleanup(req); +} + + +TEST_IMPL(fs_file_noent) { + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, NULL); + ASSERT(r == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 1); + + /* TODO add EACCES test */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_file_nametoolong) { + uv_fs_t req; + int r; + char name[TOO_LONG_NAME_LENGTH + 1]; + + loop = uv_default_loop(); + + memset(name, 'a', TOO_LONG_NAME_LENGTH); + name[TOO_LONG_NAME_LENGTH] = 0; + + r = uv_fs_open(loop, &req, name, O_RDONLY, 0, NULL); + ASSERT(r == UV_ENAMETOOLONG); + ASSERT(req.result == UV_ENAMETOOLONG); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_file_loop) { + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + unlink("test_symlink"); + uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL); + ASSERT(r == UV_ELOOP); + ASSERT(req.result == UV_ELOOP); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 1); + + unlink("test_symlink"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +static void check_utime(const char* path, double atime, double mtime) { + uv_stat_t* s; + uv_fs_t req; + int r; + + r = uv_fs_stat(loop, &req, path, NULL); + ASSERT(r == 0); + + ASSERT(req.result == 0); + s = &req.statbuf; + + ASSERT(s->st_atim.tv_sec == atime); + ASSERT(s->st_mtim.tv_sec == mtime); + + uv_fs_req_cleanup(&req); +} + + +static void utime_cb(uv_fs_t* req) { + utime_check_t* c; + + ASSERT(req == &utime_req); + ASSERT(req->result == 0); + ASSERT(req->fs_type == UV_FS_UTIME); + + c = req->data; + check_utime(c->path, c->atime, c->mtime); + + uv_fs_req_cleanup(req); + utime_cb_count++; +} + + +static void futime_cb(uv_fs_t* req) { + utime_check_t* c; + + ASSERT(req == &futime_req); + ASSERT(req->result == 0); + ASSERT(req->fs_type == UV_FS_FUTIME); + + c = req->data; + check_utime(c->path, c->atime, c->mtime); + + uv_fs_req_cleanup(req); + futime_cb_count++; +} + + +TEST_IMPL(fs_file_async) { + int r; + + /* Setup. */ + unlink("test_file"); + unlink("test_file2"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR, create_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(create_cb_count == 1); + ASSERT(write_cb_count == 1); + ASSERT(fsync_cb_count == 1); + ASSERT(fdatasync_cb_count == 1); + ASSERT(close_cb_count == 1); + + r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(create_cb_count == 1); + ASSERT(write_cb_count == 1); + ASSERT(close_cb_count == 1); + ASSERT(rename_cb_count == 1); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 1); + ASSERT(read_cb_count == 1); + ASSERT(close_cb_count == 2); + ASSERT(rename_cb_count == 1); + ASSERT(create_cb_count == 1); + ASSERT(write_cb_count == 1); + ASSERT(ftruncate_cb_count == 1); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 2); + ASSERT(read_cb_count == 2); + ASSERT(close_cb_count == 3); + ASSERT(rename_cb_count == 1); + ASSERT(unlink_cb_count == 1); + ASSERT(create_cb_count == 1); + ASSERT(write_cb_count == 1); + ASSERT(ftruncate_cb_count == 1); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file2"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_file_sync) { + int r; + + /* Setup. */ + unlink("test_file"); + unlink("test_file2"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + ASSERT(r >= 0); + ASSERT(read_req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7, NULL); + ASSERT(r == 0); + ASSERT(ftruncate_req.result == 0); + uv_fs_req_cleanup(&ftruncate_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", NULL); + ASSERT(r == 0); + ASSERT(rename_req.result == 0); + uv_fs_req_cleanup(&rename_req); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + ASSERT(r >= 0); + ASSERT(read_req.result >= 0); + ASSERT(strcmp(buf, "test-bu") == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_unlink(loop, &unlink_req, "test_file2", NULL); + ASSERT(r == 0); + ASSERT(unlink_req.result == 0); + uv_fs_req_cleanup(&unlink_req); + + /* Cleanup */ + unlink("test_file"); + unlink("test_file2"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_async_dir) { + int r; + + /* Setup */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(mkdir_cb_count == 1); + + /* Create 2 files synchronously. */ + r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, readdir_cb); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(readdir_cb_count == 1); + + /* sync uv_fs_readdir */ + r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, NULL); + ASSERT(r == 2); + ASSERT(readdir_req.result == 2); + ASSERT(readdir_req.ptr); + ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 + || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + uv_fs_req_cleanup(&readdir_req); + ASSERT(!readdir_req.ptr); + + r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(stat_cb_count == 4); + + r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(unlink_cb_count == 1); + + r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(unlink_cb_count == 2); + + r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(rmdir_cb_count == 1); + + /* Cleanup */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_async_sendfile) { + int f, r; + struct stat s1, s2; + + loop = uv_default_loop(); + + /* Setup. */ + unlink("test_file"); + unlink("test_file2"); + + f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR); + ASSERT(f != -1); + + r = write(f, "begin\n", 6); + ASSERT(r == 6); + + r = lseek(f, 65536, SEEK_CUR); + ASSERT(r == 65542); + + r = write(f, "end\n", 4); + ASSERT(r != -1); + + r = close(f); + ASSERT(r == 0); + + /* Test starts here. */ + r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_open(loop, &open_req2, "test_file2", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req2.result >= 0); + uv_fs_req_cleanup(&open_req2); + + r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result, + 0, 131072, sendfile_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(sendfile_cb_count == 1); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + r = uv_fs_close(loop, &close_req, open_req2.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + stat("test_file", &s1); + stat("test_file2", &s2); + ASSERT(65546 == s2.st_size && s1.st_size == s2.st_size); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file2"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_fstat) { + int r; + uv_fs_t req; + uv_file file; + uv_stat_t* s; +#ifndef _WIN32 + struct stat t; +#endif + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + r = uv_fs_fstat(loop, &req, file, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + s = req.ptr; + ASSERT(s->st_size == sizeof(test_buf)); + +#ifndef _WIN32 + r = fstat(file, &t); + ASSERT(r == 0); + + ASSERT(s->st_dev == (uint64_t) t.st_dev); + ASSERT(s->st_mode == (uint64_t) t.st_mode); + ASSERT(s->st_nlink == (uint64_t) t.st_nlink); + ASSERT(s->st_uid == (uint64_t) t.st_uid); + ASSERT(s->st_gid == (uint64_t) t.st_gid); + ASSERT(s->st_rdev == (uint64_t) t.st_rdev); + ASSERT(s->st_ino == (uint64_t) t.st_ino); + ASSERT(s->st_size == (uint64_t) t.st_size); + ASSERT(s->st_blksize == (uint64_t) t.st_blksize); + ASSERT(s->st_blocks == (uint64_t) t.st_blocks); +#if defined(__APPLE__) + ASSERT(s->st_atim.tv_sec == t.st_atimespec.tv_sec); + ASSERT(s->st_atim.tv_nsec == t.st_atimespec.tv_nsec); + ASSERT(s->st_mtim.tv_sec == t.st_mtimespec.tv_sec); + ASSERT(s->st_mtim.tv_nsec == t.st_mtimespec.tv_nsec); + ASSERT(s->st_ctim.tv_sec == t.st_ctimespec.tv_sec); + ASSERT(s->st_ctim.tv_nsec == t.st_ctimespec.tv_nsec); + ASSERT(s->st_birthtim.tv_sec == t.st_birthtimespec.tv_sec); + ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec); + ASSERT(s->st_flags == t.st_flags); + ASSERT(s->st_gen == t.st_gen); +#elif defined(__sun) || \ + defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || \ + defined(_XOPEN_SOURCE) + ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec); + ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec); + ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec); + ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec); + ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec); + ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec); +# if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec); + ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec); + ASSERT(s->st_flags == t.st_flags); + ASSERT(s->st_gen == t.st_gen); +# endif +#else + ASSERT(s->st_atim.tv_sec == t.st_atime); + ASSERT(s->st_atim.tv_nsec == 0); + ASSERT(s->st_mtim.tv_sec == t.st_mtime); + ASSERT(s->st_mtim.tv_nsec == 0); + ASSERT(s->st_ctim.tv_sec == t.st_ctime); + ASSERT(s->st_ctim.tv_nsec == 0); +#endif +#endif + + uv_fs_req_cleanup(&req); + + /* Now do the uv_fs_fstat call asynchronously */ + r = uv_fs_fstat(loop, &req, file, fstat_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(fstat_cb_count == 1); + + + r = uv_fs_close(loop, &req, file, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_chmod) { + int r; + uv_fs_t req; + uv_file file; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + +#ifndef _WIN32 + /* Make the file write-only */ + r = uv_fs_chmod(loop, &req, "test_file", 0200, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + check_permission("test_file", 0200); +#endif + + /* Make the file read-only */ + r = uv_fs_chmod(loop, &req, "test_file", 0400, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + check_permission("test_file", 0400); + + /* Make the file read+write with sync uv_fs_fchmod */ + r = uv_fs_fchmod(loop, &req, file, 0600, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + check_permission("test_file", 0600); + +#ifndef _WIN32 + /* async chmod */ + { + static int mode = 0200; + req.data = &mode; + } + r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chmod_cb_count == 1); + chmod_cb_count = 0; /* reset for the next test */ +#endif + + /* async chmod */ + { + static int mode = 0400; + req.data = &mode; + } + r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chmod_cb_count == 1); + + /* async fchmod */ + { + static int mode = 0600; + req.data = &mode; + } + r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(fchmod_cb_count == 1); + + close(file); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_chown) { + int r; + uv_fs_t req; + uv_file file; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + /* sync chown */ + r = uv_fs_chown(loop, &req, "test_file", -1, -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* sync fchown */ + r = uv_fs_fchown(loop, &req, file, -1, -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* async chown */ + r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chown_cb_count == 1); + + /* chown to root (fail) */ + chown_cb_count = 0; + r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chown_cb_count == 1); + + /* async fchown */ + r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(fchown_cb_count == 1); + + close(file); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_link) { + int r; + uv_fs_t req; + uv_file file; + uv_file link; + + /* Setup. */ + unlink("test_file"); + unlink("test_file_link"); + unlink("test_file_link2"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + close(file); + + /* sync link */ + r = uv_fs_link(loop, &req, "test_file", "test_file_link", NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_file_link", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + /* async link */ + r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(link_cb_count == 1); + + r = uv_fs_open(loop, &req, "test_file_link2", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file_link"); + unlink("test_file_link2"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_readlink) { + uv_fs_t req; + + loop = uv_default_loop(); + ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(dummy_cb_count == 1); + ASSERT(req.ptr == NULL); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + ASSERT(UV_ENOENT == uv_fs_readlink(loop, &req, "no_such_file", NULL)); + ASSERT(req.ptr == NULL); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_symlink) { + int r; + uv_fs_t req; + uv_file file; + uv_file link; + + /* Setup. */ + unlink("test_file"); + unlink("test_file_symlink"); + unlink("test_file_symlink2"); + unlink("test_file_symlink_symlink"); + unlink("test_file_symlink2_symlink"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + close(file); + + /* sync symlink */ + r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink", 0, NULL); +#ifdef _WIN32 + if (r < 0) { + if (r == UV_ENOTSUP) { + /* + * Windows doesn't support symlinks on older versions. + * We just pass the test and bail out early if we get ENOTSUP. + */ + return 0; + } else if (r == UV_EPERM) { + /* + * Creating a symlink is only allowed when running elevated. + * We pass the test and bail out early if we get UV_EPERM. + */ + return 0; + } + } +#endif + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_file_symlink", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + r = uv_fs_symlink(loop, + &req, + "test_file_symlink", + "test_file_symlink_symlink", + 0, + NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_readlink(loop, &req, "test_file_symlink_symlink", NULL); + ASSERT(r == 0); + ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); + uv_fs_req_cleanup(&req); + + /* async link */ + r = uv_fs_symlink(loop, + &req, + "test_file", + "test_file_symlink2", + 0, + symlink_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(symlink_cb_count == 1); + + r = uv_fs_open(loop, &req, "test_file_symlink2", O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + link = req.result; + uv_fs_req_cleanup(&req); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + + close(link); + + r = uv_fs_symlink(loop, + &req, + "test_file_symlink2", + "test_file_symlink2_symlink", + 0, + NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(readlink_cb_count == 1); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + unlink("test_file_symlink"); + unlink("test_file_symlink_symlink"); + unlink("test_file_symlink2"); + unlink("test_file_symlink2_symlink"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_symlink_dir) { + uv_fs_t req; + int r; + char* test_dir; + + /* set-up */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + rmdir("test_dir_symlink"); + + loop = uv_default_loop(); + + uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + +#ifdef _WIN32 + { + static char src_path_buf[PATHMAX]; + strcpy(src_path_buf, "\\\\?\\"); + uv_cwd(src_path_buf + 4, sizeof(src_path_buf)); + strcat(src_path_buf, "\\test_dir\\"); + test_dir = src_path_buf; + } +#else + test_dir = "test_dir"; +#endif + + r = uv_fs_symlink(loop, &req, test_dir, "test_dir_symlink", + UV_FS_SYMLINK_JUNCTION, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_stat(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK); +#ifdef _WIN32 + ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4)); +#else + ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir)); +#endif + uv_fs_req_cleanup(&req); + + r = uv_fs_readlink(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); +#ifdef _WIN32 + ASSERT(strcmp(req.ptr, test_dir + 4) == 0); +#else + ASSERT(strcmp(req.ptr, test_dir) == 0); +#endif + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL); + ASSERT(r == 2); + ASSERT(readdir_req.result == 2); + ASSERT(readdir_req.ptr); + ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 + || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + uv_fs_req_cleanup(&readdir_req); + ASSERT(!readdir_req.ptr); + + /* unlink will remove the directory symlink */ + r = uv_fs_unlink(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL); + ASSERT(r == UV_ENOENT); + uv_fs_req_cleanup(&readdir_req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, NULL); + ASSERT(r == 2); + ASSERT(readdir_req.result == 2); + ASSERT(readdir_req.ptr); + ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 + || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + uv_fs_req_cleanup(&readdir_req); + ASSERT(!readdir_req.ptr); + + /* clean-up */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + rmdir("test_dir_symlink"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_utime) { + utime_check_t checkme; + const char* path = "test_file"; + double atime; + double mtime; + uv_fs_t req; + int r; + + /* Setup. */ + loop = uv_default_loop(); + unlink(path); + r = uv_fs_open(loop, &req, path, O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + uv_fs_req_cleanup(&req); + close(r); + + atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + + r = uv_fs_utime(loop, &req, path, atime, mtime, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_stat(loop, &req, path, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + check_utime(path, atime, mtime); + uv_fs_req_cleanup(&req); + + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ + checkme.path = path; + checkme.atime = atime; + checkme.mtime = mtime; + + /* async utime */ + utime_req.data = &checkme; + r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(utime_cb_count == 1); + + /* Cleanup. */ + unlink(path); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#ifdef _WIN32 +TEST_IMPL(fs_stat_root) { + int r; + uv_loop_t* loop = uv_default_loop(); + + r = uv_fs_stat(loop, &stat_req, "\\", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..\\", NULL); + ASSERT(r == 0); + + /* stats the current directory on c: */ + r = uv_fs_stat(loop, &stat_req, "c:", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "\\\\?\\C:\\", NULL); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +TEST_IMPL(fs_futime) { + utime_check_t checkme; + const char* path = "test_file"; + double atime; + double mtime; + uv_file file; + uv_fs_t req; + int r; + + /* Setup. */ + loop = uv_default_loop(); + unlink(path); + r = uv_fs_open(loop, &req, path, O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + uv_fs_req_cleanup(&req); + close(r); + + atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + + r = uv_fs_open(loop, &req, path, O_RDWR, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; /* FIXME probably not how it's supposed to be used */ + uv_fs_req_cleanup(&req); + + r = uv_fs_futime(loop, &req, file, atime, mtime, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_stat(loop, &req, path, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + check_utime(path, atime, mtime); + uv_fs_req_cleanup(&req); + + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ + + checkme.atime = atime; + checkme.mtime = mtime; + checkme.path = path; + + /* async futime */ + futime_req.data = &checkme; + r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(futime_cb_count == 1); + + /* Cleanup. */ + unlink(path); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_stat_missing_path) { + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + r = uv_fs_stat(loop, &req, "non_existent_file", NULL); + ASSERT(r == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_readdir_empty_dir) { + const char* path; + uv_fs_t req; + int r; + + path = "./empty_dir/"; + loop = uv_default_loop(); + + uv_fs_mkdir(loop, &req, path, 0777, NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &req, path, 0, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + ASSERT(req.ptr == NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &readdir_req, path, 0, empty_readdir_cb); + ASSERT(r == 0); + + ASSERT(readdir_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(readdir_cb_count == 1); + + uv_fs_rmdir(loop, &req, path, NULL); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_readdir_file) { + const char* path; + int r; + + path = "test/fixtures/empty_file"; + loop = uv_default_loop(); + + r = uv_fs_readdir(loop, &readdir_req, path, 0, NULL); + ASSERT(r == UV_ENOTDIR); + uv_fs_req_cleanup(&readdir_req); + + r = uv_fs_readdir(loop, &readdir_req, path, 0, file_readdir_cb); + ASSERT(r == 0); + + ASSERT(readdir_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(readdir_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_open_dir) { + const char* path; + uv_fs_t req; + int r, file; + + path = "."; + loop = uv_default_loop(); + + r = uv_fs_open(loop, &req, path, O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + ASSERT(req.ptr == NULL); + file = r; + uv_fs_req_cleanup(&req); + + r = uv_fs_close(loop, &req, file, NULL); + ASSERT(r == 0); + + r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(open_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_file_open_append) { + int r; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + printf("read = %d\n", r); + ASSERT(r == 26); + ASSERT(read_req.result == 26); + ASSERT(memcmp(buf, + "test-buffer\n\0test-buffer\n\0", + sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_rename_to_existing_file) { + int r; + + /* Setup. */ + unlink("test_file"); + unlink("test_file2"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", NULL); + ASSERT(r == 0); + ASSERT(rename_req.result == 0); + uv_fs_req_cleanup(&rename_req); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + ASSERT(r >= 0); + ASSERT(read_req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + unlink("test_file2"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_read_file_eof) { + int r; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r >= 0); + ASSERT(write_req.result >= 0); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file", O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + ASSERT(r >= 0); + ASSERT(read_req.result >= 0); + ASSERT(strcmp(buf, test_buf) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), + read_req.result, NULL); + ASSERT(r == 0); + ASSERT(read_req.result == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-get-currentexe.c b/test/test-get-currentexe.c new file mode 100644 index 0000000000..be578db75d --- /dev/null +++ b/test/test-get-currentexe.c @@ -0,0 +1,65 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +extern char executable_path[]; + +TEST_IMPL(get_currentexe) { + char buffer[PATHMAX]; + size_t size; + char* match; + char* path; + int r; + + size = sizeof(buffer) / sizeof(buffer[0]); + r = uv_exepath(buffer, &size); + ASSERT(!r); + + /* uv_exepath can return an absolute path on darwin, so if the test runner + * was run with a relative prefix of "./", we need to strip that prefix off + * executable_path or we'll fail. */ + if (executable_path[0] == '.' && executable_path[1] == '/') { + path = executable_path + 2; + } else { + path = executable_path; + } + + match = strstr(buffer, path); + /* Verify that the path returned from uv_exepath is a subdirectory of + * executable_path. + */ + ASSERT(match && !strcmp(match, path)); + ASSERT(size == strlen(buffer)); + + /* Negative tests */ + size = sizeof(buffer) / sizeof(buffer[0]); + r = uv_exepath(NULL, &size); + ASSERT(r == UV_EINVAL); + + r = uv_exepath(buffer, NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/test/test-get-loadavg.c b/test/test-get-loadavg.c new file mode 100644 index 0000000000..7465e18b91 --- /dev/null +++ b/test/test-get-loadavg.c @@ -0,0 +1,36 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +TEST_IMPL(get_loadavg) { + + double avg[3]; + uv_loadavg(avg); + + ASSERT(avg != NULL); + ASSERT(avg[0] >= 0); + ASSERT(avg[1] >= 0); + ASSERT(avg[2] >= 0); + + return 0; +} diff --git a/test/test-get-memory.c b/test/test-get-memory.c new file mode 100644 index 0000000000..2396939bcb --- /dev/null +++ b/test/test-get-memory.c @@ -0,0 +1,38 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +TEST_IMPL(get_memory) { + uint64_t free_mem = uv_get_free_memory(); + uint64_t total_mem = uv_get_total_memory(); + + printf("free_mem=%llu, total_mem=%llu\n", + (unsigned long long) free_mem, + (unsigned long long) total_mem); + + ASSERT(free_mem > 0); + ASSERT(total_mem > 0); + ASSERT(total_mem > free_mem); + + return 0; +} diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c new file mode 100644 index 0000000000..bca2a6bd70 --- /dev/null +++ b/test/test-getaddrinfo.c @@ -0,0 +1,149 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#define CONCURRENT_COUNT 10 + +static const char* name = "localhost"; + +static int getaddrinfo_cbs = 0; + +/* data used for running multiple calls concurrently */ +static uv_getaddrinfo_t* getaddrinfo_handle; +static uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT]; +static int callback_counts[CONCURRENT_COUNT]; +static int fail_cb_called; + + +static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res) { + ASSERT(fail_cb_called == 0); + ASSERT(status < 0); + ASSERT(res == NULL); + uv_freeaddrinfo(res); /* Should not crash. */ + fail_cb_called++; +} + + +static void getaddrinfo_basic_cb(uv_getaddrinfo_t* handle, + int status, + struct addrinfo* res) { + ASSERT(handle == getaddrinfo_handle); + getaddrinfo_cbs++; + free(handle); + uv_freeaddrinfo(res); +} + + +static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, + int status, + struct addrinfo* res) { + int i; + int* data = (int*)handle->data; + + for (i = 0; i < CONCURRENT_COUNT; i++) { + if (&getaddrinfo_handles[i] == handle) { + ASSERT(i == *data); + + callback_counts[i]++; + break; + } + } + ASSERT (i < CONCURRENT_COUNT); + + free(data); + uv_freeaddrinfo(res); + + getaddrinfo_cbs++; +} + + +TEST_IMPL(getaddrinfo_fail) { + uv_getaddrinfo_t req; + + ASSERT(0 == uv_getaddrinfo(uv_default_loop(), + &req, + getaddrinfo_fail_cb, + "xyzzy.xyzzy.xyzzy", + NULL, + NULL)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(fail_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(getaddrinfo_basic) { + int r; + getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t)); + + r = uv_getaddrinfo(uv_default_loop(), + getaddrinfo_handle, + &getaddrinfo_basic_cb, + name, + NULL, + NULL); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(getaddrinfo_cbs == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(getaddrinfo_concurrent) { + int i, r; + int* data; + + for (i = 0; i < CONCURRENT_COUNT; i++) { + callback_counts[i] = 0; + + data = (int*)malloc(sizeof(int)); + *data = i; + getaddrinfo_handles[i].data = data; + + r = uv_getaddrinfo(uv_default_loop(), + &getaddrinfo_handles[i], + &getaddrinfo_cuncurrent_cb, + name, + NULL, + NULL); + ASSERT(r == 0); + } + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + for (i = 0; i < CONCURRENT_COUNT; i++) { + ASSERT(callback_counts[i] == 1); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-getsockname.c b/test/test-getsockname.c new file mode 100644 index 0000000000..a67d967f0b --- /dev/null +++ b/test/test-getsockname.c @@ -0,0 +1,358 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +static const int server_port = TEST_PORT; +/* Will be updated right after making the uv_connect_call */ +static int connect_port = -1; + +static int getsocknamecount = 0; +static int getpeernamecount = 0; + +static uv_loop_t* loop; +static uv_tcp_t tcp; +static uv_udp_t udp; +static uv_connect_t connect_req; +static uv_tcp_t tcpServer; +static uv_udp_t udpServer; +static uv_udp_send_t send_req; + + +static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +static void on_close(uv_handle_t* peer) { + free(peer); + uv_close((uv_handle_t*)&tcpServer, NULL); +} + + +static void after_shutdown(uv_shutdown_t* req, int status) { + uv_close((uv_handle_t*) req->handle, on_close); + free(req); +} + + +static void after_read(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + uv_shutdown_t* req; + int r; + + if (buf->base) { + free(buf->base); + } + + req = (uv_shutdown_t*) malloc(sizeof *req); + r = uv_shutdown(req, handle, after_shutdown); + ASSERT(r == 0); +} + + +static void check_sockname(struct sockaddr* addr, const char* compare_ip, + int compare_port, const char* context) { + struct sockaddr_in check_addr = *(struct sockaddr_in*) addr; + struct sockaddr_in compare_addr; + char check_ip[17]; + int r; + + ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr)); + + /* Both addresses should be ipv4 */ + ASSERT(check_addr.sin_family == AF_INET); + ASSERT(compare_addr.sin_family == AF_INET); + + /* Check if the ip matches */ + ASSERT(memcmp(&check_addr.sin_addr, + &compare_addr.sin_addr, + sizeof compare_addr.sin_addr) == 0); + + /* Check if the port matches. If port == 0 anything goes. */ + ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port); + + r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip); + ASSERT(r == 0); + + printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port)); +} + + +static void on_connection(uv_stream_t* server, int status) { + struct sockaddr sockname, peername; + int namelen; + uv_tcp_t* handle; + int r; + + if (status != 0) { + fprintf(stderr, "Connect error %s\n", uv_err_name(status)); + } + ASSERT(status == 0); + + handle = malloc(sizeof(*handle)); + ASSERT(handle != NULL); + + r = uv_tcp_init(loop, handle); + ASSERT(r == 0); + + /* associate server with stream */ + handle->data = server; + + r = uv_accept(server, (uv_stream_t*)handle); + ASSERT(r == 0); + + namelen = sizeof sockname; + r = uv_tcp_getsockname(handle, &sockname, &namelen); + ASSERT(r == 0); + check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket"); + getsocknamecount++; + + namelen = sizeof peername; + r = uv_tcp_getpeername(handle, &peername, &namelen); + ASSERT(r == 0); + check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer"); + getpeernamecount++; + + r = uv_read_start((uv_stream_t*)handle, alloc, after_read); + ASSERT(r == 0); +} + + +static void on_connect(uv_connect_t* req, int status) { + struct sockaddr sockname, peername; + int r, namelen; + + ASSERT(status == 0); + + namelen = sizeof sockname; + r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen); + ASSERT(r == 0); + check_sockname(&sockname, "127.0.0.1", 0, "connected socket"); + getsocknamecount++; + + namelen = sizeof peername; + r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen); + ASSERT(r == 0); + check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer"); + getpeernamecount++; + + uv_close((uv_handle_t*)&tcp, NULL); +} + + +static int tcp_listener(void) { + struct sockaddr_in addr; + struct sockaddr sockname, peername; + int namelen; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); + + r = uv_tcp_init(loop, &tcpServer); + if (r) { + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0); + if (r) { + fprintf(stderr, "Bind error\n"); + return 1; + } + + r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection); + if (r) { + fprintf(stderr, "Listen error\n"); + return 1; + } + + memset(&sockname, -1, sizeof sockname); + namelen = sizeof sockname; + r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen); + ASSERT(r == 0); + check_sockname(&sockname, "0.0.0.0", server_port, "server socket"); + getsocknamecount++; + + namelen = sizeof sockname; + r = uv_tcp_getpeername(&tcpServer, &peername, &namelen); + ASSERT(r == UV_ENOTCONN); + getpeernamecount++; + + return 0; +} + + +static void tcp_connector(void) { + struct sockaddr_in server_addr; + struct sockaddr sockname; + int r, namelen; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); + + r = uv_tcp_init(loop, &tcp); + tcp.data = &connect_req; + ASSERT(!r); + + r = uv_tcp_connect(&connect_req, + &tcp, + (const struct sockaddr*) &server_addr, + on_connect); + ASSERT(!r); + + /* Fetch the actual port used by the connecting socket. */ + namelen = sizeof sockname; + r = uv_tcp_getsockname(&tcp, &sockname, &namelen); + ASSERT(!r); + ASSERT(sockname.sa_family == AF_INET); + connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port); + ASSERT(connect_port > 0); +} + + +static void udp_recv(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + struct sockaddr sockname; + int namelen; + int r; + + ASSERT(nread >= 0); + free(buf->base); + + if (nread == 0) { + return; + } + + memset(&sockname, -1, sizeof sockname); + namelen = sizeof(sockname); + r = uv_udp_getsockname(&udp, &sockname, &namelen); + ASSERT(r == 0); + check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket"); + getsocknamecount++; + + uv_close((uv_handle_t*) &udp, NULL); + uv_close((uv_handle_t*) handle, NULL); +} + + +static void udp_send(uv_udp_send_t* req, int status) { + +} + + +static int udp_listener(void) { + struct sockaddr_in addr; + struct sockaddr sockname; + int namelen; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); + + r = uv_udp_init(loop, &udpServer); + if (r) { + fprintf(stderr, "Socket creation error\n"); + return 1; + } + + r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0); + if (r) { + fprintf(stderr, "Bind error\n"); + return 1; + } + + memset(&sockname, -1, sizeof sockname); + namelen = sizeof sockname; + r = uv_udp_getsockname(&udpServer, &sockname, &namelen); + ASSERT(r == 0); + check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket"); + getsocknamecount++; + + r = uv_udp_recv_start(&udpServer, alloc, udp_recv); + ASSERT(r == 0); + + return 0; +} + + +static void udp_sender(void) { + struct sockaddr_in server_addr; + uv_buf_t buf; + int r; + + r = uv_udp_init(loop, &udp); + ASSERT(!r); + + buf = uv_buf_init("PING", 4); + ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); + + r = uv_udp_send(&send_req, + &udp, + &buf, + 1, + (const struct sockaddr*) &server_addr, + udp_send); + ASSERT(!r); +} + + +TEST_IMPL(getsockname_tcp) { + loop = uv_default_loop(); + + if (tcp_listener()) + return 1; + + tcp_connector(); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(getsocknamecount == 3); + ASSERT(getpeernamecount == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(getsockname_udp) { + loop = uv_default_loop(); + + if (udp_listener()) + return 1; + + udp_sender(); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(getsocknamecount == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-hrtime.c b/test/test-hrtime.c new file mode 100644 index 0000000000..72a4d4b181 --- /dev/null +++ b/test/test-hrtime.c @@ -0,0 +1,54 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifndef MILLISEC +# define MILLISEC 1000 +#endif + +#ifndef NANOSEC +# define NANOSEC ((uint64_t) 1e9) +#endif + + +TEST_IMPL(hrtime) { + uint64_t a, b, diff; + int i = 75; + while (i > 0) { + a = uv_hrtime(); + uv_sleep(45); + b = uv_hrtime(); + + diff = b - a; + + /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */ + + /* The windows Sleep() function has only a resolution of 10-20 ms. */ + /* Check that the difference between the two hrtime values is somewhat in */ + /* the range we expect it to be. */ + ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC); + ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC); + --i; + } + return 0; +} diff --git a/test/test-idle.c b/test/test-idle.c new file mode 100644 index 0000000000..7eea1b83b1 --- /dev/null +++ b/test/test-idle.c @@ -0,0 +1,99 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +static uv_idle_t idle_handle; +static uv_check_t check_handle; +static uv_timer_t timer_handle; + +static int idle_cb_called = 0; +static int check_cb_called = 0; +static int timer_cb_called = 0; +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + + uv_close((uv_handle_t*) &idle_handle, close_cb); + uv_close((uv_handle_t*) &check_handle, close_cb); + uv_close((uv_handle_t*) &timer_handle, close_cb); + + timer_cb_called++; + LOGF("timer_cb %d\n", timer_cb_called); +} + + +static void idle_cb(uv_idle_t* handle, int status) { + ASSERT(handle == &idle_handle); + ASSERT(status == 0); + + idle_cb_called++; + LOGF("idle_cb %d\n", idle_cb_called); +} + + +static void check_cb(uv_check_t* handle, int status) { + ASSERT(handle == &check_handle); + ASSERT(status == 0); + + check_cb_called++; + LOGF("check_cb %d\n", check_cb_called); +} + + +TEST_IMPL(idle_starvation) { + int r; + + r = uv_idle_init(uv_default_loop(), &idle_handle); + ASSERT(r == 0); + r = uv_idle_start(&idle_handle, idle_cb); + ASSERT(r == 0); + + r = uv_check_init(uv_default_loop(), &check_handle); + ASSERT(r == 0); + r = uv_check_start(&check_handle, check_cb); + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &timer_handle); + ASSERT(r == 0); + r = uv_timer_start(&timer_handle, timer_cb, 50, 0); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(idle_cb_called > 0); + ASSERT(timer_cb_called == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-ip4-addr.c b/test/test-ip4-addr.c new file mode 100644 index 0000000000..3d6e0cf286 --- /dev/null +++ b/test/test-ip4-addr.c @@ -0,0 +1,46 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +TEST_IMPL(ip4_addr) { + + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr)); + ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr)); + ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr)); + ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr)); + ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr)); + + /* for broken address family */ + ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1", + &addr.sin_addr.s_addr)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c new file mode 100644 index 0000000000..ddd0812285 --- /dev/null +++ b/test/test-ip6-addr.c @@ -0,0 +1,99 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +#ifdef __linux__ +# include +# include +#endif + + +TEST_IMPL(ip6_addr_link_local) { +#ifdef UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS + char string_address[INET6_ADDRSTRLEN]; + uv_interface_address_t* addresses; + uv_interface_address_t* address; + struct sockaddr_in6 addr; + unsigned int iface_index; + const char* device_name; + /* 40 bytes address, 16 bytes device name, plus reserve. */ + char scoped_addr[128]; + int count; + int ix; + + ASSERT(0 == uv_interface_addresses(&addresses, &count)); + + for (ix = 0; ix < count; ix++) { + address = addresses + ix; + + if (address->address.address6.sin6_family != AF_INET6) + continue; + + ASSERT(0 == uv_inet_ntop(AF_INET6, + &address->address.address6.sin6_addr, + string_address, + sizeof(string_address))); + + /* Skip addresses that are not link-local. */ + if (strncmp(string_address, "fe80::", 6) != 0) + continue; + + iface_index = address->address.address6.sin6_scope_id; + device_name = address->name; + +#ifdef _WIN32 + snprintf(scoped_addr, + sizeof(scoped_addr), + "%s%%%d", + string_address, + iface_index); +#else + snprintf(scoped_addr, + sizeof(scoped_addr), + "%s%%%s", + string_address, + device_name); +#endif + + LOGF("Testing link-local address %s " + "(iface_index: 0x%02x, device_name: %s)\n", + scoped_addr, + iface_index, + device_name); + + ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr)); + LOGF("Got scope_id 0x%02x\n", addr.sin6_scope_id); + ASSERT(iface_index == addr.sin6_scope_id); + } + + uv_free_interface_addresses(addresses, count); + + MAKE_VALGRIND_HAPPY(); + return 0; +#else + RETURN_SKIP("Qualified link-local addresses are not supported."); +#endif +} diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c new file mode 100644 index 0000000000..b2b5aa0e92 --- /dev/null +++ b/test/test-ipc-send-recv.c @@ -0,0 +1,226 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +/* See test-ipc.ctx */ +void spawn_helper(uv_pipe_t* channel, + uv_process_t* process, + const char* helper); + +union handles { + uv_handle_t handle; + uv_stream_t stream; + uv_pipe_t pipe; + uv_tcp_t tcp; + uv_tty_t tty; +}; + +struct echo_ctx { + uv_pipe_t channel; + uv_write_t write_req; + uv_handle_type expected_type; + union handles send; + union handles recv; +}; + +static struct echo_ctx ctx; +static int num_recv_handles; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* we're not actually reading anything so a small buffer is okay */ + static char slab[8]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void recv_cb(uv_pipe_t* handle, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type pending) { + int r; + + ASSERT(pending == ctx.expected_type); + ASSERT(handle == &ctx.channel); + ASSERT(nread >= 0); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept((uv_stream_t*)&ctx.channel, &ctx.recv.stream); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&ctx.channel, NULL); + uv_close(&ctx.send.handle, NULL); + uv_close(&ctx.recv.handle, NULL); + num_recv_handles++; +} + + +static int run_test(void) { + uv_process_t process; + uv_buf_t buf; + int r; + + spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); + + buf = uv_buf_init(".", 1); + r = uv_write2(&ctx.write_req, + (uv_stream_t*)&ctx.channel, + &buf, 1, + &ctx.send.stream, + NULL); + ASSERT(r == 0); + + r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(num_recv_handles == 1); + + return 0; +} + + +TEST_IMPL(ipc_send_recv_pipe) { + int r; + + ctx.expected_type = UV_NAMED_PIPE; + + r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1); + ASSERT(r == 0); + + r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); + ASSERT(r == 0); + + r = run_test(); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(ipc_send_recv_tcp) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ctx.expected_type = UV_TCP; + + r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp); + ASSERT(r == 0); + + r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = run_test(); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +/* Everything here runs in a child process. */ + +static void write2_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + uv_close(&ctx.recv.handle, NULL); + uv_close((uv_handle_t*)&ctx.channel, NULL); +} + + +static void read2_cb(uv_pipe_t* handle, + ssize_t nread, + const uv_buf_t* rdbuf, + uv_handle_type pending) { + uv_buf_t wrbuf; + int r; + + ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); + ASSERT(handle == &ctx.channel); + ASSERT(nread >= 0); + + wrbuf = uv_buf_init(".", 1); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept((uv_stream_t*)handle, &ctx.recv.stream); + ASSERT(r == 0); + + r = uv_write2(&ctx.write_req, + (uv_stream_t*)&ctx.channel, + &wrbuf, + 1, + &ctx.recv.stream, + write2_cb); + ASSERT(r == 0); +} + + +/* stdin is a duplex channel over which a handle is sent. + * We receive it and send it back where it came from. + */ +int ipc_send_recv_helper(void) { + int r; + + memset(&ctx, 0, sizeof(ctx)); + + r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); + ASSERT(r == 0); + + uv_pipe_open(&ctx.channel, 0); + ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel)); + + r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, read2_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-ipc.c b/test/test-ipc.c new file mode 100644 index 0000000000..cc44d32e28 --- /dev/null +++ b/test/test-ipc.c @@ -0,0 +1,648 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +static uv_pipe_t channel; +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_connection; + +static int exit_cb_called; +static int read2_cb_called; +static int tcp_write_cb_called; +static int tcp_read_cb_called; +static int on_pipe_read_called; +static int local_conn_accepted; +static int remote_conn_accepted; +static int tcp_server_listening; +static uv_write_t write_req; +static uv_pipe_t channel; +static uv_tcp_t tcp_server; +static uv_write_t conn_notify_req; +static int close_cb_called; +static int connection_accepted; +static int tcp_conn_read_cb_called; +static int tcp_conn_write_cb_called; + +typedef struct { + uv_connect_t conn_req; + uv_write_t tcp_write_req; + uv_tcp_t conn; +} tcp_conn; + +#define CONN_COUNT 100 + + +static void close_server_conn_cb(uv_handle_t* handle) { + free(handle); +} + + +static void on_connection(uv_stream_t* server, int status) { + uv_tcp_t* conn; + int r; + + if (!local_conn_accepted) { + /* Accept the connection and close it. Also and close the server. */ + ASSERT(status == 0); + ASSERT((uv_stream_t*)&tcp_server == server); + + conn = malloc(sizeof(*conn)); + ASSERT(conn); + r = uv_tcp_init(server->loop, conn); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)conn); + ASSERT(r == 0); + + uv_close((uv_handle_t*)conn, close_server_conn_cb); + uv_close((uv_handle_t*)server, NULL); + local_conn_accepted = 1; + } +} + + +static void exit_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + printf("exit_cb\n"); + exit_cb_called++; + ASSERT(exit_status == 0); + uv_close((uv_handle_t*)process, NULL); +} + + +static void on_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +static void close_client_conn_cb(uv_handle_t* handle) { + tcp_conn* p = (tcp_conn*)handle->data; + free(p); +} + + +static void connect_cb(uv_connect_t* req, int status) { + uv_close((uv_handle_t*)req->handle, close_client_conn_cb); +} + + +static void make_many_connections(void) { + tcp_conn* conn; + struct sockaddr_in addr; + int r, i; + + for (i = 0; i < CONN_COUNT; i++) { + conn = malloc(sizeof(*conn)); + ASSERT(conn); + + r = uv_tcp_init(uv_default_loop(), &conn->conn); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_connect(&conn->conn_req, + (uv_tcp_t*) &conn->conn, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + conn->conn.data = conn; + } +} + + +static void on_read(uv_pipe_t* pipe, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type pending) { + int r; + uv_buf_t outbuf; + + if (nread == 0) { + /* Everything OK, but nothing read. */ + free(buf->base); + return; + } + + if (nread < 0) { + if (nread == UV_EOF) { + free(buf->base); + return; + } + + printf("error recving on channel: %s\n", uv_strerror(nread)); + abort(); + } + + fprintf(stderr, "got %d bytes\n", (int)nread); + + if (!tcp_server_listening) { + ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE); + read2_cb_called++; + + /* Accept the pending TCP server, and start listening on it. */ + ASSERT(pending == UV_TCP); + r = uv_tcp_init(uv_default_loop(), &tcp_server); + ASSERT(r == 0); + + r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&tcp_server, 12, on_connection); + ASSERT(r == 0); + + tcp_server_listening = 1; + + /* Make sure that the expected data is correctly multiplexed. */ + ASSERT(memcmp("hello\n", buf->base, nread) == 0); + + outbuf = uv_buf_init("world\n", 6); + r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL); + ASSERT(r == 0); + + /* Create a bunch of connections to get both servers to accept. */ + make_many_connections(); + } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) { + /* Remote server has accepted a connection. Close the channel. */ + ASSERT(pending == UV_UNKNOWN_HANDLE); + remote_conn_accepted = 1; + uv_close((uv_handle_t*)&channel, NULL); + } + + free(buf->base); +} + + +void spawn_helper(uv_pipe_t* channel, + uv_process_t* process, + const char* helper) { + uv_process_options_t options; + size_t exepath_size; + char exepath[1024]; + char* args[3]; + int r; + uv_stdio_container_t stdio[1]; + + r = uv_pipe_init(uv_default_loop(), channel, 1); + ASSERT(r == 0); + ASSERT(channel->ipc); + + exepath_size = sizeof(exepath); + r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + + exepath[exepath_size] = '\0'; + args[0] = exepath; + args[1] = (char*)helper; + args[2] = NULL; + + memset(&options, 0, sizeof(options)); + options.file = exepath; + options.args = args; + options.exit_cb = exit_cb; + + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | + UV_READABLE_PIPE | UV_WRITABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)channel; + options.stdio_count = 1; + + r = uv_spawn(uv_default_loop(), process, &options); + ASSERT(r == 0); +} + + +static void on_tcp_write(uv_write_t* req, int status) { + ASSERT(status == 0); + ASSERT(req->handle == (uv_stream_t*)&tcp_connection); + tcp_write_cb_called++; +} + + +static void on_read_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + ASSERT(nread > 0); + ASSERT(memcmp("hello again\n", buf->base, nread) == 0); + ASSERT(tcp == (uv_stream_t*)&tcp_connection); + free(buf->base); + + tcp_read_cb_called++; + + uv_close((uv_handle_t*)tcp, NULL); + uv_close((uv_handle_t*)&channel, NULL); +} + + +static void on_read_connection(uv_pipe_t* pipe, + ssize_t nread, + const uv_buf_t* buf, + uv_handle_type pending) { + int r; + uv_buf_t outbuf; + + if (nread == 0) { + /* Everything OK, but nothing read. */ + free(buf->base); + return; + } + + if (nread < 0) { + if (nread == UV_EOF) { + free(buf->base); + return; + } + + printf("error recving on channel: %s\n", uv_strerror(nread)); + abort(); + } + + fprintf(stderr, "got %d bytes\n", (int)nread); + + ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE); + read2_cb_called++; + + /* Accept the pending TCP connection */ + ASSERT(pending == UV_TCP); + r = uv_tcp_init(uv_default_loop(), &tcp_connection); + ASSERT(r == 0); + + r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_connection); + ASSERT(r == 0); + + /* Make sure that the expected data is correctly multiplexed. */ + ASSERT(memcmp("hello\n", buf->base, nread) == 0); + + /* Write/read to/from the connection */ + outbuf = uv_buf_init("world\n", 6); + r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1, + on_tcp_write); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read); + ASSERT(r == 0); + + free(buf->base); +} + + +static int run_ipc_test(const char* helper, uv_read2_cb read_cb) { + uv_process_t process; + int r; + + spawn_helper(&channel, &process, helper); + uv_read2_start((uv_stream_t*)&channel, on_alloc, read_cb); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(ipc_listen_before_write) { + int r = run_ipc_test("ipc_helper_listen_before_write", on_read); + ASSERT(local_conn_accepted == 1); + ASSERT(remote_conn_accepted == 1); + ASSERT(read2_cb_called == 1); + ASSERT(exit_cb_called == 1); + return r; +} + + +TEST_IMPL(ipc_listen_after_write) { + int r = run_ipc_test("ipc_helper_listen_after_write", on_read); + ASSERT(local_conn_accepted == 1); + ASSERT(remote_conn_accepted == 1); + ASSERT(read2_cb_called == 1); + ASSERT(exit_cb_called == 1); + return r; +} + + +TEST_IMPL(ipc_tcp_connection) { + int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection); + ASSERT(read2_cb_called == 1); + ASSERT(tcp_write_cb_called == 1); + ASSERT(tcp_read_cb_called == 1); + ASSERT(exit_cb_called == 1); + return r; +} + + +#ifdef _WIN32 +TEST_IMPL(listen_with_simultaneous_accepts) { + uv_tcp_t server; + int r; + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_tcp_simultaneous_accepts(&server, 1); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); + ASSERT(r == 0); + ASSERT(server.reqs_pending == 32); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(listen_no_simultaneous_accepts) { + uv_tcp_t server; + int r; + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_tcp_simultaneous_accepts(&server, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); + ASSERT(r == 0); + ASSERT(server.reqs_pending == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +/* Everything here runs in a child process. */ + +static tcp_conn conn; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void conn_notify_write_cb(uv_write_t* req, int status) { + uv_close((uv_handle_t*)&tcp_server, close_cb); + uv_close((uv_handle_t*)&channel, close_cb); +} + + +static void tcp_connection_write_cb(uv_write_t* req, int status) { + ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle); + uv_close((uv_handle_t*)req->handle, close_cb); + uv_close((uv_handle_t*)&channel, close_cb); + uv_close((uv_handle_t*)&tcp_server, close_cb); + tcp_conn_write_cb_called++; +} + + +static void on_tcp_child_process_read(uv_stream_t* tcp, + ssize_t nread, + const uv_buf_t* buf) { + uv_buf_t outbuf; + int r; + + if (nread < 0) { + if (nread == UV_EOF) { + free(buf->base); + return; + } + + printf("error recving on tcp connection: %s\n", uv_strerror(nread)); + abort(); + } + + ASSERT(nread > 0); + ASSERT(memcmp("world\n", buf->base, nread) == 0); + on_pipe_read_called++; + free(buf->base); + + /* Write to the socket */ + outbuf = uv_buf_init("hello again\n", 12); + r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb); + ASSERT(r == 0); + + tcp_conn_read_cb_called++; +} + + +static void connect_child_process_cb(uv_connect_t* req, int status) { + int r; + + ASSERT(status == 0); + r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read); + ASSERT(r == 0); +} + + +static void ipc_on_connection(uv_stream_t* server, int status) { + int r; + uv_buf_t buf; + + if (!connection_accepted) { + /* + * Accept the connection and close it. Also let the other + * side know. + */ + ASSERT(status == 0); + ASSERT((uv_stream_t*)&tcp_server == server); + + r = uv_tcp_init(server->loop, &conn.conn); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)&conn.conn); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&conn.conn, close_cb); + + buf = uv_buf_init("accepted_connection\n", 20); + r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, + NULL, conn_notify_write_cb); + ASSERT(r == 0); + + connection_accepted = 1; + } +} + + +static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) { + int r; + uv_buf_t buf; + uv_tcp_t* conn; + + ASSERT(status == 0); + ASSERT((uv_stream_t*)&tcp_server == server); + + conn = malloc(sizeof(*conn)); + ASSERT(conn); + + r = uv_tcp_init(server->loop, conn); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)conn); + ASSERT(r == 0); + + /* Send the accepted connection to the other process */ + buf = uv_buf_init("hello\n", 6); + r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, + (uv_stream_t*)conn, NULL); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) conn, + on_read_alloc, + on_tcp_child_process_read); + ASSERT(r == 0); + + uv_close((uv_handle_t*)conn, close_cb); +} + + +int ipc_helper(int listen_after_write) { + /* + * This is launched from test-ipc.c. stdin is a duplex channel that we + * over which a handle will be transmitted. + */ + struct sockaddr_in addr; + uv_write_t write_req; + int r; + uv_buf_t buf; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_pipe_init(uv_default_loop(), &channel, 1); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + r = uv_tcp_init(uv_default_loop(), &tcp_server); + ASSERT(r == 0); + + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + if (!listen_after_write) { + r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection); + ASSERT(r == 0); + } + + buf = uv_buf_init("hello\n", 6); + r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, + (uv_stream_t*)&tcp_server, NULL); + ASSERT(r == 0); + + if (listen_after_write) { + r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection); + ASSERT(r == 0); + } + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(connection_accepted == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +int ipc_helper_tcp_connection(void) { + /* + * This is launched from test-ipc.c. stdin is a duplex channel that we + * over which a handle will be transmitted. + */ + + int r; + struct sockaddr_in addr; + + r = uv_pipe_init(uv_default_loop(), &channel, 1); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + r = uv_tcp_init(uv_default_loop(), &tcp_server); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&tcp_server, 12, ipc_on_connection_tcp_conn); + ASSERT(r == 0); + + /* Make a connection to the server */ + r = uv_tcp_init(uv_default_loop(), &conn.conn); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_connect(&conn.conn_req, + (uv_tcp_t*) &conn.conn, + (const struct sockaddr*) &addr, + connect_child_process_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(tcp_conn_read_cb_called == 1); + ASSERT(tcp_conn_write_cb_called == 1); + ASSERT(close_cb_called == 4); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h new file mode 100644 index 0000000000..c3e15783b5 --- /dev/null +++ b/test/test-list.h @@ -0,0 +1,537 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +TEST_DECLARE (platform_output) +TEST_DECLARE (callback_order) +TEST_DECLARE (close_order) +TEST_DECLARE (run_once) +TEST_DECLARE (run_nowait) +TEST_DECLARE (loop_alive) +TEST_DECLARE (loop_stop) +TEST_DECLARE (loop_update_time) +TEST_DECLARE (barrier_1) +TEST_DECLARE (barrier_2) +TEST_DECLARE (barrier_3) +TEST_DECLARE (condvar_1) +TEST_DECLARE (condvar_2) +TEST_DECLARE (condvar_3) +TEST_DECLARE (condvar_4) +TEST_DECLARE (condvar_5) +TEST_DECLARE (semaphore_1) +TEST_DECLARE (semaphore_2) +TEST_DECLARE (semaphore_3) +TEST_DECLARE (tty) +TEST_DECLARE (stdio_over_pipes) +TEST_DECLARE (ipc_listen_before_write) +TEST_DECLARE (ipc_listen_after_write) +#ifndef _WIN32 +TEST_DECLARE (ipc_send_recv_pipe) +#endif +TEST_DECLARE (ipc_send_recv_tcp) +TEST_DECLARE (ipc_tcp_connection) +TEST_DECLARE (tcp_ping_pong) +TEST_DECLARE (tcp_ping_pong_v6) +TEST_DECLARE (pipe_ping_pong) +TEST_DECLARE (delayed_accept) +TEST_DECLARE (multiple_listen) +TEST_DECLARE (tcp_writealot) +TEST_DECLARE (tcp_try_write) +TEST_DECLARE (tcp_open) +TEST_DECLARE (tcp_connect_error_after_write) +TEST_DECLARE (tcp_shutdown_after_write) +TEST_DECLARE (tcp_bind_error_addrinuse) +TEST_DECLARE (tcp_bind_error_addrnotavail_1) +TEST_DECLARE (tcp_bind_error_addrnotavail_2) +TEST_DECLARE (tcp_bind_error_fault) +TEST_DECLARE (tcp_bind_error_inval) +TEST_DECLARE (tcp_bind_localhost_ok) +TEST_DECLARE (tcp_listen_without_bind) +TEST_DECLARE (tcp_connect_error_fault) +TEST_DECLARE (tcp_connect_timeout) +TEST_DECLARE (tcp_close_while_connecting) +TEST_DECLARE (tcp_close) +TEST_DECLARE (tcp_close_accept) +TEST_DECLARE (tcp_flags) +TEST_DECLARE (tcp_write_to_half_open_connection) +TEST_DECLARE (tcp_unexpected_read) +TEST_DECLARE (tcp_read_stop) +TEST_DECLARE (tcp_bind6_error_addrinuse) +TEST_DECLARE (tcp_bind6_error_addrnotavail) +TEST_DECLARE (tcp_bind6_error_fault) +TEST_DECLARE (tcp_bind6_error_inval) +TEST_DECLARE (tcp_bind6_localhost_ok) +TEST_DECLARE (udp_send_and_recv) +TEST_DECLARE (udp_multicast_join) +TEST_DECLARE (udp_multicast_ttl) +TEST_DECLARE (udp_dgram_too_big) +TEST_DECLARE (udp_dual_stack) +TEST_DECLARE (udp_ipv6_only) +TEST_DECLARE (udp_options) +TEST_DECLARE (udp_open) +TEST_DECLARE (pipe_bind_error_addrinuse) +TEST_DECLARE (pipe_bind_error_addrnotavail) +TEST_DECLARE (pipe_bind_error_inval) +TEST_DECLARE (pipe_listen_without_bind) +TEST_DECLARE (pipe_connect_bad_name) +TEST_DECLARE (pipe_connect_to_file) +TEST_DECLARE (pipe_server_close) +TEST_DECLARE (connection_fail) +TEST_DECLARE (connection_fail_doesnt_auto_close) +TEST_DECLARE (shutdown_close_tcp) +TEST_DECLARE (shutdown_close_pipe) +TEST_DECLARE (shutdown_eof) +TEST_DECLARE (callback_stack) +TEST_DECLARE (error_message) +TEST_DECLARE (timer) +TEST_DECLARE (timer_init) +TEST_DECLARE (timer_again) +TEST_DECLARE (timer_start_twice) +TEST_DECLARE (timer_order) +TEST_DECLARE (timer_huge_timeout) +TEST_DECLARE (timer_huge_repeat) +TEST_DECLARE (timer_run_once) +TEST_DECLARE (timer_from_check) +TEST_DECLARE (idle_starvation) +TEST_DECLARE (loop_handles) +TEST_DECLARE (get_loadavg) +TEST_DECLARE (walk_handles) +TEST_DECLARE (watcher_cross_stop) +TEST_DECLARE (ref) +TEST_DECLARE (idle_ref) +TEST_DECLARE (async_ref) +TEST_DECLARE (prepare_ref) +TEST_DECLARE (check_ref) +TEST_DECLARE (unref_in_prepare_cb) +TEST_DECLARE (timer_ref) +TEST_DECLARE (timer_ref2) +TEST_DECLARE (fs_event_ref) +TEST_DECLARE (fs_poll_ref) +TEST_DECLARE (tcp_ref) +TEST_DECLARE (tcp_ref2) +TEST_DECLARE (tcp_ref2b) +TEST_DECLARE (tcp_ref3) +TEST_DECLARE (tcp_ref4) +TEST_DECLARE (udp_ref) +TEST_DECLARE (udp_ref2) +TEST_DECLARE (udp_ref3) +TEST_DECLARE (pipe_ref) +TEST_DECLARE (pipe_ref2) +TEST_DECLARE (pipe_ref3) +TEST_DECLARE (pipe_ref4) +TEST_DECLARE (process_ref) +TEST_DECLARE (has_ref) +TEST_DECLARE (active) +TEST_DECLARE (embed) +TEST_DECLARE (async) +TEST_DECLARE (async_null_cb) +TEST_DECLARE (get_currentexe) +TEST_DECLARE (process_title) +TEST_DECLARE (cwd_and_chdir) +TEST_DECLARE (get_memory) +TEST_DECLARE (hrtime) +TEST_DECLARE (getaddrinfo_fail) +TEST_DECLARE (getaddrinfo_basic) +TEST_DECLARE (getaddrinfo_concurrent) +TEST_DECLARE (getsockname_tcp) +TEST_DECLARE (getsockname_udp) +TEST_DECLARE (fail_always) +TEST_DECLARE (pass_always) +TEST_DECLARE (spawn_fails) +TEST_DECLARE (spawn_exit_code) +TEST_DECLARE (spawn_stdout) +TEST_DECLARE (spawn_stdin) +TEST_DECLARE (spawn_stdio_greater_than_3) +TEST_DECLARE (spawn_ignored_stdio) +TEST_DECLARE (spawn_and_kill) +TEST_DECLARE (spawn_detached) +TEST_DECLARE (spawn_and_kill_with_std) +TEST_DECLARE (spawn_and_ping) +TEST_DECLARE (spawn_preserve_env) +TEST_DECLARE (spawn_setuid_fails) +TEST_DECLARE (spawn_setgid_fails) +TEST_DECLARE (spawn_stdout_to_file) +TEST_DECLARE (spawn_stdout_and_stderr_to_file) +TEST_DECLARE (spawn_auto_unref) +TEST_DECLARE (fs_poll) +TEST_DECLARE (kill) +TEST_DECLARE (fs_file_noent) +TEST_DECLARE (fs_file_nametoolong) +TEST_DECLARE (fs_file_loop) +TEST_DECLARE (fs_file_async) +TEST_DECLARE (fs_file_sync) +TEST_DECLARE (fs_async_dir) +TEST_DECLARE (fs_async_sendfile) +TEST_DECLARE (fs_fstat) +TEST_DECLARE (fs_chmod) +TEST_DECLARE (fs_chown) +TEST_DECLARE (fs_link) +TEST_DECLARE (fs_readlink) +TEST_DECLARE (fs_symlink) +TEST_DECLARE (fs_symlink_dir) +TEST_DECLARE (fs_utime) +TEST_DECLARE (fs_futime) +TEST_DECLARE (fs_file_open_append) +TEST_DECLARE (fs_stat_missing_path) +TEST_DECLARE (fs_read_file_eof) +TEST_DECLARE (fs_event_watch_dir) +TEST_DECLARE (fs_event_watch_file) +TEST_DECLARE (fs_event_watch_file_twice) +TEST_DECLARE (fs_event_watch_file_current_dir) +TEST_DECLARE (fs_event_no_callback_after_close) +TEST_DECLARE (fs_event_no_callback_on_close) +TEST_DECLARE (fs_event_immediate_close) +TEST_DECLARE (fs_event_close_with_pending_event) +TEST_DECLARE (fs_event_close_in_callback) +TEST_DECLARE (fs_event_start_and_close) +TEST_DECLARE (fs_event_error_reporting) +TEST_DECLARE (fs_readdir_empty_dir) +TEST_DECLARE (fs_readdir_file) +TEST_DECLARE (fs_open_dir) +TEST_DECLARE (fs_rename_to_existing_file) +TEST_DECLARE (threadpool_queue_work_simple) +TEST_DECLARE (threadpool_queue_work_einval) +TEST_DECLARE (threadpool_multiple_event_loops) +TEST_DECLARE (threadpool_cancel_getaddrinfo) +TEST_DECLARE (threadpool_cancel_work) +TEST_DECLARE (threadpool_cancel_fs) +TEST_DECLARE (threadpool_cancel_single) +TEST_DECLARE (thread_local_storage) +TEST_DECLARE (thread_mutex) +TEST_DECLARE (thread_rwlock) +TEST_DECLARE (thread_create) +TEST_DECLARE (dlerror) +TEST_DECLARE (poll_duplex) +TEST_DECLARE (poll_unidirectional) +TEST_DECLARE (poll_close) +TEST_DECLARE (ip4_addr) +TEST_DECLARE (ip6_addr_link_local) +#ifdef _WIN32 +TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) +TEST_DECLARE (argument_escaping) +TEST_DECLARE (environment_creation) +TEST_DECLARE (listen_with_simultaneous_accepts) +TEST_DECLARE (listen_no_simultaneous_accepts) +TEST_DECLARE (fs_stat_root) +#else +TEST_DECLARE (emfile) +TEST_DECLARE (close_fd) +TEST_DECLARE (spawn_setuid_setgid) +TEST_DECLARE (we_get_signal) +TEST_DECLARE (we_get_signals) +TEST_DECLARE (signal_multiple_loops) +#endif +#ifdef __APPLE__ +TEST_DECLARE (osx_select) +#endif +HELPER_DECLARE (tcp4_echo_server) +HELPER_DECLARE (tcp6_echo_server) +HELPER_DECLARE (udp4_echo_server) +HELPER_DECLARE (pipe_echo_server) + + +TASK_LIST_START + TEST_OUTPUT_ENTRY (platform_output) + +#if 0 + TEST_ENTRY (callback_order) +#endif + TEST_ENTRY (close_order) + TEST_ENTRY (run_once) + TEST_ENTRY (run_nowait) + TEST_ENTRY (loop_alive) + TEST_ENTRY (loop_stop) + TEST_ENTRY (loop_update_time) + TEST_ENTRY (barrier_1) + TEST_ENTRY (barrier_2) + TEST_ENTRY (barrier_3) + TEST_ENTRY (condvar_1) + TEST_ENTRY (condvar_2) + TEST_ENTRY (condvar_3) + TEST_ENTRY (condvar_4) + TEST_ENTRY (condvar_5) + TEST_ENTRY (semaphore_1) + TEST_ENTRY (semaphore_2) + TEST_ENTRY (semaphore_3) + + TEST_ENTRY (pipe_connect_bad_name) + TEST_ENTRY (pipe_connect_to_file) + + TEST_ENTRY (pipe_server_close) + TEST_ENTRY (tty) + TEST_ENTRY (stdio_over_pipes) + TEST_ENTRY (ipc_listen_before_write) + TEST_ENTRY (ipc_listen_after_write) +#ifndef _WIN32 + TEST_ENTRY (ipc_send_recv_pipe) +#endif + TEST_ENTRY (ipc_send_recv_tcp) + TEST_ENTRY (ipc_tcp_connection) + + TEST_ENTRY (tcp_ping_pong) + TEST_HELPER (tcp_ping_pong, tcp4_echo_server) + + TEST_ENTRY (tcp_ping_pong_v6) + TEST_HELPER (tcp_ping_pong_v6, tcp6_echo_server) + + TEST_ENTRY (pipe_ping_pong) + TEST_HELPER (pipe_ping_pong, pipe_echo_server) + + TEST_ENTRY (delayed_accept) + TEST_ENTRY (multiple_listen) + + TEST_ENTRY (tcp_writealot) + TEST_HELPER (tcp_writealot, tcp4_echo_server) + + TEST_ENTRY (tcp_try_write) + + TEST_ENTRY (tcp_open) + TEST_HELPER (tcp_open, tcp4_echo_server) + + TEST_ENTRY (tcp_shutdown_after_write) + TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server) + + TEST_ENTRY (tcp_connect_error_after_write) + TEST_ENTRY (tcp_bind_error_addrinuse) + TEST_ENTRY (tcp_bind_error_addrnotavail_1) + TEST_ENTRY (tcp_bind_error_addrnotavail_2) + TEST_ENTRY (tcp_bind_error_fault) + TEST_ENTRY (tcp_bind_error_inval) + TEST_ENTRY (tcp_bind_localhost_ok) + TEST_ENTRY (tcp_listen_without_bind) + TEST_ENTRY (tcp_connect_error_fault) + TEST_ENTRY (tcp_connect_timeout) + TEST_ENTRY (tcp_close_while_connecting) + TEST_ENTRY (tcp_close) + TEST_ENTRY (tcp_close_accept) + TEST_ENTRY (tcp_flags) + TEST_ENTRY (tcp_write_to_half_open_connection) + TEST_ENTRY (tcp_unexpected_read) + + TEST_ENTRY (tcp_read_stop) + TEST_HELPER (tcp_read_stop, tcp4_echo_server) + + TEST_ENTRY (tcp_bind6_error_addrinuse) + TEST_ENTRY (tcp_bind6_error_addrnotavail) + TEST_ENTRY (tcp_bind6_error_fault) + TEST_ENTRY (tcp_bind6_error_inval) + TEST_ENTRY (tcp_bind6_localhost_ok) + + TEST_ENTRY (udp_send_and_recv) + TEST_ENTRY (udp_dgram_too_big) + TEST_ENTRY (udp_dual_stack) + TEST_ENTRY (udp_ipv6_only) + TEST_ENTRY (udp_options) + TEST_ENTRY (udp_multicast_join) + TEST_ENTRY (udp_multicast_ttl) + + TEST_ENTRY (udp_open) + TEST_HELPER (udp_open, udp4_echo_server) + + TEST_ENTRY (pipe_bind_error_addrinuse) + TEST_ENTRY (pipe_bind_error_addrnotavail) + TEST_ENTRY (pipe_bind_error_inval) + TEST_ENTRY (pipe_listen_without_bind) + + TEST_ENTRY (connection_fail) + TEST_ENTRY (connection_fail_doesnt_auto_close) + + TEST_ENTRY (shutdown_close_tcp) + TEST_HELPER (shutdown_close_tcp, tcp4_echo_server) + TEST_ENTRY (shutdown_close_pipe) + TEST_HELPER (shutdown_close_pipe, pipe_echo_server) + + TEST_ENTRY (shutdown_eof) + TEST_HELPER (shutdown_eof, tcp4_echo_server) + + TEST_ENTRY (callback_stack) + TEST_HELPER (callback_stack, tcp4_echo_server) + + TEST_ENTRY (error_message) + + TEST_ENTRY (timer) + TEST_ENTRY (timer_init) + TEST_ENTRY (timer_again) + TEST_ENTRY (timer_start_twice) + TEST_ENTRY (timer_order) + TEST_ENTRY (timer_huge_timeout) + TEST_ENTRY (timer_huge_repeat) + TEST_ENTRY (timer_run_once) + TEST_ENTRY (timer_from_check) + + TEST_ENTRY (idle_starvation) + + TEST_ENTRY (ref) + TEST_ENTRY (idle_ref) + TEST_ENTRY (fs_poll_ref) + TEST_ENTRY (async_ref) + TEST_ENTRY (prepare_ref) + TEST_ENTRY (check_ref) + TEST_ENTRY (unref_in_prepare_cb) + TEST_ENTRY (timer_ref) + TEST_ENTRY (timer_ref2) + TEST_ENTRY (fs_event_ref) + TEST_ENTRY (tcp_ref) + TEST_ENTRY (tcp_ref2) + TEST_ENTRY (tcp_ref2b) + TEST_ENTRY (tcp_ref3) + TEST_HELPER (tcp_ref3, tcp4_echo_server) + TEST_ENTRY (tcp_ref4) + TEST_HELPER (tcp_ref4, tcp4_echo_server) + TEST_ENTRY (udp_ref) + TEST_ENTRY (udp_ref2) + TEST_ENTRY (udp_ref3) + TEST_HELPER (udp_ref3, udp4_echo_server) + TEST_ENTRY (pipe_ref) + TEST_ENTRY (pipe_ref2) + TEST_ENTRY (pipe_ref3) + TEST_HELPER (pipe_ref3, pipe_echo_server) + TEST_ENTRY (pipe_ref4) + TEST_HELPER (pipe_ref4, pipe_echo_server) + TEST_ENTRY (process_ref) + TEST_ENTRY (has_ref) + + TEST_ENTRY (loop_handles) + TEST_ENTRY (walk_handles) + + TEST_ENTRY (watcher_cross_stop) + + TEST_ENTRY (active) + + TEST_ENTRY (embed) + + TEST_ENTRY (async) + TEST_ENTRY (async_null_cb) + + TEST_ENTRY (get_currentexe) + + TEST_ENTRY (process_title) + + TEST_ENTRY (cwd_and_chdir) + + TEST_ENTRY (get_memory) + + TEST_ENTRY (get_loadavg) + + TEST_ENTRY (hrtime) + + TEST_ENTRY (getaddrinfo_fail) + TEST_ENTRY (getaddrinfo_basic) + TEST_ENTRY (getaddrinfo_concurrent) + + TEST_ENTRY (getsockname_tcp) + TEST_ENTRY (getsockname_udp) + + TEST_ENTRY (poll_duplex) + TEST_ENTRY (poll_unidirectional) + TEST_ENTRY (poll_close) + + TEST_ENTRY (spawn_fails) + TEST_ENTRY (spawn_exit_code) + TEST_ENTRY (spawn_stdout) + TEST_ENTRY (spawn_stdin) + TEST_ENTRY (spawn_stdio_greater_than_3) + TEST_ENTRY (spawn_ignored_stdio) + TEST_ENTRY (spawn_and_kill) + TEST_ENTRY (spawn_detached) + TEST_ENTRY (spawn_and_kill_with_std) + TEST_ENTRY (spawn_and_ping) + TEST_ENTRY (spawn_preserve_env) + TEST_ENTRY (spawn_setuid_fails) + TEST_ENTRY (spawn_setgid_fails) + TEST_ENTRY (spawn_stdout_to_file) + TEST_ENTRY (spawn_stdout_and_stderr_to_file) + TEST_ENTRY (spawn_auto_unref) + TEST_ENTRY (fs_poll) + TEST_ENTRY (kill) + +#ifdef _WIN32 + TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) + TEST_ENTRY (argument_escaping) + TEST_ENTRY (environment_creation) + TEST_ENTRY (listen_with_simultaneous_accepts) + TEST_ENTRY (listen_no_simultaneous_accepts) + TEST_ENTRY (fs_stat_root) +#else + TEST_ENTRY (emfile) + TEST_ENTRY (close_fd) + TEST_ENTRY (spawn_setuid_setgid) + TEST_ENTRY (we_get_signal) + TEST_ENTRY (we_get_signals) + TEST_ENTRY (signal_multiple_loops) +#endif + +#ifdef __APPLE__ + TEST_ENTRY (osx_select) +#endif + + TEST_ENTRY (fs_file_noent) + TEST_ENTRY (fs_file_nametoolong) + TEST_ENTRY (fs_file_loop) + TEST_ENTRY (fs_file_async) + TEST_ENTRY (fs_file_sync) + TEST_ENTRY (fs_async_dir) + TEST_ENTRY (fs_async_sendfile) + TEST_ENTRY (fs_fstat) + TEST_ENTRY (fs_chmod) + TEST_ENTRY (fs_chown) + TEST_ENTRY (fs_utime) + TEST_ENTRY (fs_futime) + TEST_ENTRY (fs_readlink) + TEST_ENTRY (fs_symlink) + TEST_ENTRY (fs_symlink_dir) + TEST_ENTRY (fs_stat_missing_path) + TEST_ENTRY (fs_read_file_eof) + TEST_ENTRY (fs_file_open_append) + TEST_ENTRY (fs_event_watch_dir) + TEST_ENTRY (fs_event_watch_file) + TEST_ENTRY (fs_event_watch_file_twice) + TEST_ENTRY (fs_event_watch_file_current_dir) + TEST_ENTRY (fs_event_no_callback_after_close) + TEST_ENTRY (fs_event_no_callback_on_close) + TEST_ENTRY (fs_event_immediate_close) + TEST_ENTRY (fs_event_close_with_pending_event) + TEST_ENTRY (fs_event_close_in_callback) + TEST_ENTRY (fs_event_start_and_close) + TEST_ENTRY (fs_event_error_reporting) + TEST_ENTRY (fs_readdir_empty_dir) + TEST_ENTRY (fs_readdir_file) + TEST_ENTRY (fs_open_dir) + TEST_ENTRY (fs_rename_to_existing_file) + TEST_ENTRY (threadpool_queue_work_simple) + TEST_ENTRY (threadpool_queue_work_einval) + TEST_ENTRY (threadpool_multiple_event_loops) + TEST_ENTRY (threadpool_cancel_getaddrinfo) + TEST_ENTRY (threadpool_cancel_work) + TEST_ENTRY (threadpool_cancel_fs) + TEST_ENTRY (threadpool_cancel_single) + TEST_ENTRY (thread_local_storage) + TEST_ENTRY (thread_mutex) + TEST_ENTRY (thread_rwlock) + TEST_ENTRY (thread_create) + TEST_ENTRY (dlerror) + TEST_ENTRY (ip4_addr) + TEST_ENTRY (ip6_addr_link_local) +#if 0 + /* These are for testing the test runner. */ + TEST_ENTRY (fail_always) + TEST_ENTRY (pass_always) +#endif +TASK_LIST_END diff --git a/test/test-loop-alive.c b/test/test-loop-alive.c new file mode 100644 index 0000000000..89243357c3 --- /dev/null +++ b/test/test-loop-alive.c @@ -0,0 +1,68 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer_handle; + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle); + ASSERT(status == 0); +} + + +static uv_work_t work_req; + +static void work_cb(uv_work_t* req) { + ASSERT(req); +} + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT(req); + ASSERT(status == 0); +} + + +TEST_IMPL(loop_alive) { + int r; + ASSERT(!uv_loop_alive(uv_default_loop())); + + /* loops with handles are alive */ + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 0); + ASSERT(uv_loop_alive(uv_default_loop())); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(!uv_loop_alive(uv_default_loop())); + + /* loops with requests are alive */ + r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb); + ASSERT(r == 0); + ASSERT(uv_loop_alive(uv_default_loop())); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(!uv_loop_alive(uv_default_loop())); + + return 0; +} diff --git a/test/test-loop-handles.c b/test/test-loop-handles.c new file mode 100644 index 0000000000..fdf9281478 --- /dev/null +++ b/test/test-loop-handles.c @@ -0,0 +1,337 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Tests commented out with XXX are ones that are failing on Linux */ + +/* + * Purpose of this test is to check semantics of starting and stopping + * prepare, check and idle watchers. + * + * - A watcher must be able to safely stop or close itself; + * - Once a watcher is stopped or closed its callback should never be called. + * - If a watcher is closed, it is implicitly stopped and its close_cb should + * be called exactly once. + * - A watcher can safely start and stop other watchers of the same type. + * - Prepare and check watchers are called once per event loop iterations. + * - All active idle watchers are queued when the event loop has no more work + * to do. This is done repeatedly until all idle watchers are inactive. + * - If a watcher starts another watcher of the same type its callback is not + * immediately queued. For check and prepare watchers, that means that if + * a watcher makes another of the same type active, it'll not be called until + * the next event loop iteration. For idle. watchers this means that the + * newly activated idle watcher might not be queued immediately. + * - Prepare, check, idle watchers keep the event loop alive even when they're + * not active. + * + * This is what the test globally does: + * + * - prepare_1 is always active and counts event loop iterations. It also + * creates and starts prepare_2 every other iteration. Finally it verifies + * that no idle watchers are active before polling. + * - prepare_2 is started by prepare_1 every other iteration. It immediately + * stops itself. It verifies that a watcher is not queued immediately + * if created by another watcher of the same type. + * - There's a check watcher that stops the event loop after a certain number + * of iterations. It starts a varying number of idle_1 watchers. + * - Idle_1 watchers stop themselves after being called a few times. All idle_1 + * watchers try to start the idle_2 watcher if it is not already started or + * awaiting its close callback. + * - The idle_2 watcher always exists but immediately closes itself after + * being started by a check_1 watcher. It verifies that a watcher is + * implicitly stopped when closed, and that a watcher can close itself + * safely. + * - There is a repeating timer. It does not keep the event loop alive + * (ev_unref) but makes sure that the loop keeps polling the system for + * events. + */ + + +#include "uv.h" +#include "task.h" + +#include + + +#define IDLE_COUNT 7 +#define ITERATIONS 21 +#define TIMEOUT 100 + + +static uv_prepare_t prepare_1_handle; +static uv_prepare_t prepare_2_handle; + +static uv_check_t check_handle; + +static uv_idle_t idle_1_handles[IDLE_COUNT]; +static uv_idle_t idle_2_handle; + +static uv_timer_t timer_handle; + + +static int loop_iteration = 0; + +static int prepare_1_cb_called = 0; +static int prepare_1_close_cb_called = 0; + +static int prepare_2_cb_called = 0; +static int prepare_2_close_cb_called = 0; + +static int check_cb_called = 0; +static int check_close_cb_called = 0; + +static int idle_1_cb_called = 0; +static int idle_1_close_cb_called = 0; +static int idles_1_active = 0; + +static int idle_2_cb_called = 0; +static int idle_2_close_cb_called = 0; +static int idle_2_cb_started = 0; +static int idle_2_is_active = 0; + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); +} + + +static void idle_2_close_cb(uv_handle_t* handle) { + LOG("IDLE_2_CLOSE_CB\n"); + + ASSERT(handle == (uv_handle_t*)&idle_2_handle); + + ASSERT(idle_2_is_active); + + idle_2_close_cb_called++; + idle_2_is_active = 0; +} + + +static void idle_2_cb(uv_idle_t* handle, int status) { + LOG("IDLE_2_CB\n"); + + ASSERT(handle == &idle_2_handle); + ASSERT(status == 0); + + idle_2_cb_called++; + + uv_close((uv_handle_t*)handle, idle_2_close_cb); +} + + +static void idle_1_cb(uv_idle_t* handle, int status) { + int r; + + LOG("IDLE_1_CB\n"); + + ASSERT(handle != NULL); + ASSERT(status == 0); + + ASSERT(idles_1_active > 0); + + /* Init idle_2 and make it active */ + if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) { + r = uv_idle_init(uv_default_loop(), &idle_2_handle); + ASSERT(r == 0); + r = uv_idle_start(&idle_2_handle, idle_2_cb); + ASSERT(r == 0); + idle_2_is_active = 1; + idle_2_cb_started++; + } + + idle_1_cb_called++; + + if (idle_1_cb_called % 5 == 0) { + r = uv_idle_stop((uv_idle_t*)handle); + ASSERT(r == 0); + idles_1_active--; + } +} + + +static void idle_1_close_cb(uv_handle_t* handle) { + LOG("IDLE_1_CLOSE_CB\n"); + + ASSERT(handle != NULL); + + idle_1_close_cb_called++; +} + + +static void prepare_1_close_cb(uv_handle_t* handle) { + LOG("PREPARE_1_CLOSE_CB"); + ASSERT(handle == (uv_handle_t*)&prepare_1_handle); + + prepare_1_close_cb_called++; +} + + +static void check_close_cb(uv_handle_t* handle) { + LOG("CHECK_CLOSE_CB\n"); + ASSERT(handle == (uv_handle_t*)&check_handle); + + check_close_cb_called++; +} + + +static void prepare_2_close_cb(uv_handle_t* handle) { + LOG("PREPARE_2_CLOSE_CB\n"); + ASSERT(handle == (uv_handle_t*)&prepare_2_handle); + + prepare_2_close_cb_called++; +} + + +static void check_cb(uv_check_t* handle, int status) { + int i, r; + + LOG("CHECK_CB\n"); + + ASSERT(handle == &check_handle); + ASSERT(status == 0); + + if (loop_iteration < ITERATIONS) { + /* Make some idle watchers active */ + for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) { + r = uv_idle_start(&idle_1_handles[i], idle_1_cb); + ASSERT(r == 0); + idles_1_active++; + } + + } else { + /* End of the test - close all handles */ + uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb); + uv_close((uv_handle_t*)&check_handle, check_close_cb); + uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb); + + for (i = 0; i < IDLE_COUNT; i++) { + uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb); + } + + /* This handle is closed/recreated every time, close it only if it is */ + /* active.*/ + if (idle_2_is_active) { + uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb); + } + } + + check_cb_called++; +} + + +static void prepare_2_cb(uv_prepare_t* handle, int status) { + int r; + + LOG("PREPARE_2_CB\n"); + + ASSERT(handle == &prepare_2_handle); + ASSERT(status == 0); + + /* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */ + /* and it stops itself immediately. A started watcher is not queued */ + /* until the next round, so when this callback is made */ + /* (loop_iteration % 2 == 0) cannot be true. */ + ASSERT(loop_iteration % 2 != 0); + + r = uv_prepare_stop((uv_prepare_t*)handle); + ASSERT(r == 0); + + prepare_2_cb_called++; +} + + +static void prepare_1_cb(uv_prepare_t* handle, int status) { + int r; + + LOG("PREPARE_1_CB\n"); + + ASSERT(handle == &prepare_1_handle); + ASSERT(status == 0); + + if (loop_iteration % 2 == 0) { + r = uv_prepare_start(&prepare_2_handle, prepare_2_cb); + ASSERT(r == 0); + } + + prepare_1_cb_called++; + loop_iteration++; + + printf("Loop iteration %d of %d.\n", loop_iteration, ITERATIONS); +} + + +TEST_IMPL(loop_handles) { + int i; + int r; + + r = uv_prepare_init(uv_default_loop(), &prepare_1_handle); + ASSERT(r == 0); + r = uv_prepare_start(&prepare_1_handle, prepare_1_cb); + ASSERT(r == 0); + + r = uv_check_init(uv_default_loop(), &check_handle); + ASSERT(r == 0); + r = uv_check_start(&check_handle, check_cb); + ASSERT(r == 0); + + /* initialize only, prepare_2 is started by prepare_1_cb */ + r = uv_prepare_init(uv_default_loop(), &prepare_2_handle); + ASSERT(r == 0); + + for (i = 0; i < IDLE_COUNT; i++) { + /* initialize only, idle_1 handles are started by check_cb */ + r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]); + ASSERT(r == 0); + } + + /* don't init or start idle_2, both is done by idle_1_cb */ + + /* the timer callback is there to keep the event loop polling */ + /* unref it as it is not supposed to keep the loop alive */ + r = uv_timer_init(uv_default_loop(), &timer_handle); + ASSERT(r == 0); + r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); + ASSERT(r == 0); + uv_unref((uv_handle_t*)&timer_handle); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(loop_iteration == ITERATIONS); + + ASSERT(prepare_1_cb_called == ITERATIONS); + ASSERT(prepare_1_close_cb_called == 1); + + ASSERT(prepare_2_cb_called == floor(ITERATIONS / 2.0)); + ASSERT(prepare_2_close_cb_called == 1); + + ASSERT(check_cb_called == ITERATIONS); + ASSERT(check_close_cb_called == 1); + + /* idle_1_cb should be called a lot */ + ASSERT(idle_1_close_cb_called == IDLE_COUNT); + + ASSERT(idle_2_close_cb_called == idle_2_cb_started); + ASSERT(idle_2_is_active == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-loop-stop.c b/test/test-loop-stop.c new file mode 100644 index 0000000000..c519644ed2 --- /dev/null +++ b/test/test-loop-stop.c @@ -0,0 +1,73 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_prepare_t prepare_handle; +static uv_timer_t timer_handle; +static int prepare_called = 0; +static int timer_called = 0; +static int num_ticks = 10; + + +static void prepare_cb(uv_prepare_t* handle, int status) { + ASSERT(handle == &prepare_handle); + ASSERT(status == 0); + prepare_called++; + if (prepare_called == num_ticks) + uv_prepare_stop(handle); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + timer_called++; + if (timer_called == 1) + uv_stop(uv_default_loop()); + else if (timer_called == num_ticks) + uv_timer_stop(handle); +} + + +TEST_IMPL(loop_stop) { + int r; + uv_prepare_init(uv_default_loop(), &prepare_handle); + uv_prepare_start(&prepare_handle, prepare_cb); + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r != 0); + ASSERT(timer_called == 1); + + r = uv_run(uv_default_loop(), UV_RUN_NOWAIT); + ASSERT(r != 0); + ASSERT(prepare_called > 1); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_called == 10); + ASSERT(prepare_called == 10); + + return 0; +} diff --git a/test/test-loop-time.c b/test/test-loop-time.c new file mode 100644 index 0000000000..49dc79b2c3 --- /dev/null +++ b/test/test-loop-time.c @@ -0,0 +1,34 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +TEST_IMPL(loop_update_time) { + uint64_t start; + + start = uv_now(uv_default_loop()); + while (uv_now(uv_default_loop()) - start < 1000) + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + return 0; +} diff --git a/test/test-multiple-listen.c b/test/test-multiple-listen.c new file mode 100644 index 0000000000..4ae5fa67b3 --- /dev/null +++ b/test/test-multiple-listen.c @@ -0,0 +1,109 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static int connection_cb_called = 0; +static int close_cb_called = 0; +static int connect_cb_called = 0; +static uv_tcp_t server; +static uv_tcp_t client; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT(status == 0); + uv_close((uv_handle_t*)&server, close_cb); + connection_cb_called++; +} + + +static void start_server(void) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, 128, connection_cb); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, 128, connection_cb); + ASSERT(r == 0); +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + free(req); + uv_close((uv_handle_t*)&client, close_cb); + connect_cb_called++; +} + + +static void client_connect(void) { + struct sockaddr_in addr; + uv_connect_t* connect_req = malloc(sizeof *connect_req); + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(connect_req != NULL); + + r = uv_tcp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_tcp_connect(connect_req, + &client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); +} + + + +TEST_IMPL(multiple_listen) { + start_server(); + + client_connect(); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(connection_cb_called == 1); + ASSERT(connect_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-mutexes.c b/test/test-mutexes.c new file mode 100644 index 0000000000..896f46bbed --- /dev/null +++ b/test/test-mutexes.c @@ -0,0 +1,63 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +/* The mutex and rwlock tests are really poor. + * They're very basic sanity checks and nothing more. + * Apologies if that rhymes. + */ + +TEST_IMPL(thread_mutex) { + uv_mutex_t mutex; + int r; + + r = uv_mutex_init(&mutex); + ASSERT(r == 0); + + uv_mutex_lock(&mutex); + uv_mutex_unlock(&mutex); + uv_mutex_destroy(&mutex); + + return 0; +} + + +TEST_IMPL(thread_rwlock) { + uv_rwlock_t rwlock; + int r; + + r = uv_rwlock_init(&rwlock); + ASSERT(r == 0); + + uv_rwlock_rdlock(&rwlock); + uv_rwlock_rdunlock(&rwlock); + uv_rwlock_wrlock(&rwlock); + uv_rwlock_wrunlock(&rwlock); + uv_rwlock_destroy(&rwlock); + + return 0; +} diff --git a/test/test-osx-select.c b/test/test-osx-select.c new file mode 100644 index 0000000000..e5e1bf8b46 --- /dev/null +++ b/test/test-osx-select.c @@ -0,0 +1,82 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifdef __APPLE__ + +#include +#include + +static int read_count; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char slab[1024]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + fprintf(stdout, "got data %d\n", ++read_count); + + if (read_count == 3) + uv_close((uv_handle_t*) stream, NULL); +} + + +TEST_IMPL(osx_select) { + int r; + int fd; + size_t i; + size_t len; + const char* str; + uv_tty_t tty; + + fd = open("/dev/tty", O_RDONLY); + + ASSERT(fd >= 0); + + r = uv_tty_init(uv_default_loop(), &tty, fd, 1); + ASSERT(r == 0); + + uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb); + + /* Emulate user-input */ + str = "got some input\n" + "with a couple of lines\n" + "feel pretty happy\n"; + for (i = 0, len = strlen(str); i < len; i++) { + r = ioctl(fd, TIOCSTI, str + i); + ASSERT(r == 0); + } + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(read_count == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* __APPLE__ */ diff --git a/test/test-pass-always.c b/test/test-pass-always.c new file mode 100644 index 0000000000..4fb58ff94b --- /dev/null +++ b/test/test-pass-always.c @@ -0,0 +1,28 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" + + +TEST_IMPL(pass_always) { + /* This test always passes. It is used to test the test runner. */ + return 0; +} diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c new file mode 100644 index 0000000000..c579fdd668 --- /dev/null +++ b/test/test-ping-pong.c @@ -0,0 +1,263 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +static int completed_pingers = 0; + +#define NUM_PINGS 1000 + +/* 64 bytes is enough for a pinger */ +#define BUFSIZE 10240 + +static char PING[] = "PING\n"; +static int pinger_on_connect_count; + + +typedef struct { + int pongs; + int state; + union { + uv_tcp_t tcp; + uv_pipe_t pipe; + } stream; + uv_connect_t connect_req; + char read_buffer[BUFSIZE]; +} pinger_t; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + + +static void pinger_on_close(uv_handle_t* handle) { + pinger_t* pinger = (pinger_t*)handle->data; + + ASSERT(NUM_PINGS == pinger->pongs); + + free(pinger); + + completed_pingers++; +} + + +static void pinger_after_write(uv_write_t *req, int status) { + ASSERT(status == 0); + free(req); +} + + +static void pinger_write_ping(pinger_t* pinger) { + uv_write_t *req; + uv_buf_t buf; + + buf = uv_buf_init(PING, sizeof(PING) - 1); + + req = malloc(sizeof(*req)); + if (uv_write(req, + (uv_stream_t*) &pinger->stream.tcp, + &buf, + 1, + pinger_after_write)) { + FATAL("uv_write failed"); + } + + puts("PING"); +} + + +static void pinger_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ssize_t i; + pinger_t* pinger; + + pinger = (pinger_t*)stream->data; + + if (nread < 0) { + ASSERT(nread == UV_EOF); + + puts("got EOF"); + free(buf->base); + + uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close); + + return; + } + + /* Now we count the pings */ + for (i = 0; i < nread; i++) { + ASSERT(buf->base[i] == PING[pinger->state]); + pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); + + if (pinger->state != 0) + continue; + + printf("PONG %d\n", pinger->pongs); + pinger->pongs++; + + if (pinger->pongs < NUM_PINGS) { + pinger_write_ping(pinger); + } else { + uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close); + break; + } + } + + free(buf->base); +} + + +static void pinger_on_connect(uv_connect_t *req, int status) { + pinger_t *pinger = (pinger_t*)req->handle->data; + + pinger_on_connect_count++; + + ASSERT(status == 0); + + ASSERT(1 == uv_is_readable(req->handle)); + ASSERT(1 == uv_is_writable(req->handle)); + ASSERT(0 == uv_is_closing((uv_handle_t *) req->handle)); + + pinger_write_ping(pinger); + + uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb); +} + + +/* same ping-pong test, but using IPv6 connection */ +static void tcp_pinger_v6_new(void) { + int r; + struct sockaddr_in6 server_addr; + pinger_t *pinger; + + ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr)); + pinger = malloc(sizeof(*pinger)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ + r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); + pinger->stream.tcp.data = pinger; + ASSERT(!r); + + /* We are never doing multiple reads/connects at a time anyway. */ + /* so these handles can be pre-initialized. */ + r = uv_tcp_connect(&pinger->connect_req, + &pinger->stream.tcp, + (const struct sockaddr*) &server_addr, + pinger_on_connect); + ASSERT(!r); + + /* Synchronous connect callbacks are not allowed. */ + ASSERT(pinger_on_connect_count == 0); +} + + +static void tcp_pinger_new(void) { + int r; + struct sockaddr_in server_addr; + pinger_t *pinger; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + pinger = malloc(sizeof(*pinger)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ + r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); + pinger->stream.tcp.data = pinger; + ASSERT(!r); + + /* We are never doing multiple reads/connects at a time anyway. */ + /* so these handles can be pre-initialized. */ + r = uv_tcp_connect(&pinger->connect_req, + &pinger->stream.tcp, + (const struct sockaddr*) &server_addr, + pinger_on_connect); + ASSERT(!r); + + /* Synchronous connect callbacks are not allowed. */ + ASSERT(pinger_on_connect_count == 0); +} + + +static void pipe_pinger_new(void) { + int r; + pinger_t *pinger; + + pinger = (pinger_t*)malloc(sizeof(*pinger)); + pinger->state = 0; + pinger->pongs = 0; + + /* Try to connect to the server and do NUM_PINGS ping-pongs. */ + r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0); + pinger->stream.pipe.data = pinger; + ASSERT(!r); + + /* We are never doing multiple reads/connects at a time anyway. */ + /* so these handles can be pre-initialized. */ + + uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME, + pinger_on_connect); + + /* Synchronous connect callbacks are not allowed. */ + ASSERT(pinger_on_connect_count == 0); +} + + +TEST_IMPL(tcp_ping_pong) { + tcp_pinger_new(); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(completed_pingers == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ping_pong_v6) { + tcp_pinger_v6_new(); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(completed_pingers == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_ping_pong) { + pipe_pinger_new(); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(completed_pingers == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c new file mode 100644 index 0000000000..38b57db699 --- /dev/null +++ b/test/test-pipe-bind-error.c @@ -0,0 +1,136 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +#ifdef _WIN32 +# define BAD_PIPENAME "bad-pipe" +#else +# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there" +#endif + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(pipe_bind_error_addrinuse) { + uv_pipe_t server1, server2; + int r; + + r = uv_pipe_init(uv_default_loop(), &server1, 0); + ASSERT(r == 0); + r = uv_pipe_bind(&server1, TEST_PIPENAME); + ASSERT(r == 0); + + r = uv_pipe_init(uv_default_loop(), &server2, 0); + ASSERT(r == 0); + r = uv_pipe_bind(&server2, TEST_PIPENAME); + ASSERT(r == UV_EADDRINUSE); + + r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server1, close_cb); + uv_close((uv_handle_t*)&server2, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_bind_error_addrnotavail) { + uv_pipe_t server; + int r; + + r = uv_pipe_init(uv_default_loop(), &server, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&server, BAD_PIPENAME); + ASSERT(r == UV_EACCES); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_bind_error_inval) { + uv_pipe_t server; + int r; + + r = uv_pipe_init(uv_default_loop(), &server, 0); + ASSERT(r == 0); + r = uv_pipe_bind(&server, TEST_PIPENAME); + ASSERT(r == 0); + r = uv_pipe_bind(&server, TEST_PIPENAME_2); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_listen_without_bind) { + uv_pipe_t server; + int r; + + r = uv_pipe_init(uv_default_loop(), &server, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-pipe-connect-error.c b/test/test-pipe-connect-error.c new file mode 100644 index 0000000000..ebb2a6ca82 --- /dev/null +++ b/test/test-pipe-connect-error.c @@ -0,0 +1,95 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +#ifdef _WIN32 +# define BAD_PIPENAME "bad-pipe" +#else +# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there" +#endif + + +static int close_cb_called = 0; +static int connect_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* connect_req, int status) { + ASSERT(status == UV_ENOENT); + uv_close((uv_handle_t*)connect_req->handle, close_cb); + connect_cb_called++; +} + + +static void connect_cb_file(uv_connect_t* connect_req, int status) { + ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED); + uv_close((uv_handle_t*)connect_req->handle, close_cb); + connect_cb_called++; +} + + +TEST_IMPL(pipe_connect_bad_name) { + uv_pipe_t client; + uv_connect_t req; + int r; + + r = uv_pipe_init(uv_default_loop(), &client, 0); + ASSERT(r == 0); + uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + ASSERT(connect_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_connect_to_file) { + const char* path = "test/fixtures/empty_file"; + uv_pipe_t client; + uv_connect_t req; + int r; + + r = uv_pipe_init(uv_default_loop(), &client, 0); + ASSERT(r == 0); + uv_pipe_connect(&req, &client, path, connect_cb_file); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + ASSERT(connect_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-pipe-server-close.c b/test/test-pipe-server-close.c new file mode 100644 index 0000000000..1dcdfffaf7 --- /dev/null +++ b/test/test-pipe-server-close.c @@ -0,0 +1,91 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +static uv_pipe_t pipe_client; +static uv_pipe_t pipe_server; +static uv_connect_t connect_req; + +static int pipe_close_cb_called = 0; +static int pipe_client_connect_cb_called = 0; + + +static void pipe_close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*) &pipe_client || + handle == (uv_handle_t*) &pipe_server); + pipe_close_cb_called++; +} + + +static void pipe_client_connect_cb(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == 0); + + pipe_client_connect_cb_called++; + + uv_close((uv_handle_t*) &pipe_client, pipe_close_cb); + uv_close((uv_handle_t*) &pipe_server, pipe_close_cb); +} + + +static void pipe_server_connection_cb(uv_stream_t* handle, int status) { + /* This function *may* be called, depending on whether accept or the + * connection callback is called first. + */ + ASSERT(status == 0); +} + + +TEST_IMPL(pipe_server_close) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + ASSERT(loop != NULL); + + r = uv_pipe_init(loop, &pipe_server, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&pipe_server, TEST_PIPENAME); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb); + ASSERT(r == 0); + + r = uv_pipe_init(loop, &pipe_client, 0); + ASSERT(r == 0); + + uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(pipe_client_connect_cb_called == 1); + ASSERT(pipe_close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-platform-output.c b/test/test-platform-output.c new file mode 100644 index 0000000000..d2104f40a1 --- /dev/null +++ b/test/test-platform-output.c @@ -0,0 +1,103 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + + +TEST_IMPL(platform_output) { + char buffer[512]; + size_t rss; + double uptime; + uv_cpu_info_t* cpus; + uv_interface_address_t* interfaces; + int count; + int i; + int err; + + err = uv_get_process_title(buffer, sizeof(buffer)); + ASSERT(err == 0); + printf("uv_get_process_title: %s\n", buffer); + + err = uv_resident_set_memory(&rss); + ASSERT(err == 0); + printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); + + err = uv_uptime(&uptime); + ASSERT(err == 0); + ASSERT(uptime > 0); + printf("uv_uptime: %f\n", uptime); + + err = uv_cpu_info(&cpus, &count); + ASSERT(err == 0); + + printf("uv_cpu_info:\n"); + for (i = 0; i < count; i++) { + printf(" model: %s\n", cpus[i].model); + printf(" speed: %d\n", cpus[i].speed); + printf(" times.sys: %llu\n", (unsigned long long) cpus[i].cpu_times.sys); + printf(" times.user: %llu\n", + (unsigned long long) cpus[i].cpu_times.user); + printf(" times.idle: %llu\n", + (unsigned long long) cpus[i].cpu_times.idle); + printf(" times.irq: %llu\n", (unsigned long long) cpus[i].cpu_times.irq); + printf(" times.nice: %llu\n", + (unsigned long long) cpus[i].cpu_times.nice); + } + uv_free_cpu_info(cpus, count); + + err = uv_interface_addresses(&interfaces, &count); + ASSERT(err == 0); + + printf("uv_interface_addresses:\n"); + for (i = 0; i < count; i++) { + printf(" name: %s\n", interfaces[i].name); + printf(" internal: %d\n", interfaces[i].is_internal); + printf(" physical address: "); + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + (unsigned char)interfaces[i].phys_addr[0], + (unsigned char)interfaces[i].phys_addr[1], + (unsigned char)interfaces[i].phys_addr[2], + (unsigned char)interfaces[i].phys_addr[3], + (unsigned char)interfaces[i].phys_addr[4], + (unsigned char)interfaces[i].phys_addr[5]); + + if (interfaces[i].address.address4.sin_family == AF_INET) { + uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer)); + } else if (interfaces[i].address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interfaces[i].address.address6, buffer, sizeof(buffer)); + } + + printf(" address: %s\n", buffer); + + if (interfaces[i].netmask.netmask4.sin_family == AF_INET) { + uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer)); + } else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) { + uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer)); + } + + printf(" netmask: %s\n", buffer); + } + uv_free_interface_addresses(interfaces, count); + + return 0; +} diff --git a/test/test-poll-close.c b/test/test-poll-close.c new file mode 100644 index 0000000000..2eccddf5b0 --- /dev/null +++ b/test/test-poll-close.c @@ -0,0 +1,73 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#ifndef _WIN32 +# include +# include +# include +#endif + +#include "uv.h" +#include "task.h" + +#define NUM_SOCKETS 64 + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +TEST_IMPL(poll_close) { + uv_os_sock_t sockets[NUM_SOCKETS]; + uv_poll_t poll_handles[NUM_SOCKETS]; + int i; + +#ifdef _WIN32 + { + struct WSAData wsa_data; + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); + } +#endif + + for (i = 0; i < NUM_SOCKETS; i++) { + sockets[i] = socket(AF_INET, SOCK_STREAM, 0); + uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]); + uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL); + } + + for (i = 0; i < NUM_SOCKETS; i++) { + uv_close((uv_handle_t*) &poll_handles[i], close_cb); + } + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == NUM_SOCKETS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-poll.c b/test/test-poll.c new file mode 100644 index 0000000000..0736b9b0bf --- /dev/null +++ b/test/test-poll.c @@ -0,0 +1,581 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#ifndef _WIN32 +# include +# include +# include +#endif + +#include "uv.h" +#include "task.h" + + +#define NUM_CLIENTS 5 +#define TRANSFER_BYTES (1 << 16) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)); + + +typedef enum { + UNIDIRECTIONAL, + DUPLEX +} test_mode_t; + +typedef struct connection_context_s { + uv_poll_t poll_handle; + uv_timer_t timer_handle; + uv_os_sock_t sock; + size_t read, sent; + int is_server_connection; + int open_handles; + int got_fin, sent_fin; + unsigned int events, delayed_events; +} connection_context_t; + +typedef struct server_context_s { + uv_poll_t poll_handle; + uv_os_sock_t sock; + int connections; +} server_context_t; + + +static void delay_timer_cb(uv_timer_t* timer, int status); + + +static test_mode_t test_mode = DUPLEX; + +static int closed_connections = 0; + +static int valid_writable_wakeups = 0; +static int spurious_writable_wakeups = 0; + + +static int got_eagain(void) { +#ifdef _WIN32 + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EAGAIN + || errno == EINPROGRESS +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK; +#endif + ; +#endif +} + + +static void set_nonblocking(uv_os_sock_t sock) { + int r; +#ifdef _WIN32 + unsigned long on = 1; + r = ioctlsocket(sock, FIONBIO, &on); + ASSERT(r == 0); +#else + int flags = fcntl(sock, F_GETFL, 0); + ASSERT(flags >= 0); + r = fcntl(sock, F_SETFL, flags | O_NONBLOCK); + ASSERT(r >= 0); +#endif +} + + +static uv_os_sock_t create_nonblocking_bound_socket( + struct sockaddr_in bind_addr) { + uv_os_sock_t sock; + int r; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + + set_nonblocking(sock); + +#ifndef _WIN32 + { + /* Allow reuse of the port. */ + int yes = 1; + r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + ASSERT(r == 0); + } +#endif + + r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr); + ASSERT(r == 0); + + return sock; +} + + +static void close_socket(uv_os_sock_t sock) { + int r; +#ifdef _WIN32 + r = closesocket(sock); +#else + r = close(sock); +#endif + ASSERT(r == 0); +} + + +static connection_context_t* create_connection_context( + uv_os_sock_t sock, int is_server_connection) { + int r; + connection_context_t* context; + + context = (connection_context_t*) malloc(sizeof *context); + ASSERT(context != NULL); + + context->sock = sock; + context->is_server_connection = is_server_connection; + context->read = 0; + context->sent = 0; + context->open_handles = 0; + context->events = 0; + context->delayed_events = 0; + context->got_fin = 0; + context->sent_fin = 0; + + r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); + context->open_handles++; + context->poll_handle.data = context; + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &context->timer_handle); + context->open_handles++; + context->timer_handle.data = context; + ASSERT(r == 0); + + return context; +} + + +static void connection_close_cb(uv_handle_t* handle) { + connection_context_t* context = (connection_context_t*) handle->data; + + if (--context->open_handles == 0) { + if (test_mode == DUPLEX || context->is_server_connection) { + ASSERT(context->read == TRANSFER_BYTES); + } else { + ASSERT(context->read == 0); + } + + if (test_mode == DUPLEX || !context->is_server_connection) { + ASSERT(context->sent == TRANSFER_BYTES); + } else { + ASSERT(context->sent == 0); + } + + closed_connections++; + + free(context); + } +} + + +static void destroy_connection_context(connection_context_t* context) { + uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb); + uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb); +} + + +static void connection_poll_cb(uv_poll_t* handle, int status, int events) { + connection_context_t* context = (connection_context_t*) handle->data; + unsigned int new_events; + int r; + + ASSERT(status == 0); + ASSERT(events & context->events); + ASSERT(!(events & ~context->events)); + + new_events = context->events; + + if (events & UV_READABLE) { + int action = rand() % 7; + + switch (action) { + case 0: + case 1: { + /* Read a couple of bytes. */ + static char buffer[74]; + r = recv(context->sock, buffer, sizeof buffer, 0); + ASSERT(r >= 0); + + if (r > 0) { + context->read += r; + } else { + /* Got FIN. */ + context->got_fin = 1; + new_events &= ~UV_READABLE; + } + + break; + } + + case 2: + case 3: { + /* Read until EAGAIN. */ + static char buffer[931]; + r = recv(context->sock, buffer, sizeof buffer, 0); + ASSERT(r >= 0); + + while (r > 0) { + context->read += r; + r = recv(context->sock, buffer, sizeof buffer, 0); + } + + if (r == 0) { + /* Got FIN. */ + context->got_fin = 1; + new_events &= ~UV_READABLE; + } else { + ASSERT(got_eagain()); + } + + break; + } + + case 4: + /* Ignore. */ + break; + + case 5: + /* Stop reading for a while. Restart in timer callback. */ + new_events &= ~UV_READABLE; + if (!uv_is_active((uv_handle_t*) &context->timer_handle)) { + context->delayed_events = UV_READABLE; + uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0); + } else { + context->delayed_events |= UV_READABLE; + } + break; + + case 6: + /* Fudge with the event mask. */ + uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb); + uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb); + context->events = UV_READABLE; + break; + + default: + ASSERT(0); + } + } + + if (events & UV_WRITABLE) { + if (context->sent < TRANSFER_BYTES && + !(test_mode == UNIDIRECTIONAL && context->is_server_connection)) { + /* We have to send more bytes. */ + int action = rand() % 7; + + switch (action) { + case 0: + case 1: { + /* Send a couple of bytes. */ + static char buffer[103]; + + int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r < 0) { + ASSERT(got_eagain()); + spurious_writable_wakeups++; + break; + } + + ASSERT(r > 0); + context->sent += r; + valid_writable_wakeups++; + break; + } + + case 2: + case 3: { + /* Send until EAGAIN. */ + static char buffer[1234]; + + int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r < 0) { + ASSERT(got_eagain()); + spurious_writable_wakeups++; + break; + } + + ASSERT(r > 0); + valid_writable_wakeups++; + context->sent += r; + + while (context->sent < TRANSFER_BYTES) { + send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r <= 0) break; + context->sent += r; + } + ASSERT(r > 0 || got_eagain()); + break; + } + + case 4: + /* Ignore. */ + break; + + case 5: + /* Stop sending for a while. Restart in timer callback. */ + new_events &= ~UV_WRITABLE; + if (!uv_is_active((uv_handle_t*) &context->timer_handle)) { + context->delayed_events = UV_WRITABLE; + uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0); + } else { + context->delayed_events |= UV_WRITABLE; + } + break; + + case 6: + /* Fudge with the event mask. */ + uv_poll_start(&context->poll_handle, + UV_READABLE, + connection_poll_cb); + uv_poll_start(&context->poll_handle, + UV_WRITABLE, + connection_poll_cb); + context->events = UV_WRITABLE; + break; + + default: + ASSERT(0); + } + + } else { + /* Nothing more to write. Send FIN. */ + int r; +#ifdef _WIN32 + r = shutdown(context->sock, SD_SEND); +#else + r = shutdown(context->sock, SHUT_WR); +#endif + ASSERT(r == 0); + context->sent_fin = 1; + new_events &= ~UV_WRITABLE; + } + } + + if (context->got_fin && context->sent_fin) { + /* Sent and received FIN. Close and destroy context. */ + close_socket(context->sock); + destroy_connection_context(context); + context->events = 0; + + } else if (new_events != context->events) { + /* Poll mask changed. Call uv_poll_start again. */ + context->events = new_events; + uv_poll_start(handle, new_events, connection_poll_cb); + } + + /* Assert that uv_is_active works correctly for poll handles. */ + if (context->events != 0) { + ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + } else { + ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + } +} + + +static void delay_timer_cb(uv_timer_t* timer, int status) { + connection_context_t* context = (connection_context_t*) timer->data; + int r; + + /* Timer should auto stop. */ + ASSERT(0 == uv_is_active((uv_handle_t*) timer)); + + /* Add the requested events to the poll mask. */ + ASSERT(context->delayed_events != 0); + context->events |= context->delayed_events; + context->delayed_events = 0; + + r = uv_poll_start(&context->poll_handle, + context->events, + connection_poll_cb); + ASSERT(r == 0); +} + + +static server_context_t* create_server_context( + uv_os_sock_t sock) { + int r; + server_context_t* context; + + context = (server_context_t*) malloc(sizeof *context); + ASSERT(context != NULL); + + context->sock = sock; + context->connections = 0; + + r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); + context->poll_handle.data = context; + ASSERT(r == 0); + + return context; +} + + +static void server_close_cb(uv_handle_t* handle) { + server_context_t* context = (server_context_t*) handle->data; + free(context); +} + + +static void destroy_server_context(server_context_t* context) { + uv_close((uv_handle_t*) &context->poll_handle, server_close_cb); +} + + +static void server_poll_cb(uv_poll_t* handle, int status, int events) { + server_context_t* server_context = (server_context_t*) + handle->data; + connection_context_t* connection_context; + struct sockaddr_in addr; + socklen_t addr_len; + uv_os_sock_t sock; + int r; + + addr_len = sizeof addr; + sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + + set_nonblocking(sock); + + connection_context = create_connection_context(sock, 1); + connection_context->events = UV_READABLE | UV_WRITABLE; + r = uv_poll_start(&connection_context->poll_handle, + UV_READABLE | UV_WRITABLE, + connection_poll_cb); + ASSERT(r == 0); + + if (++server_context->connections == NUM_CLIENTS) { + close_socket(server_context->sock); + destroy_server_context(server_context); + } +} + + +static void start_server(void) { + server_context_t* context; + struct sockaddr_in addr; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + sock = create_nonblocking_bound_socket(addr); + context = create_server_context(sock); + + r = listen(sock, 100); + ASSERT(r == 0); + + r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb); + ASSERT(r == 0); +} + + +static void start_client(void) { + uv_os_sock_t sock; + connection_context_t* context; + struct sockaddr_in server_addr; + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr)); + + sock = create_nonblocking_bound_socket(addr); + context = create_connection_context(sock, 0); + + context->events = UV_READABLE | UV_WRITABLE; + r = uv_poll_start(&context->poll_handle, + UV_READABLE | UV_WRITABLE, + connection_poll_cb); + ASSERT(r == 0); + + r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr); + ASSERT(r == 0 || got_eagain()); +} + + +static void start_poll_test(void) { + int i, r; + +#ifdef _WIN32 + { + struct WSAData wsa_data; + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); + } +#endif + + start_server(); + + for (i = 0; i < NUM_CLIENTS; i++) + start_client(); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + /* Assert that at most five percent of the writable wakeups was spurious. */ + ASSERT(spurious_writable_wakeups == 0 || + (valid_writable_wakeups + spurious_writable_wakeups) / + spurious_writable_wakeups > 20); + + ASSERT(closed_connections == NUM_CLIENTS * 2); + + MAKE_VALGRIND_HAPPY(); +} + + +TEST_IMPL(poll_duplex) { + test_mode = DUPLEX; + start_poll_test(); + return 0; +} + + +TEST_IMPL(poll_unidirectional) { + test_mode = UNIDIRECTIONAL; + start_poll_test(); + return 0; +} diff --git a/test/test-process-title.c b/test/test-process-title.c new file mode 100644 index 0000000000..29be20749b --- /dev/null +++ b/test/test-process-title.c @@ -0,0 +1,53 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + + +static void set_title(const char* title) { + char buffer[512]; + int err; + + err = uv_get_process_title(buffer, sizeof(buffer)); + ASSERT(err == 0); + + err = uv_set_process_title(title); + ASSERT(err == 0); + + err = uv_get_process_title(buffer, sizeof(buffer)); + ASSERT(err == 0); + + ASSERT(strcmp(buffer, title) == 0); +} + + +TEST_IMPL(process_title) { +#if defined(__sun) + RETURN_SKIP("uv_(get|set)_process_title is not implemented."); +#else + /* Check for format string vulnerabilities. */ + set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"); + set_title("new title"); + return 0; +#endif +} diff --git a/test/test-ref.c b/test/test-ref.c new file mode 100644 index 0000000000..7ff2e84e38 --- /dev/null +++ b/test/test-ref.c @@ -0,0 +1,443 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +static uv_write_t write_req; +static uv_shutdown_t shutdown_req; +static uv_connect_t connect_req; + +static char buffer[32767]; + +static int req_cb_called; +static int connect_cb_called; +static int write_cb_called; +static int shutdown_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void do_close(void* handle) { + close_cb_called = 0; + uv_close((uv_handle_t*)handle, close_cb); + ASSERT(close_cb_called == 0); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(close_cb_called == 1); +} + + +static void fail_cb(void) { + FATAL("fail_cb should not have been called"); +} + + +static void fail_cb2(void) { + ASSERT(0 && "fail_cb2 should not have been called"); +} + + +static void req_cb(uv_handle_t* req, int status) { + req_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &shutdown_req); + shutdown_cb_called++; +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req == &write_req); + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + write_cb_called++; +} + + +static void connect_and_write(uv_connect_t* req, int status) { + uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); + ASSERT(req == &connect_req); + ASSERT(status == 0); + uv_write(&write_req, req->handle, &buf, 1, write_cb); + connect_cb_called++; +} + + + +static void connect_and_shutdown(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == 0); + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + connect_cb_called++; +} + + +TEST_IMPL(ref) { + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(idle_ref) { + uv_idle_t h; + uv_idle_init(uv_default_loop(), &h); + uv_idle_start(&h, (uv_idle_cb) fail_cb2); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(async_ref) { + uv_async_t h; + uv_async_init(uv_default_loop(), &h, NULL); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(prepare_ref) { + uv_prepare_t h; + uv_prepare_init(uv_default_loop(), &h); + uv_prepare_start(&h, (uv_prepare_cb) fail_cb2); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(check_ref) { + uv_check_t h; + uv_check_init(uv_default_loop(), &h); + uv_check_start(&h, (uv_check_cb) fail_cb2); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void prepare_cb(uv_prepare_t* h, int status) { + ASSERT(h != NULL); + ASSERT(status == 0); + uv_unref((uv_handle_t*)h); +} + + +TEST_IMPL(unref_in_prepare_cb) { + uv_prepare_t h; + uv_prepare_init(uv_default_loop(), &h); + uv_prepare_start(&h, prepare_cb); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(timer_ref) { + uv_timer_t h; + uv_timer_init(uv_default_loop(), &h); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(timer_ref2) { + uv_timer_t h; + uv_timer_init(uv_default_loop(), &h); + uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_event_ref) { + uv_fs_event_t h; + uv_fs_event_init(uv_default_loop(), &h); + uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fs_poll_ref) { + uv_fs_poll_t h; + uv_fs_poll_init(uv_default_loop(), &h); + uv_fs_poll_start(&h, NULL, ".", 999); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ref) { + uv_tcp_t h; + uv_tcp_init(uv_default_loop(), &h); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ref2) { + uv_tcp_t h; + uv_tcp_init(uv_default_loop(), &h); + uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ref2b) { + uv_tcp_t h; + uv_tcp_init(uv_default_loop(), &h); + uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); + uv_unref((uv_handle_t*)&h); + uv_close((uv_handle_t*)&h, close_cb); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(close_cb_called == 1); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ref3) { + struct sockaddr_in addr; + uv_tcp_t h; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + uv_tcp_init(uv_default_loop(), &h); + uv_tcp_connect(&connect_req, + &h, + (const struct sockaddr*) &addr, + connect_and_shutdown); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_ref4) { + struct sockaddr_in addr; + uv_tcp_t h; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + uv_tcp_init(uv_default_loop(), &h); + uv_tcp_connect(&connect_req, + &h, + (const struct sockaddr*) &addr, + connect_and_write); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(udp_ref) { + uv_udp_t h; + uv_udp_init(uv_default_loop(), &h); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(udp_ref2) { + struct sockaddr_in addr; + uv_udp_t h; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + uv_udp_init(uv_default_loop(), &h); + uv_udp_bind(&h, (const struct sockaddr*) &addr, 0); + uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(udp_ref3) { + struct sockaddr_in addr; + uv_buf_t buf = uv_buf_init("PING", 4); + uv_udp_send_t req; + uv_udp_t h; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + uv_udp_init(uv_default_loop(), &h); + uv_udp_send(&req, + &h, + &buf, + 1, + (const struct sockaddr*) &addr, + (uv_udp_send_cb) req_cb); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(req_cb_called == 1); + do_close(&h); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_ref) { + uv_pipe_t h; + uv_pipe_init(uv_default_loop(), &h, 0); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_ref2) { + uv_pipe_t h; + uv_pipe_init(uv_default_loop(), &h, 0); + uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_ref3) { + uv_pipe_t h; + uv_pipe_init(uv_default_loop(), &h, 0); + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_ref4) { + uv_pipe_t h; + uv_pipe_init(uv_default_loop(), &h, 0); + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write); + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + do_close(&h); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(process_ref) { + /* spawn_helper4 blocks indefinitely. */ + char *argv[] = { NULL, "spawn_helper4", NULL }; + uv_process_options_t options; + size_t exepath_size; + char exepath[256]; + uv_process_t h; + int r; + + memset(&options, 0, sizeof(options)); + exepath_size = sizeof(exepath); + + r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + + argv[0] = exepath; + options.file = exepath; + options.args = argv; + options.exit_cb = NULL; + + r = uv_spawn(uv_default_loop(), &h, &options); + ASSERT(r == 0); + + uv_unref((uv_handle_t*)&h); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + r = uv_process_kill(&h, /* SIGTERM */ 15); + ASSERT(r == 0); + + do_close(&h); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(has_ref) { + uv_idle_t h; + uv_idle_init(uv_default_loop(), &h); + uv_ref((uv_handle_t*)&h); + ASSERT(uv_has_ref((uv_handle_t*)&h) == 1); + uv_unref((uv_handle_t*)&h); + ASSERT(uv_has_ref((uv_handle_t*)&h) == 0); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-run-nowait.c b/test/test-run-nowait.c new file mode 100644 index 0000000000..ee4b36ff3b --- /dev/null +++ b/test/test-run-nowait.c @@ -0,0 +1,46 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer_handle; +static int timer_called = 0; + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + timer_called = 1; +} + + +TEST_IMPL(run_nowait) { + int r; + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + r = uv_run(uv_default_loop(), UV_RUN_NOWAIT); + ASSERT(r != 0); + ASSERT(timer_called == 0); + + return 0; +} diff --git a/test/test-run-once.c b/test/test-run-once.c new file mode 100644 index 0000000000..e243de0ade --- /dev/null +++ b/test/test-run-once.c @@ -0,0 +1,49 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#define NUM_TICKS 64 + +static uv_idle_t idle_handle; +static int idle_counter; + + +static void idle_cb(uv_idle_t* handle, int status) { + ASSERT(handle == &idle_handle); + ASSERT(status == 0); + + if (++idle_counter == NUM_TICKS) + uv_idle_stop(handle); +} + + +TEST_IMPL(run_once) { + uv_idle_init(uv_default_loop(), &idle_handle); + uv_idle_start(&idle_handle, idle_cb); + + while (uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT(idle_counter == NUM_TICKS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-semaphore.c b/test/test-semaphore.c new file mode 100644 index 0000000000..ac03bb08f1 --- /dev/null +++ b/test/test-semaphore.c @@ -0,0 +1,111 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +typedef struct { + uv_mutex_t mutex; + uv_sem_t sem; + int delay; + volatile int posted; +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + + if (c->delay) + uv_sleep(c->delay); + + uv_mutex_lock(&c->mutex); + ASSERT(c->posted == 0); + uv_sem_post(&c->sem); + c->posted = 1; + uv_mutex_unlock(&c->mutex); +} + + +TEST_IMPL(semaphore_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + + ASSERT(0 == uv_sem_init(&wc.sem, 0)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_sleep(100); + uv_mutex_lock(&wc.mutex); + ASSERT(wc.posted == 1); + uv_sem_wait(&wc.sem); /* should not block */ + uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */ + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_sem_destroy(&wc.sem); + + return 0; +} + + +TEST_IMPL(semaphore_2) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.delay = 100; + + ASSERT(0 == uv_sem_init(&wc.sem, 0)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + uv_sem_wait(&wc.sem); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_sem_destroy(&wc.sem); + + return 0; +} + + +TEST_IMPL(semaphore_3) { + uv_sem_t sem; + + ASSERT(0 == uv_sem_init(&sem, 3)); + uv_sem_wait(&sem); /* should not block */ + uv_sem_wait(&sem); /* should not block */ + ASSERT(0 == uv_sem_trywait(&sem)); + ASSERT(UV_EAGAIN == uv_sem_trywait(&sem)); + + uv_sem_post(&sem); + ASSERT(0 == uv_sem_trywait(&sem)); + ASSERT(UV_EAGAIN == uv_sem_trywait(&sem)); + + uv_sem_destroy(&sem); + + return 0; +} diff --git a/test/test-shutdown-close.c b/test/test-shutdown-close.c new file mode 100644 index 0000000000..78c369be2d --- /dev/null +++ b/test/test-shutdown-close.c @@ -0,0 +1,108 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * These tests verify that the uv_shutdown callback is always made, even when + * it is immediately followed by an uv_close call. + */ + +#include "uv.h" +#include "task.h" + + +static uv_shutdown_t shutdown_req; +static uv_connect_t connect_req; + +static int connect_cb_called = 0; +static int shutdown_cb_called = 0; +static int close_cb_called = 0; + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &shutdown_req); + ASSERT(status == 0 || status == UV_ECANCELED); + shutdown_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + int r; + + ASSERT(req == &connect_req); + ASSERT(status == 0); + + r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + ASSERT(r == 0); + ASSERT(0 == uv_is_closing((uv_handle_t*) req->handle)); + uv_close((uv_handle_t*) req->handle, close_cb); + ASSERT(1 == uv_is_closing((uv_handle_t*) req->handle)); + + connect_cb_called++; +} + + +TEST_IMPL(shutdown_close_tcp) { + struct sockaddr_in addr; + uv_tcp_t h; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + r = uv_tcp_init(uv_default_loop(), &h); + ASSERT(r == 0); + r = uv_tcp_connect(&connect_req, + &h, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(shutdown_close_pipe) { + uv_pipe_t h; + int r; + + r = uv_pipe_init(uv_default_loop(), &h, 0); + ASSERT(r == 0); + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-shutdown-eof.c b/test/test-shutdown-eof.c new file mode 100644 index 0000000000..58346361c7 --- /dev/null +++ b/test/test-shutdown-eof.c @@ -0,0 +1,182 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static uv_timer_t timer; +static uv_tcp_t tcp; +static uv_connect_t connect_req; +static uv_write_t write_req; +static uv_shutdown_t shutdown_req; +static uv_buf_t qbuf; +static int got_q; +static int got_eof; +static int called_connect_cb; +static int called_shutdown_cb; +static int called_tcp_close_cb; +static int called_timer_close_cb; +static int called_timer_cb; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + + +static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { + ASSERT((uv_tcp_t*)t == &tcp); + + if (nread == 0) { + free(buf->base); + return; + } + + if (!got_q) { + ASSERT(nread == 1); + ASSERT(!got_eof); + ASSERT(buf->base[0] == 'Q'); + free(buf->base); + got_q = 1; + puts("got Q"); + } else { + ASSERT(nread == UV_EOF); + if (buf->base) { + free(buf->base); + } + got_eof = 1; + puts("got EOF"); + } +} + + +static void shutdown_cb(uv_shutdown_t *req, int status) { + ASSERT(req == &shutdown_req); + + ASSERT(called_connect_cb == 1); + ASSERT(!got_eof); + ASSERT(called_tcp_close_cb == 0); + ASSERT(called_timer_close_cb == 0); + ASSERT(called_timer_cb == 0); + + called_shutdown_cb++; +} + + +static void connect_cb(uv_connect_t *req, int status) { + ASSERT(status == 0); + ASSERT(req == &connect_req); + + /* Start reading from our connection so we can receive the EOF. */ + uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb); + + /* + * Write the letter 'Q' to gracefully kill the echo-server. This will not + * effect our connection. + */ + uv_write(&write_req, (uv_stream_t*) &tcp, &qbuf, 1, NULL); + + /* Shutdown our end of the connection. */ + uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb); + + called_connect_cb++; + ASSERT(called_shutdown_cb == 0); +} + + +static void tcp_close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*) &tcp); + + ASSERT(called_connect_cb == 1); + ASSERT(got_q); + ASSERT(got_eof); + ASSERT(called_timer_cb == 1); + + called_tcp_close_cb++; +} + + +static void timer_close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*) &timer); + called_timer_close_cb++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer); + uv_close((uv_handle_t*) handle, timer_close_cb); + + /* + * The most important assert of the test: we have not received + * tcp_close_cb yet. + */ + ASSERT(called_tcp_close_cb == 0); + uv_close((uv_handle_t*) &tcp, tcp_close_cb); + + called_timer_cb++; +} + + +/* + * This test has a client which connects to the echo_server and immediately + * issues a shutdown. The echo-server, in response, will also shutdown their + * connection. We check, with a timer, that libuv is not automatically + * calling uv_close when the client receives the EOF from echo-server. + */ +TEST_IMPL(shutdown_eof) { + struct sockaddr_in server_addr; + int r; + + qbuf.base = "Q"; + qbuf.len = 1; + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + uv_timer_start(&timer, timer_cb, 100, 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT(!r); + + r = uv_tcp_connect(&connect_req, + &tcp, + (const struct sockaddr*) &server_addr, + connect_cb); + ASSERT(!r); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(called_connect_cb == 1); + ASSERT(called_shutdown_cb == 1); + ASSERT(got_eof); + ASSERT(got_q); + ASSERT(called_tcp_close_cb == 1); + ASSERT(called_timer_close_cb == 1); + ASSERT(called_timer_cb == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c new file mode 100644 index 0000000000..e80154e3e8 --- /dev/null +++ b/test/test-signal-multiple-loops.c @@ -0,0 +1,289 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +/* This test does not pretend to be cross-platform. */ +#ifndef _WIN32 + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include +#include +#include +#include + +/* The value of NUM_SIGNAL_HANDLING_THREADS is not arbitrary; it needs to be a + * multiple of three for reasons that will become clear when you scroll down. + * We're basically creating three different thread groups. The total needs + * to be divisible by three in order for the numbers in the final check to + * match up. + */ +#define NUM_SIGNAL_HANDLING_THREADS 24 +#define NUM_LOOP_CREATING_THREADS 10 + +enum signal_action { + ONLY_SIGUSR1, + ONLY_SIGUSR2, + SIGUSR1_AND_SIGUSR2 +}; + +static uv_sem_t sem; +static uv_mutex_t counter_lock; +static volatile int stop = 0; + +static volatile int signal1_cb_counter = 0; +static volatile int signal2_cb_counter = 0; +static volatile int loop_creation_counter = 0; + + +static void increment_counter(volatile int* counter) { + uv_mutex_lock(&counter_lock); + ++(*counter); + uv_mutex_unlock(&counter_lock); +} + + +static void signal1_cb(uv_signal_t* handle, int signum) { + ASSERT(signum == SIGUSR1); + increment_counter(&signal1_cb_counter); + uv_signal_stop(handle); +} + + +static void signal2_cb(uv_signal_t* handle, int signum) { + ASSERT(signum == SIGUSR2); + increment_counter(&signal2_cb_counter); + uv_signal_stop(handle); +} + + +static void signal_handling_worker(void* context) { + enum signal_action action; + uv_signal_t signal1a; + uv_signal_t signal1b; + uv_signal_t signal2; + uv_loop_t* loop; + int r; + + action = (enum signal_action) (uintptr_t) context; + + loop = uv_loop_new(); + ASSERT(loop != NULL); + + /* Setup the signal watchers and start them. */ + if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { + r = uv_signal_init(loop, &signal1a); + ASSERT(r == 0); + r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); + ASSERT(r == 0); + r = uv_signal_init(loop, &signal1b); + ASSERT(r == 0); + r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); + ASSERT(r == 0); + } + + if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { + r = uv_signal_init(loop, &signal2); + ASSERT(r == 0); + r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); + ASSERT(r == 0); + } + + /* Signal watchers are now set up. */ + uv_sem_post(&sem); + + /* Wait for all signals. The signal callbacks stop the watcher, so uv_run + * will return when all signal watchers caught a signal. + */ + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + /* Restart the signal watchers. */ + if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { + r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); + ASSERT(r == 0); + r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); + ASSERT(r == 0); + } + + if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { + r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); + ASSERT(r == 0); + } + + /* Wait for signals once more. */ + uv_sem_post(&sem); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + /* Close the watchers. */ + if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { + uv_close((uv_handle_t*) &signal1a, NULL); + uv_close((uv_handle_t*) &signal1b, NULL); + } + + if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { + uv_close((uv_handle_t*) &signal2, NULL); + } + + /* Wait for the signal watchers to close. */ + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + uv_loop_delete(loop); +} + + +static void signal_unexpected_cb(uv_signal_t* handle, int signum) { + ASSERT(0 && "signal_unexpected_cb should never be called"); +} + + +static void loop_creating_worker(void* context) { + (void) context; + + do { + uv_loop_t* loop; + uv_signal_t signal; + int r; + + loop = uv_loop_new(); + ASSERT(loop != NULL); + + r = uv_signal_init(loop, &signal); + ASSERT(r == 0); + + r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &signal, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + uv_loop_delete(loop); + + increment_counter(&loop_creation_counter); + } while (!stop); +} + + +TEST_IMPL(signal_multiple_loops) { + uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS]; + uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS]; + enum signal_action action; + sigset_t sigset; + int i; + int r; + + r = uv_sem_init(&sem, 0); + ASSERT(r == 0); + + r = uv_mutex_init(&counter_lock); + ASSERT(r == 0); + + /* Create a couple of threads that create a destroy loops continuously. */ + for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { + r = uv_thread_create(&loop_creating_threads[i], + loop_creating_worker, + NULL); + ASSERT(r == 0); + } + + /* Create a couple of threads that actually handle signals. */ + for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) { + switch (i % 3) { + case 0: action = ONLY_SIGUSR1; break; + case 1: action = ONLY_SIGUSR2; break; + case 2: action = SIGUSR1_AND_SIGUSR2; break; + } + + r = uv_thread_create(&signal_handling_threads[i], + signal_handling_worker, + (void*) (uintptr_t) action); + ASSERT(r == 0); + } + + /* Wait until all threads have started and set up their signal watchers. */ + for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) + uv_sem_wait(&sem); + + r = kill(getpid(), SIGUSR1); + ASSERT(r == 0); + r = kill(getpid(), SIGUSR2); + ASSERT(r == 0); + + /* Wait for all threads to handle these signals. */ + for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) + uv_sem_wait(&sem); + + /* Block all signals to this thread, so we are sure that from here the signal + * handler runs in another thread. This is is more likely to catch thread and + * signal safety issues if there are any. + */ + sigfillset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + r = kill(getpid(), SIGUSR1); + ASSERT(r == 0); + r = kill(getpid(), SIGUSR2); + ASSERT(r == 0); + + /* Wait for all signal handling threads to exit. */ + for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) { + r = uv_thread_join(&signal_handling_threads[i]); + ASSERT(r == 0); + } + + /* Tell all loop creating threads to stop. */ + stop = 1; + + /* Wait for all loop creating threads to exit. */ + for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { + r = uv_thread_join(&loop_creating_threads[i]); + ASSERT(r == 0); + } + + printf("signal1_cb calls: %d\n", signal1_cb_counter); + printf("signal2_cb calls: %d\n", signal2_cb_counter); + printf("loops created and destroyed: %d\n", loop_creation_counter); + + /* The division by three reflects the fact that we spawn three different + * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each. + */ + ASSERT(signal1_cb_counter == 8 * (NUM_SIGNAL_HANDLING_THREADS / 3)); + ASSERT(signal2_cb_counter == 4 * (NUM_SIGNAL_HANDLING_THREADS / 3)); + + /* We don't know exactly how much loops will be created and destroyed, but at + * least there should be 1 for every loop creating thread. + */ + ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/test/test-signal.c b/test/test-signal.c new file mode 100644 index 0000000000..9fb1c7f916 --- /dev/null +++ b/test/test-signal.c @@ -0,0 +1,152 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +/* This test does not pretend to be cross-platform. */ +#ifndef _WIN32 + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include +#include +#include +#include + +#define NSIGNALS 10 + +struct timer_ctx { + unsigned int ncalls; + uv_timer_t handle; + int signum; +}; + +struct signal_ctx { + enum { CLOSE, STOP } stop_or_close; + unsigned int ncalls; + uv_signal_t handle; + int signum; +}; + + +static void signal_cb(uv_signal_t* handle, int signum) { + struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); + ASSERT(signum == ctx->signum); + + if (++ctx->ncalls == NSIGNALS) { + if (ctx->stop_or_close == STOP) + uv_signal_stop(handle); + else if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); + else + ASSERT(0); + } +} + + +static void timer_cb(uv_timer_t* handle, int status) { + struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle); + + raise(ctx->signum); + + if (++ctx->ncalls == NSIGNALS) + uv_close((uv_handle_t*)handle, NULL); +} + + +static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ctx->stop_or_close = CLOSE; + ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum)); +} + + +static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ASSERT(0 == uv_timer_init(loop, &ctx->handle)); + ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5)); +} + + +TEST_IMPL(we_get_signal) { + struct signal_ctx sc; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, &sc); + sc.stop_or_close = STOP; /* stop, don't close the signal handle */ + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + sc.ncalls = 0; + sc.stop_or_close = CLOSE; /* now close it when it's done */ + uv_signal_start(&sc.handle, signal_cb, SIGCHLD); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(we_get_signals) { + struct signal_ctx sc[4]; + struct timer_ctx tc[2]; + uv_loop_t* loop; + unsigned int i; + + loop = uv_default_loop(); + start_watcher(loop, SIGUSR1, sc + 0); + start_watcher(loop, SIGUSR1, sc + 1); + start_watcher(loop, SIGUSR2, sc + 2); + start_watcher(loop, SIGUSR2, sc + 3); + start_timer(loop, SIGUSR1, tc + 0); + start_timer(loop, SIGUSR2, tc + 1); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + for (i = 0; i < ARRAY_SIZE(sc); i++) + ASSERT(sc[i].ncalls == NSIGNALS); + + for (i = 0; i < ARRAY_SIZE(tc); i++) + ASSERT(tc[i].ncalls == NSIGNALS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* _WIN32 */ diff --git a/test/test-spawn.c b/test/test-spawn.c new file mode 100644 index 0000000000..5f71fce2c0 --- /dev/null +++ b/test/test-spawn.c @@ -0,0 +1,1051 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + + +static int close_cb_called; +static int exit_cb_called; +static uv_process_t process; +static uv_timer_t timer; +static uv_process_options_t options; +static char exepath[1024]; +static size_t exepath_size = 1024; +static char* args[3]; +static int no_term_signal; + +#define OUTPUT_SIZE 1024 +static char output[OUTPUT_SIZE]; +static int output_used; + + +static void close_cb(uv_handle_t* handle) { + printf("close_cb\n"); + close_cb_called++; +} + +static void exit_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + printf("exit_cb\n"); + exit_cb_called++; + ASSERT(exit_status == 1); + ASSERT(term_signal == 0); + uv_close((uv_handle_t*)process, close_cb); +} + + +static void fail_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + ASSERT(0 && "fail_cb called"); +} + + +static void kill_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + int err; + + printf("exit_cb\n"); + exit_cb_called++; +#ifdef _WIN32 + ASSERT(exit_status == 1); +#else + ASSERT(exit_status == 0); +#endif + ASSERT(no_term_signal || term_signal == 15); + uv_close((uv_handle_t*)process, close_cb); + + /* + * Sending signum == 0 should check if the + * child process is still alive, not kill it. + * This process should be dead. + */ + err = uv_kill(process->pid, 0); + ASSERT(err == UV_ESRCH); +} + +static void detach_failure_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + printf("detach_cb\n"); + exit_cb_called++; +} + +static void on_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = output + output_used; + buf->len = OUTPUT_SIZE - output_used; +} + + +static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + output_used += nread; + } else if (nread < 0) { + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t*)tcp, close_cb); + } +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + uv_close((uv_handle_t*)req->handle, close_cb); +} + + +static void init_process_options(char* test, uv_exit_cb exit_cb) { + /* Note spawn_helper1 defined in test/run-tests.c */ + int r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + exepath[exepath_size] = '\0'; + args[0] = exepath; + args[1] = test; + args[2] = NULL; + options.file = exepath; + options.args = args; + options.exit_cb = exit_cb; + options.flags = 0; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_process_kill(&process, /* SIGTERM */ 15); + uv_close((uv_handle_t*)handle, close_cb); +} + + +TEST_IMPL(spawn_fails) { + int r; + + init_process_options("", fail_cb); + options.file = options.args[0] = "program-that-had-better-not-exist"; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_ENOENT || r == UV_EACCES); + ASSERT(0 == uv_is_active((uv_handle_t*) &process)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_exit_code) { + int r; + + init_process_options("spawn_helper1", exit_cb); + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_stdout) { + int r; + uv_pipe_t out; + uv_stdio_container_t stdio[2]; + + init_process_options("spawn_helper2", exit_cb); + + uv_pipe_init(uv_default_loop(), &out, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + printf("output is: %s", output); + ASSERT(strcmp("hello world\n", output) == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_stdout_to_file) { + int r; + uv_file file; + uv_fs_t fs_req; + uv_stdio_container_t stdio[2]; + + /* Setup. */ + unlink("stdout_file"); + + init_process_options("spawn_helper2", exit_cb); + + r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR, NULL); + ASSERT(r != -1); + uv_fs_req_cleanup(&fs_req); + + file = r; + + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = file; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output), + 0, NULL); + ASSERT(r == 12); + uv_fs_req_cleanup(&fs_req); + + r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&fs_req); + + printf("output is: %s", output); + ASSERT(strcmp("hello world\n", output) == 0); + + /* Cleanup. */ + unlink("stdout_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_stdout_and_stderr_to_file) { + int r; + uv_file file; + uv_fs_t fs_req; + uv_stdio_container_t stdio[3]; + + /* Setup. */ + unlink("stdout_file"); + + init_process_options("spawn_helper6", exit_cb); + + r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR, + S_IREAD | S_IWRITE, NULL); + ASSERT(r != -1); + uv_fs_req_cleanup(&fs_req); + + file = r; + + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = file; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = file; + options.stdio_count = 3; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output), + 0, NULL); + ASSERT(r == 27); + uv_fs_req_cleanup(&fs_req); + + r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&fs_req); + + printf("output is: %s", output); + ASSERT(strcmp("hello world\nhello errworld\n", output) == 0); + + /* Cleanup. */ + unlink("stdout_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_stdin) { + int r; + uv_pipe_t out; + uv_pipe_t in; + uv_write_t write_req; + uv_buf_t buf; + uv_stdio_container_t stdio[2]; + char buffer[] = "hello-from-spawn_stdin"; + + init_process_options("spawn_helper3", exit_cb); + + uv_pipe_init(uv_default_loop(), &out, 0); + uv_pipe_init(uv_default_loop(), &in, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + buf.base = buffer; + buf.len = sizeof(buffer); + r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */ + ASSERT(strcmp(buffer, output) == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_stdio_greater_than_3) { + int r; + uv_pipe_t pipe; + uv_stdio_container_t stdio[4]; + + init_process_options("spawn_helper5", exit_cb); + + uv_pipe_init(uv_default_loop(), &pipe, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_IGNORE; + options.stdio[2].flags = UV_IGNORE; + options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[3].data.stream = (uv_stream_t*)&pipe; + options.stdio_count = 4; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + printf("output from stdio[3] is: %s", output); + ASSERT(strcmp("fourth stdio!\n", output) == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_ignored_stdio) { + int r; + + init_process_options("spawn_helper6", exit_cb); + + options.stdio = NULL; + options.stdio_count = 0; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_and_kill) { + int r; + + init_process_options("spawn_helper4", kill_cb); + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 500, 0); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); /* Once for process and once for timer. */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_preserve_env) { + int r; + uv_pipe_t out; + uv_stdio_container_t stdio[2]; + + init_process_options("spawn_helper7", exit_cb); + + uv_pipe_init(uv_default_loop(), &out, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*) &out; + options.stdio_count = 2; + + r = putenv("ENV_TEST=testval"); + ASSERT(r == 0); + + /* Explicitly set options.env to NULL to test for env clobbering. */ + options.env = NULL; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); + + printf("output is: %s", output); + ASSERT(strcmp("testval", output) == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_detached) { + int r; + + init_process_options("spawn_helper4", detach_failure_cb); + + options.flags |= UV_PROCESS_DETACHED; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + uv_unref((uv_handle_t*)&process); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 0); + + r = uv_kill(process.pid, 0); + ASSERT(r == 0); + + r = uv_kill(process.pid, 15); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(spawn_and_kill_with_std) { + int r; + uv_pipe_t in, out, err; + uv_write_t write; + char message[] = "Nancy's joining me because the message this evening is " + "not my message but ours."; + uv_buf_t buf; + uv_stdio_container_t stdio[3]; + + init_process_options("spawn_helper4", kill_cb); + + r = uv_pipe_init(uv_default_loop(), &in, 0); + ASSERT(r == 0); + + r = uv_pipe_init(uv_default_loop(), &out, 0); + ASSERT(r == 0); + + r = uv_pipe_init(uv_default_loop(), &err, 0); + ASSERT(r == 0); + + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[2].data.stream = (uv_stream_t*)&err; + options.stdio_count = 3; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + buf = uv_buf_init(message, sizeof message); + r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 500, 0); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_and_ping) { + uv_write_t write_req; + uv_pipe_t in, out; + uv_buf_t buf; + uv_stdio_container_t stdio[2]; + int r; + + init_process_options("spawn_helper3", exit_cb); + buf = uv_buf_init("TEST", 4); + + uv_pipe_init(uv_default_loop(), &out, 0); + uv_pipe_init(uv_default_loop(), &in, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + r = uv_process_kill(&process, 0); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(strcmp(output, "TEST") == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_same_stdout_stderr) { + uv_write_t write_req; + uv_pipe_t in, out; + uv_buf_t buf; + uv_stdio_container_t stdio[3]; + int r; + + init_process_options("spawn_helper3", exit_cb); + buf = uv_buf_init("TEST", 4); + + uv_pipe_init(uv_default_loop(), &out, 0); + uv_pipe_init(uv_default_loop(), &in, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + r = uv_process_kill(&process, 0); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(strcmp(output, "TEST") == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(kill) { + int r; + +#ifdef _WIN32 + no_term_signal = 1; +#endif + + init_process_options("spawn_helper4", kill_cb); + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + r = uv_kill(process.pid, 0); + ASSERT(r == 0); + + /* Kill the process. */ + r = uv_kill(process.pid, /* SIGTERM */ 15); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#ifdef _WIN32 +TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { + int r; + uv_pipe_t out; + char name[64]; + HANDLE pipe_handle; + uv_stdio_container_t stdio[2]; + + init_process_options("spawn_helper2", exit_cb); + + uv_pipe_init(uv_default_loop(), &out, 0); + options.stdio = stdio; + options.stdio[0].flags = UV_IGNORE; + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + /* Create a pipe that'll cause a collision. */ + _snprintf(name, + sizeof(name), + "\\\\.\\pipe\\uv\\%p-%d", + &out, + GetCurrentProcessId()); + pipe_handle = CreateNamedPipeA(name, + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + 10, + 65536, + 65536, + 0, + NULL); + ASSERT(pipe_handle != INVALID_HANDLE_VALUE); + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + printf("output is: %s", output); + ASSERT(strcmp("hello world\n", output) == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr); +WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target); + +TEST_IMPL(argument_escaping) { + const WCHAR* test_str[] = { + L"HelloWorld", + L"Hello World", + L"Hello\"World", + L"Hello World\\", + L"Hello\\\"World", + L"Hello\\World", + L"Hello\\\\World", + L"Hello World\\", + L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"" + }; + const int count = sizeof(test_str) / sizeof(*test_str); + WCHAR** test_output; + WCHAR* command_line; + WCHAR** cracked; + size_t total_size = 0; + int i; + int num_args; + int result; + + char* verbatim[] = { + "cmd.exe", + "/c", + "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"", + NULL + }; + WCHAR* verbatim_output; + WCHAR* non_verbatim_output; + + test_output = calloc(count, sizeof(WCHAR*)); + for (i = 0; i < count; ++i) { + test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR)); + quote_cmd_arg(test_str[i], test_output[i]); + wprintf(L"input : %s\n", test_str[i]); + wprintf(L"output: %s\n", test_output[i]); + total_size += wcslen(test_output[i]) + 1; + } + command_line = calloc(total_size + 1, sizeof(WCHAR)); + for (i = 0; i < count; ++i) { + wcscat(command_line, test_output[i]); + wcscat(command_line, L" "); + } + command_line[total_size - 1] = L'\0'; + + wprintf(L"command_line: %s\n", command_line); + + cracked = CommandLineToArgvW(command_line, &num_args); + for (i = 0; i < num_args; ++i) { + wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]); + ASSERT(wcscmp(test_str[i], cracked[i]) == 0); + } + + LocalFree(cracked); + for (i = 0; i < count; ++i) { + free(test_output[i]); + } + + result = make_program_args(verbatim, 1, &verbatim_output); + ASSERT(result == 0); + result = make_program_args(verbatim, 0, &non_verbatim_output); + ASSERT(result == 0); + + wprintf(L" verbatim_output: %s\n", verbatim_output); + wprintf(L"non_verbatim_output: %s\n", non_verbatim_output); + + ASSERT(wcscmp(verbatim_output, + L"cmd.exe /c c:\\path\\to\\node.exe --eval " + L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0); + ASSERT(wcscmp(non_verbatim_output, + L"cmd.exe /c \"c:\\path\\to\\node.exe --eval " + L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0); + + free(verbatim_output); + free(non_verbatim_output); + + return 0; +} + +int make_program_env(char** env_block, WCHAR** dst_ptr); + +TEST_IMPL(environment_creation) { + int i; + char* environment[] = { + "FOO=BAR", + "SYSTEM=ROOT", /* substring of a supplied var name */ + "SYSTEMROOTED=OMG", /* supplied var name is a substring */ + "TEMP=C:\\Temp", + "BAZ=QUX", + NULL + }; + + WCHAR expected[512]; + WCHAR* ptr = expected; + int result; + WCHAR* str; + WCHAR* env; + + for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) { + ptr += uv_utf8_to_utf16(environment[i], + ptr, + expected + sizeof(expected) - ptr); + } + + memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT=")); + ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1; + ptr += GetEnvironmentVariableW(L"SYSTEMROOT", + ptr, + expected + sizeof(expected) - ptr); + ++ptr; + + memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE=")); + ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1; + ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", + ptr, + expected + sizeof(expected) - ptr); + ++ptr; + *ptr = '\0'; + + result = make_program_env(environment, &env); + ASSERT(result == 0); + + for (str = env; *str; str += wcslen(str) + 1) { + wprintf(L"%s\n", str); + } + + ASSERT(wcscmp(expected, env) == 0); + + return 0; +} +#endif + +#ifndef _WIN32 +TEST_IMPL(spawn_setuid_setgid) { + int r; + + /* if not root, then this will fail. */ + uv_uid_t uid = getuid(); + if (uid != 0) { + fprintf(stderr, "spawn_setuid_setgid skipped: not root\n"); + return 0; + } + + init_process_options("spawn_helper1", exit_cb); + + /* become the "nobody" user. */ + struct passwd* pw; + pw = getpwnam("nobody"); + ASSERT(pw != NULL); + options.uid = pw->pw_uid; + options.gid = pw->pw_gid; + options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +#ifndef _WIN32 +TEST_IMPL(spawn_setuid_fails) { + int r; + + /* if root, become nobody. */ + uv_uid_t uid = getuid(); + if (uid == 0) { + struct passwd* pw; + pw = getpwnam("nobody"); + ASSERT(pw != NULL); + ASSERT(0 == setgid(pw->pw_gid)); + ASSERT(0 == setuid(pw->pw_uid)); + } + + init_process_options("spawn_helper1", fail_cb); + + options.flags |= UV_PROCESS_SETUID; + options.uid = 0; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_EPERM); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_setgid_fails) { + int r; + + /* if root, become nobody. */ + uv_uid_t uid = getuid(); + if (uid == 0) { + struct passwd* pw; + pw = getpwnam("nobody"); + ASSERT(pw != NULL); + ASSERT(0 == setgid(pw->pw_gid)); + ASSERT(0 == setuid(pw->pw_uid)); + } + + init_process_options("spawn_helper1", fail_cb); + + options.flags |= UV_PROCESS_SETGID; + options.gid = 0; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_EPERM); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +#ifdef _WIN32 + +static void exit_cb_unexpected(uv_process_t* process, + int64_t exit_status, + int term_signal) { + ASSERT(0 && "should not have been called"); +} + + +TEST_IMPL(spawn_setuid_fails) { + int r; + + init_process_options("spawn_helper1", exit_cb_unexpected); + + options.flags |= UV_PROCESS_SETUID; + options.uid = (uv_uid_t) -42424242; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_ENOTSUP); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(spawn_setgid_fails) { + int r; + + init_process_options("spawn_helper1", exit_cb_unexpected); + + options.flags |= UV_PROCESS_SETGID; + options.gid = (uv_gid_t) -42424242; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_ENOTSUP); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +TEST_IMPL(spawn_auto_unref) { + init_process_options("spawn_helper1", NULL); + ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &process)); + uv_close((uv_handle_t*) &process, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == uv_is_closing((uv_handle_t*) &process)); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-stdio-over-pipes.c b/test/test-stdio-over-pipes.c new file mode 100644 index 0000000000..1574476104 --- /dev/null +++ b/test/test-stdio-over-pipes.c @@ -0,0 +1,255 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +static char exepath[1024]; +static size_t exepath_size = 1024; +static char* args[3]; +static uv_process_options_t options; +static int close_cb_called; +static int exit_cb_called; +static int on_read_cb_called; +static int after_write_cb_called; +static uv_pipe_t in; +static uv_pipe_t out; +static uv_loop_t* loop; +#define OUTPUT_SIZE 1024 +static char output[OUTPUT_SIZE]; +static int output_used; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void exit_cb(uv_process_t* process, + int64_t exit_status, + int term_signal) { + printf("exit_cb\n"); + exit_cb_called++; + ASSERT(exit_status == 0); + ASSERT(term_signal == 0); + uv_close((uv_handle_t*)process, close_cb); + uv_close((uv_handle_t*)&in, close_cb); + uv_close((uv_handle_t*)&out, close_cb); +} + + +static void init_process_options(char* test, uv_exit_cb exit_cb) { + int r = uv_exepath(exepath, &exepath_size); + ASSERT(r == 0); + exepath[exepath_size] = '\0'; + args[0] = exepath; + args[1] = test; + args[2] = NULL; + options.file = exepath; + options.args = args; + options.exit_cb = exit_cb; +} + + +static void on_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = output + output_used; + buf->len = OUTPUT_SIZE - output_used; +} + + +static void after_write(uv_write_t* req, int status) { + if (status) { + fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); + ASSERT(0); + } + + /* Free the read/write buffer and the request */ + free(req); + + after_write_cb_called++; +} + + +static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) { + uv_write_t* req; + uv_buf_t wrbuf; + int r; + + ASSERT(nread > 0 || nread == UV_EOF); + + if (nread > 0) { + output_used += nread; + if (output_used == 12) { + ASSERT(memcmp("hello world\n", output, 12) == 0); + wrbuf = uv_buf_init(output, output_used); + req = malloc(sizeof(*req)); + r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write); + ASSERT(r == 0); + } + } + + on_read_cb_called++; +} + + +TEST_IMPL(stdio_over_pipes) { + int r; + uv_process_t process; + uv_stdio_container_t stdio[2]; + + loop = uv_default_loop(); + + init_process_options("stdio_over_pipes_helper", exit_cb); + + uv_pipe_init(loop, &out, 0); + uv_pipe_init(loop, &in, 0); + + options.stdio = stdio; + options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + options.stdio[0].data.stream = (uv_stream_t*)∈ + options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; + options.stdio[1].data.stream = (uv_stream_t*)&out; + options.stdio_count = 2; + + r = uv_spawn(loop, &process, &options); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(on_read_cb_called > 1); + ASSERT(after_write_cb_called == 1); + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 3); + ASSERT(memcmp("hello world\n", output, 12) == 0); + ASSERT(output_used == 12); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +/* Everything here runs in a child process. */ + +static int on_pipe_read_called; +static int after_write_called; +static uv_pipe_t stdin_pipe; +static uv_pipe_t stdout_pipe; + +static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + ASSERT(nread > 0); + ASSERT(memcmp("hello world\n", buf->base, nread) == 0); + on_pipe_read_called++; + + free(buf->base); + + uv_close((uv_handle_t*)&stdin_pipe, close_cb); + uv_close((uv_handle_t*)&stdout_pipe, close_cb); +} + + +static void after_pipe_write(uv_write_t* req, int status) { + ASSERT(status == 0); + after_write_called++; +} + + +static void on_read_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + + +int stdio_over_pipes_helper(void) { + /* Write several buffers to test that the write order is preserved. */ + char* buffers[] = { + "he", + "ll", + "o ", + "wo", + "rl", + "d", + "\n" + }; + + uv_write_t write_req[ARRAY_SIZE(buffers)]; + uv_buf_t buf[ARRAY_SIZE(buffers)]; + unsigned int i; + int r; + uv_loop_t* loop = uv_default_loop(); + + ASSERT(UV_NAMED_PIPE == uv_guess_handle(0)); + ASSERT(UV_NAMED_PIPE == uv_guess_handle(1)); + + r = uv_pipe_init(loop, &stdin_pipe, 0); + ASSERT(r == 0); + r = uv_pipe_init(loop, &stdout_pipe, 0); + ASSERT(r == 0); + + uv_pipe_open(&stdin_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + /* Unref both stdio handles to make sure that all writes complete. */ + uv_unref((uv_handle_t*)&stdin_pipe); + uv_unref((uv_handle_t*)&stdout_pipe); + + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); + } + + for (i = 0; i < ARRAY_SIZE(buffers); i++) { + r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1, + after_pipe_write); + ASSERT(r == 0); + } + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(after_write_called == 7); + ASSERT(on_pipe_read_called == 0); + ASSERT(close_cb_called == 0); + + uv_ref((uv_handle_t*)&stdout_pipe); + uv_ref((uv_handle_t*)&stdin_pipe); + + r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(after_write_called == 7); + ASSERT(on_pipe_read_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c new file mode 100644 index 0000000000..96bfe11601 --- /dev/null +++ b/test/test-tcp-bind-error.c @@ -0,0 +1,199 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(tcp_bind_error_addrinuse) { + struct sockaddr_in addr; + uv_tcp_t server1, server2; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + r = uv_tcp_init(uv_default_loop(), &server1); + ASSERT(r == 0); + r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_tcp_init(uv_default_loop(), &server2); + ASSERT(r == 0); + r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server1, 128, NULL); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server2, 128, NULL); + ASSERT(r == UV_EADDRINUSE); + + uv_close((uv_handle_t*)&server1, close_cb); + uv_close((uv_handle_t*)&server2, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind_error_addrnotavail_1) { + struct sockaddr_in addr; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip4_addr("127.255.255.255", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + /* It seems that Linux is broken here - bind succeeds. */ + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0 || r == UV_EADDRNOTAVAIL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind_error_addrnotavail_2) { + struct sockaddr_in addr; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip4_addr("4.4.4.4", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == UV_EADDRNOTAVAIL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind_error_fault) { + char garbage[] = + "blah blah blah blah blah blah blah blah blah blah blah blah"; + struct sockaddr_in* garbage_addr; + uv_tcp_t server; + int r; + + garbage_addr = (struct sockaddr_in*) &garbage; + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* Notes: On Linux uv_bind(server, NULL) will segfault the program. */ + +TEST_IMPL(tcp_bind_error_inval) { + struct sockaddr_in addr1; + struct sockaddr_in addr2; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1)); + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind_localhost_ok) { + struct sockaddr_in addr; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_listen_without_bind) { + int r; + uv_tcp_t server; + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server, 128, NULL); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-bind6-error.c b/test/test-tcp-bind6-error.c new file mode 100644 index 0000000000..1d65f3de3e --- /dev/null +++ b/test/test-tcp-bind6-error.c @@ -0,0 +1,161 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +static int close_cb_called = 0; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(tcp_bind6_error_addrinuse) { + struct sockaddr_in6 addr; + uv_tcp_t server1, server2; + int r; + + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server1); + ASSERT(r == 0); + r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_tcp_init(uv_default_loop(), &server2); + ASSERT(r == 0); + r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server1, 128, NULL); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server2, 128, NULL); + ASSERT(r == UV_EADDRINUSE); + + uv_close((uv_handle_t*)&server1, close_cb); + uv_close((uv_handle_t*)&server2, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind6_error_addrnotavail) { + struct sockaddr_in6 addr; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == UV_EADDRNOTAVAIL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind6_error_fault) { + char garbage[] = + "blah blah blah blah blah blah blah blah blah blah blah blah"; + struct sockaddr_in6* garbage_addr; + uv_tcp_t server; + int r; + + garbage_addr = (struct sockaddr_in6*) &garbage; + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* Notes: On Linux uv_bind6(server, NULL) will segfault the program. */ + +TEST_IMPL(tcp_bind6_error_inval) { + struct sockaddr_in6 addr1; + struct sockaddr_in6 addr2; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1)); + ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_bind6_localhost_ok) { + struct sockaddr_in6 addr; + uv_tcp_t server; + int r; + + ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c new file mode 100644 index 0000000000..10f9d91964 --- /dev/null +++ b/test/test-tcp-close-accept.c @@ -0,0 +1,183 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +static struct sockaddr_in addr; +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_outgoing[2]; +static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)]; +static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)]; +static uv_tcp_t tcp_check; +static uv_connect_t tcp_check_req; +static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)]; +static unsigned int got_connections; +static unsigned int close_cb_called; +static unsigned int write_cb_called; +static unsigned int read_cb_called; + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + write_cb_called++; +} + +static void connect_cb(uv_connect_t* req, int status) { + unsigned int i; + uv_buf_t buf; + uv_stream_t* outgoing; + + if (req == &tcp_check_req) { + ASSERT(status != 0); + + /* Close check and incoming[0], time to finish test */ + uv_close((uv_handle_t*) &tcp_incoming[0], close_cb); + uv_close((uv_handle_t*) &tcp_check, close_cb); + return; + } + + ASSERT(status == 0); + ASSERT(connect_reqs <= req); + ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs)); + i = req - connect_reqs; + + buf = uv_buf_init("x", 1); + outgoing = (uv_stream_t*) &tcp_outgoing[i]; + ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb)); +} + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char slab[1]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + uv_loop_t* loop; + unsigned int i; + + /* Only first stream should receive read events */ + ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]); + ASSERT(0 == uv_read_stop(stream)); + ASSERT(1 == nread); + + loop = stream->loop; + read_cb_called++; + + /* Close all active incomings, except current one */ + for (i = 1; i < got_connections; i++) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + + /* Create new fd that should be one of the closed incomings */ + ASSERT(0 == uv_tcp_init(loop, &tcp_check)); + ASSERT(0 == uv_tcp_connect(&tcp_check_req, + &tcp_check, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); + + /* Close server, so no one will connect to it */ + uv_close((uv_handle_t*) &tcp_server, close_cb); +} + +static void connection_cb(uv_stream_t* server, int status) { + unsigned int i; + uv_tcp_t* incoming; + + ASSERT(server == (uv_stream_t*) &tcp_server); + + /* Ignore tcp_check connection */ + if (got_connections == ARRAY_SIZE(tcp_incoming)) + return; + + /* Accept everyone */ + incoming = &tcp_incoming[got_connections++]; + ASSERT(0 == uv_tcp_init(server->loop, incoming)); + ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming)); + + if (got_connections != ARRAY_SIZE(tcp_incoming)) + return; + + /* Once all clients are accepted - start reading */ + for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) { + incoming = &tcp_incoming[i]; + ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb)); + } +} + +TEST_IMPL(tcp_close_accept) { + unsigned int i; + uv_loop_t* loop; + uv_tcp_t* client; + + /* + * A little explanation of what goes on below: + * + * We'll create server and connect to it using two clients, each writing one + * byte once connected. + * + * When all clients will be accepted by server - we'll start reading from them + * and, on first client's first byte, will close second client and server. + * After that, we'll immediately initiate new connection to server using + * tcp_check handle (thus, reusing fd from second client). + * + * In this situation uv__io_poll()'s event list should still contain read + * event for second client, and, if not cleaned up properly, `tcp_check` will + * receive stale event of second incoming and invoke `connect_cb` with zero + * status. + */ + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(loop, &tcp_server)); + ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server, + ARRAY_SIZE(tcp_outgoing), + connection_cb)); + + for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) { + client = tcp_outgoing + i; + + ASSERT(0 == uv_tcp_init(loop, client)); + ASSERT(0 == uv_tcp_connect(&connect_reqs[i], + client, + (const struct sockaddr*) &addr, + connect_cb)); + } + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections); + ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called); + ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called); + ASSERT(1 == read_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c new file mode 100644 index 0000000000..b9f7f9661c --- /dev/null +++ b/test/test-tcp-close-while-connecting.c @@ -0,0 +1,82 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer1_handle; +static uv_timer_t timer2_handle; +static uv_tcp_t tcp_handle; + +static int connect_cb_called; +static int timer1_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(status == UV_ECANCELED); + uv_timer_stop(&timer2_handle); + connect_cb_called++; +} + + +static void timer1_cb(uv_timer_t* handle, int status) { + uv_close((uv_handle_t*)handle, close_cb); + uv_close((uv_handle_t*)&tcp_handle, close_cb); + timer1_cb_called++; +} + + +static void timer2_cb(uv_timer_t* handle, int status) { + ASSERT(0 && "should not be called"); +} + + +TEST_IMPL(tcp_close_while_connecting) { + uv_connect_t connect_req; + struct sockaddr_in addr; + uv_loop_t* loop; + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("1.2.3.4", TEST_PORT, &addr)); + ASSERT(0 == uv_tcp_init(loop, &tcp_handle)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &tcp_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT(0 == uv_timer_init(loop, &timer1_handle)); + ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0)); + ASSERT(0 == uv_timer_init(loop, &timer2_handle)); + ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(timer1_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-close.c b/test/test-tcp-close.c new file mode 100644 index 0000000000..e65885aa55 --- /dev/null +++ b/test/test-tcp-close.c @@ -0,0 +1,136 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include /* memset */ + +#define NUM_WRITE_REQS 32 + +static uv_tcp_t tcp_handle; +static uv_connect_t connect_req; + +static int write_cb_called; +static int close_cb_called; + +static void connect_cb(uv_connect_t* req, int status); +static void write_cb(uv_write_t* req, int status); +static void close_cb(uv_handle_t* handle); + + +static void connect_cb(uv_connect_t* conn_req, int status) { + uv_write_t* req; + uv_buf_t buf; + int i, r; + + buf = uv_buf_init("PING", 4); + for (i = 0; i < NUM_WRITE_REQS; i++) { + req = malloc(sizeof *req); + ASSERT(req != NULL); + + r = uv_write(req, (uv_stream_t*)&tcp_handle, &buf, 1, write_cb); + ASSERT(r == 0); + } + + uv_close((uv_handle_t*)&tcp_handle, close_cb); +} + + +static void write_cb(uv_write_t* req, int status) { + /* write callbacks should run before the close callback */ + ASSERT(close_cb_called == 0); + ASSERT(req->handle == (uv_stream_t*)&tcp_handle); + write_cb_called++; + free(req); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*)&tcp_handle); + close_cb_called++; +} + + +static void connection_cb(uv_stream_t* server, int status) { + ASSERT(status == 0); +} + + +static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, handle); + ASSERT(r == 0); + + r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)handle, 128, connection_cb); + ASSERT(r == 0); + + uv_unref((uv_handle_t*)handle); +} + + +/* Check that pending write requests have their callbacks + * invoked when the handle is closed. + */ +TEST_IMPL(tcp_close) { + struct sockaddr_in addr; + uv_tcp_t tcp_server; + uv_loop_t* loop; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + loop = uv_default_loop(); + + /* We can't use the echo server, it doesn't handle ECONNRESET. */ + start_server(loop, &tcp_server); + + r = uv_tcp_init(loop, &tcp_handle); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &tcp_handle, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + ASSERT(write_cb_called == 0); + ASSERT(close_cb_called == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + printf("%d of %d write reqs seen\n", write_cb_called, NUM_WRITE_REQS); + + ASSERT(write_cb_called == NUM_WRITE_REQS); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-connect-error-after-write.c b/test/test-tcp-connect-error-after-write.c new file mode 100644 index 0000000000..3f2e3572da --- /dev/null +++ b/test/test-tcp-connect-error-after-write.c @@ -0,0 +1,98 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +static int connect_cb_called; +static int write_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(status < 0); + connect_cb_called++; + uv_close((uv_handle_t*)req->handle, close_cb); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status < 0); + write_cb_called++; +} + + +/* + * Try to connect to an address on which nothing listens, get ECONNREFUSED + * (uv errno 12) and get connect_cb() called once with status != 0. + * Related issue: https://github.com/joyent/libuv/issues/443 + */ +TEST_IMPL(tcp_connect_error_after_write) { + uv_connect_t connect_req; + struct sockaddr_in addr; + uv_write_t write_req; + uv_tcp_t conn; + uv_buf_t buf; + int r; + +#ifdef _WIN32 + fprintf(stderr, "This test is disabled on Windows for now.\n"); + fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n"); + return 0; /* windows slackers... */ +#endif + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + buf = uv_buf_init("TEST", 4); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == UV_EBADF); + + r = uv_tcp_connect(&connect_req, + &conn, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-connect-error.c b/test/test-tcp-connect-error.c new file mode 100644 index 0000000000..eab1eeb254 --- /dev/null +++ b/test/test-tcp-connect-error.c @@ -0,0 +1,73 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +static int connect_cb_called = 0; +static int close_cb_called = 0; + + + +static void connect_cb(uv_connect_t* handle, int status) { + ASSERT(handle != NULL); + connect_cb_called++; +} + + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(tcp_connect_error_fault) { + const char garbage[] = + "blah blah blah blah blah blah blah blah blah blah blah blah"; + const struct sockaddr_in* garbage_addr; + uv_tcp_t server; + int r; + uv_connect_t req; + + garbage_addr = (const struct sockaddr_in*) &garbage; + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_connect(&req, + &server, + (const struct sockaddr*) garbage_addr, + connect_cb); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(connect_cb_called == 0); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-connect-timeout.c b/test/test-tcp-connect-timeout.c new file mode 100644 index 0000000000..cc583cafb2 --- /dev/null +++ b/test/test-tcp-connect-timeout.c @@ -0,0 +1,89 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +static int connect_cb_called; +static int close_cb_called; + +static uv_connect_t connect_req; +static uv_timer_t timer; +static uv_tcp_t conn; + +static void connect_cb(uv_connect_t* req, int status); +static void timer_cb(uv_timer_t* handle, int status); +static void close_cb(uv_handle_t* handle); + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == UV_ECANCELED); + connect_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer); + uv_close((uv_handle_t*)&conn, close_cb); + uv_close((uv_handle_t*)&timer, close_cb); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer); + close_cb_called++; +} + + +/* Verify that connecting to an unreachable address or port doesn't hang + * the event loop. + */ +TEST_IMPL(tcp_connect_timeout) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("8.8.8.8", 9999, &addr)); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 50, 0); + ASSERT(r == 0); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &conn, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c new file mode 100644 index 0000000000..91ac0a3a10 --- /dev/null +++ b/test/test-tcp-connect6-error.c @@ -0,0 +1,71 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +static int connect_cb_called = 0; +static int close_cb_called = 0; + + +static void connect_cb(uv_connect_t* handle, int status) { + ASSERT(handle != NULL); + connect_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +TEST_IMPL(tcp_connect6_error_fault) { + const char garbage[] = + "blah blah blah blah blah blah blah blah blah blah blah blah"; + const struct sockaddr_in6* garbage_addr; + uv_tcp_t server; + int r; + uv_connect_t req; + + garbage_addr = (const struct sockaddr_in6*) &garbage; + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_connect(&req, + &server, + (const struct sockaddr*) garbage_addr, + connect_cb); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(connect_cb_called == 0); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c new file mode 100644 index 0000000000..68afb39f45 --- /dev/null +++ b/test/test-tcp-flags.c @@ -0,0 +1,52 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +TEST_IMPL(tcp_flags) { + uv_loop_t* loop; + uv_tcp_t handle; + int r; + + loop = uv_default_loop(); + + r = uv_tcp_init(loop, &handle); + ASSERT(r == 0); + + r = uv_tcp_nodelay(&handle, 1); + ASSERT(r == 0); + + r = uv_tcp_keepalive(&handle, 1, 60); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&handle, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-open.c b/test/test-tcp-open.c new file mode 100644 index 0000000000..edeacc70e4 --- /dev/null +++ b/test/test-tcp-open.c @@ -0,0 +1,182 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include + +#ifndef _WIN32 +# include +#endif + +static int shutdown_cb_called = 0; +static int connect_cb_called = 0; +static int write_cb_called = 0; +static int close_cb_called = 0; + +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; +static uv_write_t write_req; + + +static void startup(void) { +#ifdef _WIN32 + struct WSAData wsa_data; + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); +#endif +} + + +static uv_os_sock_t create_tcp_socket(void) { + uv_os_sock_t sock; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + +#ifndef _WIN32 + { + /* Allow reuse of the port. */ + int yes = 1; + int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + ASSERT(r == 0); + } +#endif + + return sock; +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &shutdown_req); + ASSERT(status == 0); + + /* Now we wait for the EOF */ + shutdown_cb_called++; +} + + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + ASSERT(tcp != NULL); + + if (nread >= 0) { + ASSERT(nread == 4); + ASSERT(memcmp("PING", buf->base, nread) == 0); + } + else { + ASSERT(nread == UV_EOF); + printf("GOT EOF\n"); + uv_close((uv_handle_t*)tcp, close_cb); + } +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req != NULL); + + if (status) { + fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); + ASSERT(0); + } + + write_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + uv_buf_t buf = uv_buf_init("PING", 4); + uv_stream_t* stream; + int r; + + ASSERT(req == &connect_req); + ASSERT(status == 0); + + stream = req->handle; + connect_cb_called++; + + r = uv_write(&write_req, stream, &buf, 1, write_cb); + ASSERT(r == 0); + + /* Shutdown on drain. */ + r = uv_shutdown(&shutdown_req, stream, shutdown_cb); + ASSERT(r == 0); + + /* Start reading */ + r = uv_read_start(stream, alloc_cb, read_cb); + ASSERT(r == 0); +} + + +TEST_IMPL(tcp_open) { + struct sockaddr_in addr; + uv_tcp_t client; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_tcp_socket(); + + r = uv_tcp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_tcp_open(&client, sock); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(shutdown_cb_called == 1); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-read-stop.c b/test/test-tcp-read-stop.c new file mode 100644 index 0000000000..c8d9c0407e --- /dev/null +++ b/test/test-tcp-read-stop.c @@ -0,0 +1,76 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer_handle; +static uv_tcp_t tcp_handle; +static uv_write_t write_req; + + +static void fail_cb(void) { + ASSERT(0 && "fail_cb called"); +} + + +static void write_cb(uv_write_t* req, int status) { + uv_close((uv_handle_t*) &timer_handle, NULL); + uv_close((uv_handle_t*) &tcp_handle, NULL); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_buf_t buf = uv_buf_init("PING", 4); + ASSERT(0 == uv_write(&write_req, + (uv_stream_t*) &tcp_handle, + &buf, + 1, + write_cb)); + ASSERT(0 == uv_read_stop((uv_stream_t*) &tcp_handle)); +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(0 == status); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_handle, + (uv_alloc_cb) fail_cb, + (uv_read_cb) fail_cb)); +} + + +TEST_IMPL(tcp_read_stop) { + uv_connect_t connect_req; + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp_handle)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &tcp_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + MAKE_VALGRIND_HAPPY(); + + return 0; +} diff --git a/test/test-tcp-shutdown-after-write.c b/test/test-tcp-shutdown-after-write.c new file mode 100644 index 0000000000..c59acc4020 --- /dev/null +++ b/test/test-tcp-shutdown-after-write.c @@ -0,0 +1,138 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static void write_cb(uv_write_t* req, int status); +static void shutdown_cb(uv_shutdown_t* req, int status); + +static uv_tcp_t conn; +static uv_timer_t timer; +static uv_connect_t connect_req; +static uv_write_t write_req; +static uv_shutdown_t shutdown_req; + +static int connect_cb_called; +static int write_cb_called; +static int shutdown_cb_called; + +static int conn_close_cb_called; +static int timer_close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + if (handle == (uv_handle_t*)&conn) + conn_close_cb_called++; + else if (handle == (uv_handle_t*)&timer) + timer_close_cb_called++; + else + ASSERT(0 && "bad handle in close_cb"); +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[64]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_buf_t buf; + int r; + + uv_close((uv_handle_t*)handle, close_cb); + + buf = uv_buf_init("TEST", 4); + r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); + ASSERT(r == 0); + + r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb); + ASSERT(r == 0); +} + + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { +} + + +static void connect_cb(uv_connect_t* req, int status) { + int r; + + ASSERT(status == 0); + connect_cb_called++; + + r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb); + ASSERT(r == 0); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + write_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(status == 0); + shutdown_cb_called++; + uv_close((uv_handle_t*)&conn, close_cb); +} + + +TEST_IMPL(tcp_shutdown_after_write) { + struct sockaddr_in addr; + uv_loop_t* loop; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + loop = uv_default_loop(); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 125, 0); + ASSERT(r == 0); + + r = uv_tcp_init(loop, &conn); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &conn, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); + ASSERT(conn_close_cb_called == 1); + ASSERT(timer_close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-try-write.c b/test/test-tcp-try-write.c new file mode 100644 index 0000000000..00341e4169 --- /dev/null +++ b/test/test-tcp-try-write.c @@ -0,0 +1,144 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define MAX_BYTES 1024 * 1024 + +#ifdef _WIN32 + +TEST_IMPL(tcp_try_write) { + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#else /* !_WIN32 */ + +static uv_tcp_t server; +static uv_tcp_t client; +static uv_tcp_t incoming; +static int connect_cb_called; +static int close_cb_called; +static int connection_cb_called; +static int bytes_read; +static int bytes_written; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + static char zeroes[1024]; + int r; + uv_buf_t buf; + ASSERT(status == 0); + connect_cb_called++; + + do { + buf = uv_buf_init(zeroes, sizeof(zeroes)); + r = uv_try_write((uv_stream_t*) &client, &buf, 1); + ASSERT(r >= 0); + bytes_written += r; + + /* Partial write */ + if (r != (int) sizeof(zeroes)) + break; + } while (1); + uv_close((uv_handle_t*) &client, close_cb); +} + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char base[1024]; + + buf->base = base; + buf->len = sizeof(base); +} + + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + if (nread < 0) { + uv_close((uv_handle_t*) tcp, close_cb); + uv_close((uv_handle_t*) &server, close_cb); + return; + } + + bytes_read += nread; +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT(status == 0); + + ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); + ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + + connection_cb_called++; + ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); +} + + +static void start_server(void) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); +} + + +TEST_IMPL(tcp_try_write) { + uv_connect_t connect_req; + struct sockaddr_in addr; + + start_server(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(close_cb_called == 3); + ASSERT(connection_cb_called == 1); + ASSERT(bytes_read == bytes_written); + ASSERT(bytes_written > 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/test/test-tcp-unexpected-read.c b/test/test-tcp-unexpected-read.c new file mode 100644 index 0000000000..11fee8ba8e --- /dev/null +++ b/test/test-tcp-unexpected-read.c @@ -0,0 +1,117 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_check_t check_handle; +static uv_timer_t timer_handle; +static uv_tcp_t server_handle; +static uv_tcp_t client_handle; +static uv_tcp_t peer_handle; +static uv_write_t write_req; +static uv_connect_t connect_req; + +static unsigned long ticks; /* event loop ticks */ + + +static void check_cb(uv_check_t* handle, int status) { + ticks++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + uv_close((uv_handle_t*) &check_handle, NULL); + uv_close((uv_handle_t*) &timer_handle, NULL); + uv_close((uv_handle_t*) &server_handle, NULL); + uv_close((uv_handle_t*) &client_handle, NULL); + uv_close((uv_handle_t*) &peer_handle, NULL); +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + ASSERT(0 && "alloc_cb should not have been called"); +} + + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + ASSERT(0 && "read_cb should not have been called"); +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req->handle == (uv_stream_t*) &client_handle); + ASSERT(0 == status); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req->handle == (uv_stream_t*) &peer_handle); + ASSERT(0 == status); +} + + +static void connection_cb(uv_stream_t* handle, int status) { + uv_buf_t buf; + + buf = uv_buf_init("PING", 4); + + ASSERT(0 == status); + ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle, + &buf, 1, write_cb)); +} + + +TEST_IMPL(tcp_unexpected_read) { + struct sockaddr_in addr; + uv_loop_t* loop; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + loop = uv_default_loop(); + + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0)); + ASSERT(0 == uv_check_init(loop, &check_handle)); + ASSERT(0 == uv_check_start(&check_handle, check_cb)); + ASSERT(0 == uv_tcp_init(loop, &server_handle)); + ASSERT(0 == uv_tcp_init(loop, &client_handle)); + ASSERT(0 == uv_tcp_init(loop, &peer_handle)); + ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &client_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + /* This is somewhat inexact but the idea is that the event loop should not + * start busy looping when the server sends a message and the client isn't + * reading. + */ + ASSERT(ticks <= 20); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-write-to-half-open-connection.c b/test/test-tcp-write-to-half-open-connection.c new file mode 100644 index 0000000000..2fa2ae7225 --- /dev/null +++ b/test/test-tcp-write-to-half-open-connection.c @@ -0,0 +1,141 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +static void connection_cb(uv_stream_t* server, int status); +static void connect_cb(uv_connect_t* req, int status); +static void write_cb(uv_write_t* req, int status); +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); +static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); + +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_client; +static uv_tcp_t tcp_peer; /* client socket as accept()-ed by server */ +static uv_connect_t connect_req; +static uv_write_t write_req; + +static int write_cb_called; +static int read_cb_called; + +static void connection_cb(uv_stream_t* server, int status) { + int r; + uv_buf_t buf; + + ASSERT(server == (uv_stream_t*)&tcp_server); + ASSERT(status == 0); + + r = uv_tcp_init(server->loop, &tcp_peer); + ASSERT(r == 0); + + r = uv_accept(server, (uv_stream_t*)&tcp_peer); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb); + ASSERT(r == 0); + + buf.base = "hello\n"; + buf.len = 6; + + r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb); + ASSERT(r == 0); +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[1024]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + if (nread < 0) { + fprintf(stderr, "read_cb error: %s\n", uv_err_name(nread)); + ASSERT(nread == UV_ECONNRESET || nread == UV_EOF); + + uv_close((uv_handle_t*)&tcp_server, NULL); + uv_close((uv_handle_t*)&tcp_peer, NULL); + } + + read_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == 0); + + /* Close the client. */ + uv_close((uv_handle_t*)&tcp_client, NULL); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + write_cb_called++; +} + + +TEST_IMPL(tcp_write_to_half_open_connection) { + struct sockaddr_in addr; + uv_loop_t* loop; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + loop = uv_default_loop(); + ASSERT(loop != NULL); + + r = uv_tcp_init(loop, &tcp_server); + ASSERT(r == 0); + + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb); + ASSERT(r == 0); + + r = uv_tcp_init(loop, &tcp_client); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(write_cb_called > 0); + ASSERT(read_cb_called > 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c new file mode 100644 index 0000000000..6cfe2ebb18 --- /dev/null +++ b/test/test-tcp-writealot.c @@ -0,0 +1,176 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + + +#define WRITES 3 +#define CHUNKS_PER_WRITE 4096 +#define CHUNK_SIZE 10024 /* 10 kb */ + +#define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE) + +static char* send_buffer; + +static int shutdown_cb_called = 0; +static int connect_cb_called = 0; +static int write_cb_called = 0; +static int close_cb_called = 0; +static size_t bytes_sent = 0; +static size_t bytes_sent_done = 0; +static size_t bytes_received_done = 0; + +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; +static uv_write_t write_reqs[WRITES]; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void shutdown_cb(uv_shutdown_t* req, int status) { + uv_tcp_t* tcp; + + ASSERT(req == &shutdown_req); + ASSERT(status == 0); + + tcp = (uv_tcp_t*)(req->handle); + + /* The write buffer should be empty by now. */ + ASSERT(tcp->write_queue_size == 0); + + /* Now we wait for the EOF */ + shutdown_cb_called++; + + /* We should have had all the writes called already. */ + ASSERT(write_cb_called == WRITES); +} + + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + ASSERT(tcp != NULL); + + if (nread >= 0) { + bytes_received_done += nread; + } + else { + ASSERT(nread == UV_EOF); + printf("GOT EOF\n"); + uv_close((uv_handle_t*)tcp, close_cb); + } + + free(buf->base); +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req != NULL); + + if (status) { + fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); + ASSERT(0); + } + + bytes_sent_done += CHUNKS_PER_WRITE * CHUNK_SIZE; + write_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + uv_buf_t send_bufs[CHUNKS_PER_WRITE]; + uv_stream_t* stream; + int i, j, r; + + ASSERT(req == &connect_req); + ASSERT(status == 0); + + stream = req->handle; + connect_cb_called++; + + /* Write a lot of data */ + for (i = 0; i < WRITES; i++) { + uv_write_t* write_req = write_reqs + i; + + for (j = 0; j < CHUNKS_PER_WRITE; j++) { + send_bufs[j] = uv_buf_init(send_buffer + bytes_sent, CHUNK_SIZE); + bytes_sent += CHUNK_SIZE; + } + + r = uv_write(write_req, stream, send_bufs, CHUNKS_PER_WRITE, write_cb); + ASSERT(r == 0); + } + + /* Shutdown on drain. */ + r = uv_shutdown(&shutdown_req, stream, shutdown_cb); + ASSERT(r == 0); + + /* Start reading */ + r = uv_read_start(stream, alloc_cb, read_cb); + ASSERT(r == 0); +} + + +TEST_IMPL(tcp_writealot) { + struct sockaddr_in addr; + uv_tcp_t client; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + send_buffer = calloc(1, TOTAL_BYTES); + ASSERT(send_buffer != NULL); + + r = uv_tcp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(shutdown_cb_called == 1); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == WRITES); + ASSERT(close_cb_called == 1); + ASSERT(bytes_sent == TOTAL_BYTES); + ASSERT(bytes_sent_done == TOTAL_BYTES); + ASSERT(bytes_received_done == TOTAL_BYTES); + + free(send_buffer); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-thread.c b/test/test-thread.c new file mode 100644 index 0000000000..c396baa100 --- /dev/null +++ b/test/test-thread.c @@ -0,0 +1,209 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include /* memset */ + +struct getaddrinfo_req { + uv_thread_t thread_id; + unsigned int counter; + uv_loop_t* loop; + uv_getaddrinfo_t handle; +}; + + +struct fs_req { + uv_thread_t thread_id; + unsigned int counter; + uv_loop_t* loop; + uv_fs_t handle; +}; + + +struct test_thread { + uv_thread_t thread_id; + volatile int thread_called; +}; + +static void getaddrinfo_do(struct getaddrinfo_req* req); +static void getaddrinfo_cb(uv_getaddrinfo_t* handle, + int status, + struct addrinfo* res); +static void fs_do(struct fs_req* req); +static void fs_cb(uv_fs_t* handle); + +static volatile int thread_called; +static uv_key_t tls_key; + + +static void getaddrinfo_do(struct getaddrinfo_req* req) { + int r; + + r = uv_getaddrinfo(req->loop, + &req->handle, + getaddrinfo_cb, + "localhost", + NULL, + NULL); + ASSERT(r == 0); +} + + +static void getaddrinfo_cb(uv_getaddrinfo_t* handle, + int status, + struct addrinfo* res) { + struct getaddrinfo_req* req; + + ASSERT(status == 0); + + req = container_of(handle, struct getaddrinfo_req, handle); + uv_freeaddrinfo(res); + + if (--req->counter) + getaddrinfo_do(req); +} + + +static void fs_do(struct fs_req* req) { + int r; + + r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb); + ASSERT(r == 0); +} + + +static void fs_cb(uv_fs_t* handle) { + struct fs_req* req = container_of(handle, struct fs_req, handle); + + uv_fs_req_cleanup(handle); + + if (--req->counter) + fs_do(req); +} + + +static void do_work(void* arg) { + struct getaddrinfo_req getaddrinfo_reqs[16]; + struct fs_req fs_reqs[16]; + uv_loop_t* loop; + size_t i; + int r; + struct test_thread* thread = arg; + + loop = uv_loop_new(); + ASSERT(loop != NULL); + + for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { + struct getaddrinfo_req* req = getaddrinfo_reqs + i; + req->counter = 16; + req->loop = loop; + getaddrinfo_do(req); + } + + for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { + struct fs_req* req = fs_reqs + i; + req->counter = 16; + req->loop = loop; + fs_do(req); + } + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + uv_loop_delete(loop); + thread->thread_called = 1; +} + + +static void thread_entry(void* arg) { + ASSERT(arg == (void *) 42); + thread_called++; +} + + +TEST_IMPL(thread_create) { + uv_thread_t tid; + int r; + + r = uv_thread_create(&tid, thread_entry, (void *) 42); + ASSERT(r == 0); + + r = uv_thread_join(&tid); + ASSERT(r == 0); + + ASSERT(thread_called == 1); + + return 0; +} + + +/* Hilariously bad test name. Run a lot of tasks in the thread pool and verify + * that each "finished" callback is run in its originating thread. + */ +TEST_IMPL(threadpool_multiple_event_loops) { + struct test_thread threads[8]; + size_t i; + int r; + + memset(threads, 0, sizeof(threads)); + + for (i = 0; i < ARRAY_SIZE(threads); i++) { + r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]); + ASSERT(r == 0); + } + + for (i = 0; i < ARRAY_SIZE(threads); i++) { + r = uv_thread_join(&threads[i].thread_id); + ASSERT(r == 0); + ASSERT(threads[i].thread_called); + } + + return 0; +} + + +static void tls_thread(void* arg) { + ASSERT(NULL == uv_key_get(&tls_key)); + uv_key_set(&tls_key, arg); + ASSERT(arg == uv_key_get(&tls_key)); + uv_key_set(&tls_key, NULL); + ASSERT(NULL == uv_key_get(&tls_key)); +} + + +TEST_IMPL(thread_local_storage) { + char name[] = "main"; + uv_thread_t threads[2]; + ASSERT(0 == uv_key_create(&tls_key)); + ASSERT(NULL == uv_key_get(&tls_key)); + uv_key_set(&tls_key, name); + ASSERT(name == uv_key_get(&tls_key)); + ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0)); + ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1)); + ASSERT(0 == uv_thread_join(threads + 0)); + ASSERT(0 == uv_thread_join(threads + 1)); + uv_key_delete(&tls_key); + return 0; +} diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c new file mode 100644 index 0000000000..1443773cc2 --- /dev/null +++ b/test/test-threadpool-cancel.c @@ -0,0 +1,311 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#define INIT_CANCEL_INFO(ci, what) \ + do { \ + (ci)->reqs = (what); \ + (ci)->nreqs = ARRAY_SIZE(what); \ + (ci)->stride = sizeof((what)[0]); \ + } \ + while (0) + +struct cancel_info { + void* reqs; + unsigned nreqs; + unsigned stride; + uv_timer_t timer_handle; +}; + +static uv_cond_t signal_cond; +static uv_mutex_t signal_mutex; +static uv_mutex_t wait_mutex; +static unsigned num_threads; +static unsigned fs_cb_called; +static unsigned work_cb_called; +static unsigned done_cb_called; +static unsigned done2_cb_called; +static unsigned timer_cb_called; +static unsigned getaddrinfo_cb_called; + + +static void work_cb(uv_work_t* req) { + uv_mutex_lock(&signal_mutex); + uv_cond_signal(&signal_cond); + uv_mutex_unlock(&signal_mutex); + + uv_mutex_lock(&wait_mutex); + uv_mutex_unlock(&wait_mutex); + + work_cb_called++; +} + + +static void done_cb(uv_work_t* req, int status) { + done_cb_called++; + free(req); +} + + +static void saturate_threadpool(void) { + uv_work_t* req; + + ASSERT(0 == uv_cond_init(&signal_cond)); + ASSERT(0 == uv_mutex_init(&signal_mutex)); + ASSERT(0 == uv_mutex_init(&wait_mutex)); + + uv_mutex_lock(&signal_mutex); + uv_mutex_lock(&wait_mutex); + + for (num_threads = 0; /* empty */; num_threads++) { + req = malloc(sizeof(*req)); + ASSERT(req != NULL); + ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb)); + + /* Expect to get signalled within 350 ms, otherwise assume that + * the thread pool is saturated. As with any timing dependent test, + * this is obviously not ideal. + */ + if (uv_cond_timedwait(&signal_cond, &signal_mutex, 350 * 1e6)) { + ASSERT(0 == uv_cancel((uv_req_t*) req)); + break; + } + } +} + + +static void unblock_threadpool(void) { + uv_mutex_unlock(&signal_mutex); + uv_mutex_unlock(&wait_mutex); +} + + +static void cleanup_threadpool(void) { + ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */ + ASSERT(work_cb_called == num_threads); + + uv_cond_destroy(&signal_cond); + uv_mutex_destroy(&signal_mutex); + uv_mutex_destroy(&wait_mutex); +} + + +static void fs_cb(uv_fs_t* req) { + ASSERT(req->result == UV_ECANCELED); + uv_fs_req_cleanup(req); + fs_cb_called++; +} + + +static void getaddrinfo_cb(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res) { + ASSERT(status == UV_EAI_CANCELED); + ASSERT(res == NULL); + uv_freeaddrinfo(res); /* Should not crash. */ + getaddrinfo_cb_called++; +} + + +static void work2_cb(uv_work_t* req) { + ASSERT(0 && "work2_cb called"); +} + + +static void done2_cb(uv_work_t* req, int status) { + ASSERT(status == UV_ECANCELED); + done2_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + struct cancel_info* ci; + uv_req_t* req; + unsigned i; + + ci = container_of(handle, struct cancel_info, timer_handle); + + for (i = 0; i < ci->nreqs; i++) { + req = (uv_req_t*) ((char*) ci->reqs + i * ci->stride); + ASSERT(0 == uv_cancel(req)); + } + + uv_close((uv_handle_t*) &ci->timer_handle, NULL); + unblock_threadpool(); + timer_cb_called++; +} + + +static void nop_work_cb(uv_work_t* req) { +} + + +static void nop_done_cb(uv_work_t* req, int status) { + req->data = "OK"; +} + + +TEST_IMPL(threadpool_cancel_getaddrinfo) { + uv_getaddrinfo_t reqs[4]; + struct cancel_info ci; + struct addrinfo hints; + uv_loop_t* loop; + int r; + + INIT_CANCEL_INFO(&ci, reqs); + loop = uv_default_loop(); + saturate_threadpool(); + + r = uv_getaddrinfo(loop, reqs + 0, getaddrinfo_cb, "fail", NULL, NULL); + ASSERT(r == 0); + + r = uv_getaddrinfo(loop, reqs + 1, getaddrinfo_cb, NULL, "fail", NULL); + ASSERT(r == 0); + + r = uv_getaddrinfo(loop, reqs + 2, getaddrinfo_cb, "fail", "fail", NULL); + ASSERT(r == 0); + + r = uv_getaddrinfo(loop, reqs + 3, getaddrinfo_cb, "fail", NULL, &hints); + ASSERT(r == 0); + + ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); + ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == timer_cb_called); + + cleanup_threadpool(); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_cancel_work) { + struct cancel_info ci; + uv_work_t reqs[16]; + uv_loop_t* loop; + unsigned i; + + INIT_CANCEL_INFO(&ci, reqs); + loop = uv_default_loop(); + saturate_threadpool(); + + for (i = 0; i < ARRAY_SIZE(reqs); i++) + ASSERT(0 == uv_queue_work(loop, reqs + i, work2_cb, done2_cb)); + + ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); + ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == timer_cb_called); + ASSERT(ARRAY_SIZE(reqs) == done2_cb_called); + + cleanup_threadpool(); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_cancel_fs) { + struct cancel_info ci; + uv_fs_t reqs[25]; + uv_loop_t* loop; + unsigned n; + + INIT_CANCEL_INFO(&ci, reqs); + loop = uv_default_loop(); + saturate_threadpool(); + + /* Needs to match ARRAY_SIZE(fs_reqs). */ + n = 0; + ASSERT(0 == uv_fs_chmod(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT(0 == uv_fs_chown(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT(0 == uv_fs_close(loop, reqs + n++, 0, fs_cb)); + ASSERT(0 == uv_fs_fchmod(loop, reqs + n++, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_fchown(loop, reqs + n++, 0, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_fdatasync(loop, reqs + n++, 0, fs_cb)); + ASSERT(0 == uv_fs_fstat(loop, reqs + n++, 0, fs_cb)); + ASSERT(0 == uv_fs_fsync(loop, reqs + n++, 0, fs_cb)); + ASSERT(0 == uv_fs_ftruncate(loop, reqs + n++, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_futime(loop, reqs + n++, 0, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_link(loop, reqs + n++, "/", "/", fs_cb)); + ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb)); + ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, NULL, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_readdir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); + ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb)); + ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb)); + ASSERT(0 == uv_fs_stat(loop, reqs + n++, "/", fs_cb)); + ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb)); + ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb)); + ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, NULL, 0, 0, fs_cb)); + ASSERT(n == ARRAY_SIZE(reqs)); + + ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); + ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(n == fs_cb_called); + ASSERT(1 == timer_cb_called); + + cleanup_threadpool(); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_cancel_single) { + uv_loop_t* loop; + uv_work_t req; + int cancelled; + int i; + + loop = uv_default_loop(); + for (i = 0; i < 5000; i++) { + req.data = NULL; + ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb)); + + cancelled = uv_cancel((uv_req_t*) &req); + if (cancelled == 0) + break; + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + } + + if (cancelled != 0) { + fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n", + stderr); + return 1; + } + + ASSERT(req.data == NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */ + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-threadpool.c b/test/test-threadpool.c new file mode 100644 index 0000000000..e3d17d7546 --- /dev/null +++ b/test/test-threadpool.c @@ -0,0 +1,76 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static int work_cb_count; +static int after_work_cb_count; +static uv_work_t work_req; +static char data; + + +static void work_cb(uv_work_t* req) { + ASSERT(req == &work_req); + ASSERT(req->data == &data); + work_cb_count++; +} + + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT(status == 0); + ASSERT(req == &work_req); + ASSERT(req->data == &data); + after_work_cb_count++; +} + + +TEST_IMPL(threadpool_queue_work_simple) { + int r; + + work_req.data = &data; + r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb); + ASSERT(r == 0); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(work_cb_count == 1); + ASSERT(after_work_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_queue_work_einval) { + int r; + + work_req.data = &data; + r = uv_queue_work(uv_default_loop(), &work_req, NULL, after_work_cb); + ASSERT(r == UV_EINVAL); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(work_cb_count == 0); + ASSERT(after_work_cb_count == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-timer-again.c b/test/test-timer-again.c new file mode 100644 index 0000000000..1638da2dfc --- /dev/null +++ b/test/test-timer-again.c @@ -0,0 +1,140 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +static int close_cb_called = 0; +static int repeat_1_cb_called = 0; +static int repeat_2_cb_called = 0; + +static int repeat_2_cb_allowed = 0; + +static uv_timer_t dummy, repeat_1, repeat_2; + +static uint64_t start_time; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + + close_cb_called++; +} + + +static void repeat_1_cb(uv_timer_t* handle, int status) { + int r; + + ASSERT(handle == &repeat_1); + ASSERT(status == 0); + + ASSERT(uv_timer_get_repeat((uv_timer_t*)handle) == 50); + + LOGF("repeat_1_cb called after %ld ms\n", + (long int)(uv_now(uv_default_loop()) - start_time)); + + repeat_1_cb_called++; + + r = uv_timer_again(&repeat_2); + ASSERT(r == 0); + + if (repeat_1_cb_called == 10) { + uv_close((uv_handle_t*)handle, close_cb); + /* We're not calling uv_timer_again on repeat_2 any more, so after this */ + /* timer_2_cb is expected. */ + repeat_2_cb_allowed = 1; + return; + } +} + + +static void repeat_2_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &repeat_2); + ASSERT(status == 0); + ASSERT(repeat_2_cb_allowed); + + LOGF("repeat_2_cb called after %ld ms\n", + (long int)(uv_now(uv_default_loop()) - start_time)); + + repeat_2_cb_called++; + + if (uv_timer_get_repeat(&repeat_2) == 0) { + ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + uv_close((uv_handle_t*)handle, close_cb); + return; + } + + LOGF("uv_timer_get_repeat %ld ms\n", + (long int)uv_timer_get_repeat(&repeat_2)); + ASSERT(uv_timer_get_repeat(&repeat_2) == 100); + + /* This shouldn't take effect immediately. */ + uv_timer_set_repeat(&repeat_2, 0); +} + + +TEST_IMPL(timer_again) { + int r; + + start_time = uv_now(uv_default_loop()); + ASSERT(0 < start_time); + + /* Verify that it is not possible to uv_timer_again a never-started timer. */ + r = uv_timer_init(uv_default_loop(), &dummy); + ASSERT(r == 0); + r = uv_timer_again(&dummy); + ASSERT(r == UV_EINVAL); + uv_unref((uv_handle_t*)&dummy); + + /* Start timer repeat_1. */ + r = uv_timer_init(uv_default_loop(), &repeat_1); + ASSERT(r == 0); + r = uv_timer_start(&repeat_1, repeat_1_cb, 50, 0); + ASSERT(r == 0); + ASSERT(uv_timer_get_repeat(&repeat_1) == 0); + + /* Actually make repeat_1 repeating. */ + uv_timer_set_repeat(&repeat_1, 50); + ASSERT(uv_timer_get_repeat(&repeat_1) == 50); + + /* + * Start another repeating timer. It'll be again()ed by the repeat_1 so + * it should not time out until repeat_1 stops. + */ + r = uv_timer_init(uv_default_loop(), &repeat_2); + ASSERT(r == 0); + r = uv_timer_start(&repeat_2, repeat_2_cb, 100, 100); + ASSERT(r == 0); + ASSERT(uv_timer_get_repeat(&repeat_2) == 100); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(repeat_1_cb_called == 10); + ASSERT(repeat_2_cb_called == 2); + ASSERT(close_cb_called == 2); + + LOGF("Test took %ld ms (expected ~700 ms)\n", + (long int)(uv_now(uv_default_loop()) - start_time)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-timer-from-check.c b/test/test-timer-from-check.c new file mode 100644 index 0000000000..2aa3fe4119 --- /dev/null +++ b/test/test-timer-from-check.c @@ -0,0 +1,80 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_prepare_t prepare_handle; +static uv_check_t check_handle; +static uv_timer_t timer_handle; + +static int prepare_cb_called; +static int check_cb_called; +static int timer_cb_called; + + +static void prepare_cb(uv_prepare_t* handle, int status) { + ASSERT(0 == uv_prepare_stop(&prepare_handle)); + ASSERT(0 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(0 == timer_cb_called); + prepare_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(0 == uv_timer_stop(&timer_handle)); + ASSERT(1 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(0 == timer_cb_called); + timer_cb_called++; +} + + +static void check_cb(uv_check_t* handle, int status) { + ASSERT(0 == uv_check_stop(&check_handle)); + ASSERT(0 == uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */ + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT(0 == uv_prepare_start(&prepare_handle, prepare_cb)); + ASSERT(0 == prepare_cb_called); + ASSERT(0 == check_cb_called); + ASSERT(0 == timer_cb_called); + check_cb_called++; +} + + +TEST_IMPL(timer_from_check) { + ASSERT(0 == uv_prepare_init(uv_default_loop(), &prepare_handle)); + ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle)); + ASSERT(0 == uv_check_start(&check_handle, check_cb)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(1 == timer_cb_called); + uv_close((uv_handle_t*) &prepare_handle, NULL); + uv_close((uv_handle_t*) &check_handle, NULL); + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-timer.c b/test/test-timer.c new file mode 100644 index 0000000000..bbe69f68be --- /dev/null +++ b/test/test-timer.c @@ -0,0 +1,294 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +static int once_cb_called = 0; +static int once_close_cb_called = 0; +static int repeat_cb_called = 0; +static int repeat_close_cb_called = 0; +static int order_cb_called = 0; +static uint64_t start_time; +static uv_timer_t tiny_timer; +static uv_timer_t huge_timer1; +static uv_timer_t huge_timer2; + + +static void once_close_cb(uv_handle_t* handle) { + printf("ONCE_CLOSE_CB\n"); + + ASSERT(handle != NULL); + ASSERT(0 == uv_is_active(handle)); + + once_close_cb_called++; +} + + +static void once_cb(uv_timer_t* handle, int status) { + printf("ONCE_CB %d\n", once_cb_called); + + ASSERT(handle != NULL); + ASSERT(status == 0); + ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + + once_cb_called++; + + uv_close((uv_handle_t*)handle, once_close_cb); + + /* Just call this randomly for the code coverage. */ + uv_update_time(uv_default_loop()); +} + + +static void repeat_close_cb(uv_handle_t* handle) { + printf("REPEAT_CLOSE_CB\n"); + + ASSERT(handle != NULL); + + repeat_close_cb_called++; +} + + +static void repeat_cb(uv_timer_t* handle, int status) { + printf("REPEAT_CB\n"); + + ASSERT(handle != NULL); + ASSERT(status == 0); + ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + + repeat_cb_called++; + + if (repeat_cb_called == 5) { + uv_close((uv_handle_t*)handle, repeat_close_cb); + } +} + + +static void never_cb(uv_timer_t* handle, int status) { + FATAL("never_cb should never be called"); +} + + +TEST_IMPL(timer) { + uv_timer_t once_timers[10]; + uv_timer_t *once; + uv_timer_t repeat, never; + unsigned int i; + int r; + + start_time = uv_now(uv_default_loop()); + ASSERT(0 < start_time); + + /* Let 10 timers time out in 500 ms total. */ + for (i = 0; i < ARRAY_SIZE(once_timers); i++) { + once = once_timers + i; + r = uv_timer_init(uv_default_loop(), once); + ASSERT(r == 0); + r = uv_timer_start(once, once_cb, i * 50, 0); + ASSERT(r == 0); + } + + /* The 11th timer is a repeating timer that runs 4 times */ + r = uv_timer_init(uv_default_loop(), &repeat); + ASSERT(r == 0); + r = uv_timer_start(&repeat, repeat_cb, 100, 100); + ASSERT(r == 0); + + /* The 12th timer should not do anything. */ + r = uv_timer_init(uv_default_loop(), &never); + ASSERT(r == 0); + r = uv_timer_start(&never, never_cb, 100, 100); + ASSERT(r == 0); + r = uv_timer_stop(&never); + ASSERT(r == 0); + uv_unref((uv_handle_t*)&never); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(once_cb_called == 10); + ASSERT(once_close_cb_called == 10); + printf("repeat_cb_called %d\n", repeat_cb_called); + ASSERT(repeat_cb_called == 5); + ASSERT(repeat_close_cb_called == 1); + + ASSERT(500 <= uv_now(uv_default_loop()) - start_time); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(timer_start_twice) { + uv_timer_t once; + int r; + + r = uv_timer_init(uv_default_loop(), &once); + ASSERT(r == 0); + r = uv_timer_start(&once, never_cb, 86400 * 1000, 0); + ASSERT(r == 0); + r = uv_timer_start(&once, once_cb, 10, 0); + ASSERT(r == 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(once_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(timer_init) { + uv_timer_t handle; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); + ASSERT(0 == uv_timer_get_repeat(&handle)); + ASSERT(0 == uv_is_active((uv_handle_t*) &handle)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void order_cb_a(uv_timer_t *handle, int status) { + ASSERT(order_cb_called++ == *(int*)handle->data); +} + + +static void order_cb_b(uv_timer_t *handle, int status) { + ASSERT(order_cb_called++ == *(int*)handle->data); +} + + +TEST_IMPL(timer_order) { + int first; + int second; + uv_timer_t handle_a; + uv_timer_t handle_b; + + first = 0; + second = 1; + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_a)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_b)); + + /* Test for starting handle_a then handle_b */ + handle_a.data = &first; + ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0)); + handle_b.data = &second; + ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(order_cb_called == 2); + + ASSERT(0 == uv_timer_stop(&handle_a)); + ASSERT(0 == uv_timer_stop(&handle_b)); + + /* Test for starting handle_b then handle_a */ + order_cb_called = 0; + handle_b.data = &first; + ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0)); + + handle_a.data = &second; + ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(order_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void tiny_timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &tiny_timer); + uv_close((uv_handle_t*) &tiny_timer, NULL); + uv_close((uv_handle_t*) &huge_timer1, NULL); + uv_close((uv_handle_t*) &huge_timer2, NULL); +} + + +TEST_IMPL(timer_huge_timeout) { + ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer2)); + ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0)); + ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0)); + ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void huge_repeat_cb(uv_timer_t* handle, int status) { + static int ncalls; + + if (ncalls == 0) + ASSERT(handle == &huge_timer1); + else + ASSERT(handle == &tiny_timer); + + if (++ncalls == 10) { + uv_close((uv_handle_t*) &tiny_timer, NULL); + uv_close((uv_handle_t*) &huge_timer1, NULL); + } +} + + +TEST_IMPL(timer_huge_repeat) { + ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2)); + ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static unsigned int timer_run_once_timer_cb_called; + + +static void timer_run_once_timer_cb(uv_timer_t* handle, int status) { + timer_run_once_timer_cb_called++; +} + + +TEST_IMPL(timer_run_once) { + uv_timer_t timer_handle; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT(1 == timer_run_once_timer_cb_called); + + ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT(2 == timer_run_once_timer_cb_called); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tty.c b/test/test-tty.c new file mode 100644 index 0000000000..fb69910732 --- /dev/null +++ b/test/test-tty.c @@ -0,0 +1,123 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 +# include +# include +#else /* Unix */ +# include +# include +#endif + +#include +#include + + +TEST_IMPL(tty) { + int r, width, height; + int ttyin_fd, ttyout_fd; + uv_tty_t tty_in, tty_out; + uv_loop_t* loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ +#ifdef _WIN32 + HANDLE handle; + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + +#else /* unix */ + ttyin_fd = open("/dev/tty", O_RDONLY, 0); + if (ttyin_fd < 0) { + LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno)); + return TEST_SKIP; + } + + ttyout_fd = open("/dev/tty", O_WRONLY, 0); + if (ttyout_fd < 0) { + LOGF("Cannot open /dev/tty as write-only: %s\n", strerror(errno)); + return TEST_SKIP; + } +#endif + + ASSERT(ttyin_fd >= 0); + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_UNKNOWN_HANDLE == uv_guess_handle(-1)); + + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + r = uv_tty_get_winsize(&tty_out, &width, &height); + ASSERT(r == 0); + + printf("width=%d height=%d\n", width, height); + + /* + * Is it a safe assumption that most people have terminals larger than + * 10x10? + */ + ASSERT(width > 10); + ASSERT(height > 10); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, 1); + ASSERT(r == 0); + + /* Turn off raw mode. */ + r = uv_tty_set_mode(&tty_in, 0); + ASSERT(r == 0); + + /* TODO check the actual mode! */ + + uv_close((uv_handle_t*) &tty_in, NULL); + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-dgram-too-big.c b/test/test-udp-dgram-too-big.c new file mode 100644 index 0000000000..bd44c42528 --- /dev/null +++ b/test/test-udp-dgram-too-big.c @@ -0,0 +1,91 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &handle_) + +#define CHECK_REQ(req) \ + ASSERT((req) == &req_); + +static uv_udp_t handle_; +static uv_udp_send_t req_; + +static int send_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void send_cb(uv_udp_send_t* req, int status) { + CHECK_REQ(req); + CHECK_HANDLE(req->handle); + + ASSERT(status == UV_EMSGSIZE); + + uv_close((uv_handle_t*)req->handle, close_cb); + send_cb_called++; +} + + +TEST_IMPL(udp_dgram_too_big) { + char dgram[65536]; /* 64K MTU is unlikely, even on localhost */ + struct sockaddr_in addr; + uv_buf_t buf; + int r; + + memset(dgram, 42, sizeof dgram); /* silence valgrind */ + + r = uv_udp_init(uv_default_loop(), &handle_); + ASSERT(r == 0); + + buf = uv_buf_init(dgram, sizeof dgram); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_send(&req_, + &handle_, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(send_cb_called == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(send_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c new file mode 100644 index 0000000000..32cabf097c --- /dev/null +++ b/test/test-udp-ipv6.c @@ -0,0 +1,166 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server \ + || (uv_udp_t*)(handle) == &client \ + || (uv_timer_t*)(handle) == &timeout) + +#define CHECK_REQ(req) \ + ASSERT((req) == &req_); + +static uv_udp_t client; +static uv_udp_t server; +static uv_udp_send_t req_; +static uv_timer_t timeout; + +static int send_cb_called; +static int recv_cb_called; +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void send_cb(uv_udp_send_t* req, int status) { + CHECK_REQ(req); + CHECK_HANDLE(req->handle); + ASSERT(status == 0); + send_cb_called++; +} + + +static void ipv6_recv_fail(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + ASSERT(0 && "this function should not have been called"); +} + + +static void ipv6_recv_ok(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + ASSERT(nread >= 0); + + if (nread) + recv_cb_called++; +} + + +static void timeout_cb(uv_timer_t* timer, int status) { + uv_close((uv_handle_t*)&server, close_cb); + uv_close((uv_handle_t*)&client, close_cb); + uv_close((uv_handle_t*)&timeout, close_cb); +} + + +static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { + struct sockaddr_in6 addr6; + struct sockaddr_in addr; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip6_addr("::0", TEST_PORT, &addr6)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, recv_cb); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + buf = uv_buf_init("PING", 4); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_send(&req_, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &timeout); + ASSERT(r == 0); + + r = uv_timer_start(&timeout, timeout_cb, 500, 0); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(send_cb_called == 0); + ASSERT(recv_cb_called == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); +} + + +TEST_IMPL(udp_dual_stack) { + do_test(ipv6_recv_ok, 0); + + ASSERT(recv_cb_called == 1); + ASSERT(send_cb_called == 1); + + return 0; +} + + +TEST_IMPL(udp_ipv6_only) { + do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY); + + ASSERT(recv_cb_called == 0); + ASSERT(send_cb_called == 1); + + return 0; +} diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c new file mode 100644 index 0000000000..686edf3d22 --- /dev/null +++ b/test/test-udp-multicast-join.c @@ -0,0 +1,148 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int cl_recv_cb_called; + +static int sv_send_cb_called; + +static int close_cb_called; + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + sv_send_cb_called++; + + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +static void cl_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + cl_recv_cb_called++; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards cl_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(!memcmp("PING", buf->base, nread)); + + /* we are done with the client handle, we can close it */ + uv_close((uv_handle_t*) &client, close_cb); +} + + +TEST_IMPL(udp_multicast_join) { + int r; + uv_udp_send_t req; + uv_buf_t buf; + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + /* bind to the desired port */ + r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + /* join the multicast channel */ + r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP); + ASSERT(r == 0); + + r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb); + ASSERT(r == 0); + + buf = uv_buf_init("PING", 4); + + /* server sends "PING" */ + r = uv_udp_send(&req, + &server, + &buf, + 1, + (const struct sockaddr*) &addr, + sv_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(cl_recv_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + + /* run the loop till all events are processed */ + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(cl_recv_cb_called == 1); + ASSERT(sv_send_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-multicast-ttl.c b/test/test-udp-multicast-ttl.c new file mode 100644 index 0000000000..bed0ea1342 --- /dev/null +++ b/test/test-udp-multicast-ttl.c @@ -0,0 +1,94 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int sv_send_cb_called; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + sv_send_cb_called++; + + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +TEST_IMPL(udp_multicast_ttl) { + int r; + uv_udp_send_t req; + uv_buf_t buf; + struct sockaddr_in addr; + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr)); + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_set_multicast_ttl(&server, 32); + ASSERT(r == 0); + + /* server sends "PING" */ + buf = uv_buf_init("PING", 4); + ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); + r = uv_udp_send(&req, + &server, + &buf, + 1, + (const struct sockaddr*) &addr, + sv_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + + /* run the loop till all events are processed */ + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(sv_send_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-open.c b/test/test-udp-open.c new file mode 100644 index 0000000000..9a97303f12 --- /dev/null +++ b/test/test-udp-open.c @@ -0,0 +1,164 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include +#include + +#ifndef _WIN32 +# include +#endif + +static int send_cb_called = 0; +static int close_cb_called = 0; + +static uv_udp_send_t send_req; + + +static void startup(void) { +#ifdef _WIN32 + struct WSAData wsa_data; + int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); +#endif +} + + +static uv_os_sock_t create_udp_socket(void) { + uv_os_sock_t sock; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + +#ifndef _WIN32 + { + /* Allow reuse of the port. */ + int yes = 1; + int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + ASSERT(r == 0); + } +#endif + + return sock; +} + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle != NULL); + close_cb_called++; +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + int r; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards sv_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + ASSERT(flags == 0); + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(memcmp("PING", buf->base, nread) == 0); + + r = uv_udp_recv_stop(handle); + ASSERT(r == 0); + + uv_close((uv_handle_t*) handle, close_cb); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + + send_cb_called++; +} + + +TEST_IMPL(udp_open) { + struct sockaddr_in addr; + uv_buf_t buf = uv_buf_init("PING", 4); + uv_udp_t client; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_udp_socket(); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_udp_open(&client, sock); + ASSERT(r == 0); + + r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&client, alloc_cb, recv_cb); + ASSERT(r == 0); + + r = uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(send_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-options.c b/test/test-udp-options.c new file mode 100644 index 0000000000..5cc369878a --- /dev/null +++ b/test/test-udp-options.c @@ -0,0 +1,88 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + + +TEST_IMPL(udp_options) { + static int invalid_ttls[] = { -1, 0, 256 }; + struct sockaddr_in addr; + uv_loop_t* loop; + uv_udp_t h; + int i, r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + loop = uv_default_loop(); + + r = uv_udp_init(loop, &h); + ASSERT(r == 0); + + uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */ + + r = uv_udp_bind(&h, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_set_broadcast(&h, 1); + r |= uv_udp_set_broadcast(&h, 1); + r |= uv_udp_set_broadcast(&h, 0); + r |= uv_udp_set_broadcast(&h, 0); + ASSERT(r == 0); + + /* values 1-255 should work */ + for (i = 1; i <= 255; i++) { + r = uv_udp_set_ttl(&h, i); + ASSERT(r == 0); + } + + for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) { + r = uv_udp_set_ttl(&h, invalid_ttls[i]); + ASSERT(r == UV_EINVAL); + } + + r = uv_udp_set_multicast_loop(&h, 1); + r |= uv_udp_set_multicast_loop(&h, 1); + r |= uv_udp_set_multicast_loop(&h, 0); + r |= uv_udp_set_multicast_loop(&h, 0); + ASSERT(r == 0); + + /* values 0-255 should work */ + for (i = 0; i <= 255; i++) { + r = uv_udp_set_multicast_ttl(&h, i); + ASSERT(r == 0); + } + + /* anything >255 should fail */ + r = uv_udp_set_multicast_ttl(&h, 256); + ASSERT(r == UV_EINVAL); + /* don't test ttl=-1, it's a valid value on some platforms */ + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-udp-send-and-recv.c b/test/test-udp-send-and-recv.c new file mode 100644 index 0000000000..3020ded7bf --- /dev/null +++ b/test/test-udp-send-and-recv.c @@ -0,0 +1,211 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int cl_send_cb_called; +static int cl_recv_cb_called; + +static int sv_send_cb_called; +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(1 == uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards cl_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(!memcmp("PONG", buf->base, nread)); + + cl_recv_cb_called++; + + uv_close((uv_handle_t*) handle, close_cb); +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + int r; + + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + r = uv_udp_recv_start(req->handle, alloc_cb, cl_recv_cb); + ASSERT(r == 0); + + cl_send_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + uv_close((uv_handle_t*) req->handle, close_cb); + free(req); + + sv_send_cb_called++; +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + uv_udp_send_t* req; + uv_buf_t sndbuf; + int r; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards sv_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(!memcmp("PING", rcvbuf->base, nread)); + + /* FIXME? `uv_udp_recv_stop` does what it says: recv_cb is not called + * anymore. That's problematic because the read buffer won't be returned + * either... Not sure I like that but it's consistent with `uv_read_stop`. + */ + r = uv_udp_recv_stop(handle); + ASSERT(r == 0); + + req = malloc(sizeof *req); + ASSERT(req != NULL); + + sndbuf = uv_buf_init("PONG", 4); + r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb); + ASSERT(r == 0); + + sv_recv_cb_called++; +} + + +TEST_IMPL(udp_send_and_recv) { + struct sockaddr_in addr; + uv_udp_send_t req; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + /* client sends "PING", expects "PONG" */ + buf = uv_buf_init("PING", 4); + + r = uv_udp_send(&req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + cl_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(cl_send_cb_called == 0); + ASSERT(cl_recv_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + ASSERT(sv_recv_cb_called == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(cl_send_cb_called == 1); + ASSERT(cl_recv_cb_called == 1); + ASSERT(sv_send_cb_called == 1); + ASSERT(sv_recv_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-walk-handles.c b/test/test-walk-handles.c new file mode 100644 index 0000000000..f2ae41564f --- /dev/null +++ b/test/test-walk-handles.c @@ -0,0 +1,78 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +static char magic_cookie[] = "magic cookie"; +static int seen_timer_handle; +static uv_timer_t timer; + + +static void walk_cb(uv_handle_t* handle, void* arg) { + ASSERT(arg == (void*)magic_cookie); + + if (handle == (uv_handle_t*)&timer) { + seen_timer_handle++; + } else { + ASSERT(0 && "unexpected handle"); + } +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer); + ASSERT(status == 0); + + uv_walk(handle->loop, walk_cb, magic_cookie); + uv_close((uv_handle_t*)handle, NULL); +} + + +TEST_IMPL(walk_handles) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 1, 0); + ASSERT(r == 0); + + /* Start event loop, expect to see the timer handle in walk_cb. */ + ASSERT(seen_timer_handle == 0); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(seen_timer_handle == 1); + + /* Loop is finished, walk_cb should not see our timer handle. */ + seen_timer_handle = 0; + uv_walk(loop, walk_cb, magic_cookie); + ASSERT(seen_timer_handle == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c new file mode 100644 index 0000000000..c701dd2f91 --- /dev/null +++ b/test/test-watcher-cross-stop.c @@ -0,0 +1,101 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +/* NOTE: Number should be big enough to trigger this problem */ +static uv_udp_t sockets[2500]; +static uv_udp_send_t reqs[ARRAY_SIZE(sockets)]; +static char slab[1]; +static unsigned int recv_cb_called; +static unsigned int send_cb_called; +static unsigned int close_cb_called; + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + recv_cb_called++; +} + + +static void send_cb(uv_udp_send_t* req, int status) { + send_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +TEST_IMPL(watcher_cross_stop) { + uv_loop_t* loop = uv_default_loop(); + unsigned int i; + struct sockaddr_in addr; + uv_buf_t buf; + char big_string[1024]; + + TEST_FILE_LIMIT(ARRAY_SIZE(sockets) + 32); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + memset(big_string, 'A', sizeof(big_string)); + buf = uv_buf_init(big_string, sizeof(big_string)); + + for (i = 0; i < ARRAY_SIZE(sockets); i++) { + ASSERT(0 == uv_udp_init(loop, &sockets[i])); + ASSERT(0 == uv_udp_bind(&sockets[i], (const struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb)); + ASSERT(0 == uv_udp_send(&reqs[i], + &sockets[i], + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb)); + } + + while (recv_cb_called == 0) + uv_run(loop, UV_RUN_ONCE); + + for (i = 0; i < ARRAY_SIZE(sockets); i++) + uv_close((uv_handle_t*) &sockets[i], close_cb); + + ASSERT(0 < recv_cb_called && recv_cb_called <= ARRAY_SIZE(sockets)); + ASSERT(ARRAY_SIZE(sockets) == send_cb_called); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(ARRAY_SIZE(sockets) == close_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/uv.gyp b/uv.gyp new file mode 100644 index 0000000000..50e19357de --- /dev/null +++ b/uv.gyp @@ -0,0 +1,532 @@ +{ + 'variables': { + 'uv_use_dtrace%': 'false', + # uv_parent_path is the relative path to libuv in the parent project + # this is only relevant when dtrace is enabled and libuv is a child project + # as it's necessary to correctly locate the object files for post + # processing. + # XXX gyp is quite sensitive about paths with double / they don't normalize + 'uv_parent_path': '/', + }, + + 'target_defaults': { + 'conditions': [ + ['OS != "win"', { + 'defines': [ + '_LARGEFILE_SOURCE', + '_FILE_OFFSET_BITS=64', + ], + 'conditions': [ + ['OS=="solaris"', { + 'cflags': [ '-pthreads' ], + }], + ['OS not in "solaris android"', { + 'cflags': [ '-pthread' ], + }], + ], + }], + ], + }, + + 'targets': [ + { + 'target_name': 'libuv', + 'type': '<(library)', + 'include_dirs': [ + 'include', + 'src/', + ], + 'direct_dependent_settings': { + 'include_dirs': [ 'include' ], + 'conditions': [ + ['OS != "win"', { + 'defines': [ + '_LARGEFILE_SOURCE', + '_FILE_OFFSET_BITS=64', + ], + }], + ['OS == "mac"', { + 'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], + }], + ['OS == "linux"', { + 'defines': [ '_POSIX_C_SOURCE=200112' ], + }], + ], + }, + 'defines': [ + 'HAVE_CONFIG_H' + ], + 'sources': [ + 'common.gypi', + 'include/uv.h', + 'include/tree.h', + 'include/uv-errno.h', + 'src/fs-poll.c', + 'src/inet.c', + 'src/queue.h', + 'src/uv-common.c', + 'src/uv-common.h', + 'src/version.c' + ], + 'conditions': [ + [ 'OS=="win"', { + 'defines': [ + '_WIN32_WINNT=0x0600', + '_GNU_SOURCE', + ], + 'sources': [ + 'include/uv-win.h', + 'src/win/async.c', + 'src/win/atomicops-inl.h', + 'src/win/core.c', + 'src/win/dl.c', + 'src/win/error.c', + 'src/win/fs.c', + 'src/win/fs-event.c', + 'src/win/getaddrinfo.c', + 'src/win/handle.c', + 'src/win/handle-inl.h', + 'src/win/internal.h', + 'src/win/loop-watcher.c', + 'src/win/pipe.c', + 'src/win/thread.c', + 'src/win/poll.c', + 'src/win/process.c', + 'src/win/process-stdio.c', + 'src/win/req.c', + 'src/win/req-inl.h', + 'src/win/signal.c', + 'src/win/stream.c', + 'src/win/stream-inl.h', + 'src/win/tcp.c', + 'src/win/tty.c', + 'src/win/threadpool.c', + 'src/win/timer.c', + 'src/win/udp.c', + 'src/win/util.c', + 'src/win/winapi.c', + 'src/win/winapi.h', + 'src/win/winsock.c', + 'src/win/winsock.h', + ], + 'link_settings': { + 'libraries': [ + '-ladvapi32.lib', + '-liphlpapi.lib', + '-lpsapi.lib', + '-lshell32.lib', + '-lws2_32.lib' + ], + }, + }, { # Not Windows i.e. POSIX + 'cflags': [ + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ], + 'sources': [ + 'include/uv-unix.h', + 'include/uv-linux.h', + 'include/uv-sunos.h', + 'include/uv-darwin.h', + 'include/uv-bsd.h', + 'src/unix/async.c', + 'src/unix/atomic-ops.h', + 'src/unix/core.c', + 'src/unix/dl.c', + 'src/unix/fs.c', + 'src/unix/getaddrinfo.c', + 'src/unix/internal.h', + 'src/unix/loop.c', + 'src/unix/loop-watcher.c', + 'src/unix/pipe.c', + 'src/unix/poll.c', + 'src/unix/process.c', + 'src/unix/signal.c', + 'src/unix/spinlock.h', + 'src/unix/stream.c', + 'src/unix/tcp.c', + 'src/unix/thread.c', + 'src/unix/threadpool.c', + 'src/unix/timer.c', + 'src/unix/tty.c', + 'src/unix/udp.c', + ], + 'link_settings': { + 'libraries': [ '-lm' ], + 'conditions': [ + ['OS=="solaris"', { + 'ldflags': [ '-pthreads' ], + }], + ['OS != "solaris" and OS != "android"', { + 'ldflags': [ '-pthread' ], + }], + ], + }, + 'conditions': [ + ['library=="shared_library"', { + 'cflags': [ '-fPIC' ], + }], + ['library=="shared_library" and OS!="mac"', { + 'link_settings': { + # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR + # in src/version.c + 'libraries': [ '-Wl,-soname,libuv.so.0.11' ], + }, + }], + ], + }], + [ 'OS in "linux mac android"', { + 'sources': [ 'src/unix/proctitle.c' ], + }], + [ 'OS=="mac"', { + 'sources': [ + 'src/unix/darwin.c', + 'src/unix/fsevents.c', + 'src/unix/darwin-proctitle.c', + ], + 'defines': [ + '_DARWIN_USE_64_BIT_INODE=1', + ] + }], + [ 'OS!="mac"', { + # Enable on all platforms except OS X. The antique gcc/clang that + # ships with Xcode emits waaaay too many false positives. + 'cflags': [ '-Wstrict-aliasing' ], + }], + [ 'OS=="linux"', { + 'sources': [ + 'src/unix/linux-core.c', + 'src/unix/linux-inotify.c', + 'src/unix/linux-syscalls.c', + 'src/unix/linux-syscalls.h', + ], + 'link_settings': { + 'libraries': [ '-ldl', '-lrt' ], + }, + }], + [ 'OS=="android"', { + 'sources': [ + 'src/unix/linux-core.c', + 'src/unix/linux-inotify.c', + 'src/unix/linux-syscalls.c', + 'src/unix/linux-syscalls.h', + 'src/unix/pthread-fixes.c', + ], + 'link_settings': { + 'libraries': [ '-ldl' ], + }, + }], + [ 'OS=="solaris"', { + 'sources': [ 'src/unix/sunos.c' ], + 'defines': [ + '__EXTENSIONS__', + '_XOPEN_SOURCE=500', + ], + 'link_settings': { + 'libraries': [ + '-lkstat', + '-lnsl', + '-lsendfile', + '-lsocket', + ], + }, + }], + [ 'OS=="aix"', { + 'include_dirs': [ 'src/ares/config_aix' ], + 'sources': [ 'src/unix/aix.c' ], + 'defines': [ + '_ALL_SOURCE', + '_XOPEN_SOURCE=500', + ], + 'link_settings': { + 'libraries': [ + '-lperfstat', + ], + }, + }], + [ 'OS=="freebsd" or OS=="dragonflybsd"', { + 'sources': [ 'src/unix/freebsd.c' ], + }], + [ 'OS=="openbsd"', { + 'sources': [ 'src/unix/openbsd.c' ], + }], + [ 'OS=="netbsd"', { + 'sources': [ 'src/unix/netbsd.c' ], + }], + [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', { + 'link_settings': { + 'libraries': [ '-lkvm' ], + }, + }], + [ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', { + 'sources': [ 'src/unix/kqueue.c' ], + }], + ['library=="shared_library"', { + 'defines': [ 'BUILDING_UV_SHARED=1' ] + }], + # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. + ['uv_use_dtrace=="true"', { + 'defines': [ 'HAVE_DTRACE=1' ], + 'dependencies': [ 'uv_dtrace_header' ], + 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], + 'conditions': [ + [ 'OS not in "mac linux"', { + 'sources': [ 'src/unix/dtrace.c' ], + }], + [ 'OS=="linux"', { + 'sources': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ] + }], + ], + }], + ] + }, + + { + 'target_name': 'run-tests', + 'type': 'executable', + 'dependencies': [ 'libuv' ], + 'sources': [ + 'test/blackhole-server.c', + 'test/echo-server.c', + 'test/run-tests.c', + 'test/runner.c', + 'test/runner.h', + 'test/test-get-loadavg.c', + 'test/task.h', + 'test/test-active.c', + 'test/test-async.c', + 'test/test-async-null-cb.c', + 'test/test-callback-stack.c', + 'test/test-callback-order.c', + 'test/test-close-fd.c', + 'test/test-close-order.c', + 'test/test-connection-fail.c', + 'test/test-cwd-and-chdir.c', + 'test/test-delayed-accept.c', + 'test/test-error.c', + 'test/test-embed.c', + 'test/test-emfile.c', + 'test/test-fail-always.c', + 'test/test-fs.c', + 'test/test-fs-event.c', + 'test/test-get-currentexe.c', + 'test/test-get-memory.c', + 'test/test-getaddrinfo.c', + 'test/test-getsockname.c', + 'test/test-hrtime.c', + 'test/test-idle.c', + 'test/test-ipc.c', + 'test/test-ipc-send-recv.c', + 'test/test-list.h', + 'test/test-loop-handles.c', + 'test/test-loop-alive.c', + 'test/test-loop-stop.c', + 'test/test-loop-time.c', + 'test/test-walk-handles.c', + 'test/test-watcher-cross-stop.c', + 'test/test-multiple-listen.c', + 'test/test-osx-select.c', + 'test/test-pass-always.c', + 'test/test-ping-pong.c', + 'test/test-pipe-bind-error.c', + 'test/test-pipe-connect-error.c', + 'test/test-pipe-server-close.c', + 'test/test-platform-output.c', + 'test/test-poll.c', + 'test/test-poll-close.c', + 'test/test-process-title.c', + 'test/test-ref.c', + 'test/test-run-nowait.c', + 'test/test-run-once.c', + 'test/test-semaphore.c', + 'test/test-shutdown-close.c', + 'test/test-shutdown-eof.c', + 'test/test-signal.c', + 'test/test-signal-multiple-loops.c', + 'test/test-spawn.c', + 'test/test-fs-poll.c', + 'test/test-stdio-over-pipes.c', + 'test/test-tcp-bind-error.c', + 'test/test-tcp-bind6-error.c', + 'test/test-tcp-close.c', + 'test/test-tcp-close-accept.c', + 'test/test-tcp-close-while-connecting.c', + 'test/test-tcp-connect-error-after-write.c', + 'test/test-tcp-shutdown-after-write.c', + 'test/test-tcp-flags.c', + 'test/test-tcp-connect-error.c', + 'test/test-tcp-connect-timeout.c', + 'test/test-tcp-connect6-error.c', + 'test/test-tcp-open.c', + 'test/test-tcp-write-to-half-open-connection.c', + 'test/test-tcp-writealot.c', + 'test/test-tcp-try-write.c', + 'test/test-tcp-unexpected-read.c', + 'test/test-tcp-read-stop.c', + 'test/test-threadpool.c', + 'test/test-threadpool-cancel.c', + 'test/test-mutexes.c', + 'test/test-thread.c', + 'test/test-barrier.c', + 'test/test-condvar.c', + 'test/test-timer-again.c', + 'test/test-timer-from-check.c', + 'test/test-timer.c', + 'test/test-tty.c', + 'test/test-udp-dgram-too-big.c', + 'test/test-udp-ipv6.c', + 'test/test-udp-open.c', + 'test/test-udp-options.c', + 'test/test-udp-send-and-recv.c', + 'test/test-udp-multicast-join.c', + 'test/test-dlerror.c', + 'test/test-udp-multicast-ttl.c', + 'test/test-ip4-addr.c', + 'test/test-ip6-addr.c', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'test/runner-win.c', + 'test/runner-win.h' + ], + 'libraries': [ 'ws2_32.lib' ] + }, { # POSIX + 'defines': [ '_GNU_SOURCE' ], + 'sources': [ + 'test/runner-unix.c', + 'test/runner-unix.h', + ], + }], + [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE + 'defines': [ + '__EXTENSIONS__', + '_XOPEN_SOURCE=500', + ], + }], + [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE + 'defines': [ + '_ALL_SOURCE', + '_XOPEN_SOURCE=500', + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + + { + 'target_name': 'run-benchmarks', + 'type': 'executable', + 'dependencies': [ 'libuv' ], + 'sources': [ + 'test/benchmark-async.c', + 'test/benchmark-async-pummel.c', + 'test/benchmark-fs-stat.c', + 'test/benchmark-getaddrinfo.c', + 'test/benchmark-list.h', + 'test/benchmark-loop-count.c', + 'test/benchmark-million-async.c', + 'test/benchmark-million-timers.c', + 'test/benchmark-multi-accept.c', + 'test/benchmark-ping-pongs.c', + 'test/benchmark-pound.c', + 'test/benchmark-pump.c', + 'test/benchmark-sizes.c', + 'test/benchmark-spawn.c', + 'test/benchmark-thread.c', + 'test/benchmark-tcp-write-batch.c', + 'test/benchmark-udp-pummel.c', + 'test/dns-server.c', + 'test/echo-server.c', + 'test/blackhole-server.c', + 'test/run-benchmarks.c', + 'test/runner.c', + 'test/runner.h', + 'test/task.h', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'test/runner-win.c', + 'test/runner-win.h', + ], + 'libraries': [ 'ws2_32.lib' ] + }, { # POSIX + 'defines': [ '_GNU_SOURCE' ], + 'sources': [ + 'test/runner-unix.c', + 'test/runner-unix.h', + ] + }] + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + + { + 'target_name': 'uv_dtrace_header', + 'type': 'none', + 'conditions': [ + [ 'uv_use_dtrace=="true"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_header', + 'inputs': [ 'src/unix/uv-dtrace.d' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/uv-dtrace.h' ], + 'action': [ 'dtrace', '-h', '-xnolibs', '-s', '<@(_inputs)', + '-o', '<@(_outputs)' ], + }, + ], + }], + ], + }, + + # FIXME(bnoordhuis or tjfontaine) Unify this, it's extremely ugly. + { + 'target_name': 'uv_dtrace_provider', + 'type': 'none', + 'conditions': [ + [ 'uv_use_dtrace=="true" and OS not in "mac linux"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_o', + 'inputs': [ + 'src/unix/uv-dtrace.d', + '<(PRODUCT_DIR)/obj.target/libuv<(uv_parent_path)src/unix/core.o', + ], + 'outputs': [ + '<(PRODUCT_DIR)/obj.target/libuv<(uv_parent_path)src/unix/dtrace.o', + ], + 'action': [ 'dtrace', '-G', '-xnolibs', '-s', '<@(_inputs)', + '-o', '<@(_outputs)' ] + } + ] + }], + [ 'uv_use_dtrace=="true" and OS=="linux"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_o', + 'inputs': [ 'src/unix/uv-dtrace.d' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/dtrace.o' ], + 'action': [ + 'dtrace', '-C', '-G', '-s', '<@(_inputs)', '-o', '<@(_outputs)' + ], + } + ] + }], + ] + }, + + ] +} diff --git a/vcbuild.bat b/vcbuild.bat new file mode 100644 index 0000000000..8545b2635b --- /dev/null +++ b/vcbuild.bat @@ -0,0 +1,144 @@ +@echo off + +cd %~dp0 + +if /i "%1"=="help" goto help +if /i "%1"=="--help" goto help +if /i "%1"=="-help" goto help +if /i "%1"=="/help" goto help +if /i "%1"=="?" goto help +if /i "%1"=="-?" goto help +if /i "%1"=="--?" goto help +if /i "%1"=="/?" goto help + +@rem Process arguments. +set config= +set target=Build +set noprojgen= +set nobuild= +set run= +set target_arch=ia32 +set vs_toolset=x86 +set platform=WIN32 +set library=static_library + +:next-arg +if "%1"=="" goto args-done +if /i "%1"=="debug" set config=Debug&goto arg-ok +if /i "%1"=="release" set config=Release&goto arg-ok +if /i "%1"=="test" set run=run-tests.exe&goto arg-ok +if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok +if /i "%1"=="clean" set target=Clean&goto arg-ok +if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok +if /i "%1"=="nobuild" set nobuild=1&goto arg-ok +if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="x64" set target_arch=x64&set platform=amd64&set vs_toolset=x64&goto arg-ok +if /i "%1"=="shared" set library=shared_library&goto arg-ok +if /i "%1"=="static" set library=static_library&goto arg-ok +:arg-ok +shift +goto next-arg +:args-done + +@rem Look for Visual Studio 2013 +if not defined VS120COMNTOOLS goto vc-set-2012 +if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 +call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% +set GYP_MSVS_VERSION=2013 +goto select-target + +@rem Look for Visual Studio 2012 +:vc-set-2012 +if not defined VS110COMNTOOLS goto vc-set-2010 +if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 +call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% +set GYP_MSVS_VERSION=2012 +goto select-target + +:vc-set-2010 +@rem Look for Visual Studio 2010 +if not defined VS100COMNTOOLS goto vc-set-2008 +if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008 +call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% +set GYP_MSVS_VERSION=2010 +goto select-target + +:vc-set-2008 +@rem Look for Visual Studio 2008 +if not defined VS90COMNTOOLS goto vc-set-notfound +if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound +call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% +set GYP_MSVS_VERSION=2008 +goto select-target + +:vc-set-notfound +echo Warning: Visual Studio not found + +:select-target +if not "%config%"=="" goto project-gen +if "%run%"=="run-tests.exe" set config=Debug& goto project-gen +if "%run%"=="run-benchmarks.exe" set config=Release& goto project-gen +set config=Debug + +:project-gen +@rem Skip project generation if requested. +if defined noprojgen goto msbuild + +@rem Generate the VS project. +if exist build\gyp goto have_gyp +echo git clone https://git.chromium.org/external/gyp.git build/gyp +git clone https://git.chromium.org/external/gyp.git build/gyp +if errorlevel 1 goto gyp_install_failed +goto have_gyp + +:gyp_install_failed +echo Failed to download gyp. Make sure you have git installed, or +echo manually install gyp into %~dp0build\gyp. +exit /b 1 + +:have_gyp +if not defined PYTHON set PYTHON="python" +%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Dlibrary=%library% +if errorlevel 1 goto create-msvs-files-failed +if not exist uv.sln goto create-msvs-files-failed +echo Project files generated. + +:msbuild +@rem Skip project generation if requested. +if defined nobuild goto run + +@rem Check if VS build env is available +if not defined VCINSTALLDIR goto msbuild-not-found +goto msbuild-found + +:msbuild-not-found +echo Build skipped. To build, this file needs to run from VS cmd prompt. +goto run + +@rem Build the sln with msbuild. +:msbuild-found +msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +if errorlevel 1 exit /b 1 + +:run +@rem Run tests if requested. +if "%run%"=="" goto exit +if not exist %config%\%run% goto exit +echo running '%config%\%run%' +%config%\%run% +goto exit + +:create-msvs-files-failed +echo Failed to create vc project files. +exit /b 1 + +:help +echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [x86/x64] [static/shared] +echo Examples: +echo vcbuild.bat : builds debug build +echo vcbuild.bat test : builds debug build and runs tests +echo vcbuild.bat release bench: builds release build and runs benchmarks +goto exit + +:exit -- cgit From d047b28ac140b082ef31b9ee7769da505bfd509d Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 10:03:11 +0000 Subject: get-libuv.sh: compile bundled libuv Rename file to reflect new intent of script. Libuv is bundled into the third-party directory. Modify the script to compile but not fetch libuv. --- scripts/compile-libuv.sh | 10 ++++++++++ scripts/get-libuv.sh | 16 ---------------- 2 files changed, 10 insertions(+), 16 deletions(-) create mode 100644 scripts/compile-libuv.sh delete mode 100644 scripts/get-libuv.sh diff --git a/scripts/compile-libuv.sh b/scripts/compile-libuv.sh new file mode 100644 index 0000000000..f07120ed56 --- /dev/null +++ b/scripts/compile-libuv.sh @@ -0,0 +1,10 @@ +. scripts/common.sh + +uv_dir="third-party/libuv" + +cd "$uv_dir" +sh autogen.sh +./configure --prefix="$prefix" +make +make install +rm "$prefix/lib/"libuv*.{so,dylib} "$prefix/lib/"libuv*.{so,dylib}.* || true diff --git a/scripts/get-libuv.sh b/scripts/get-libuv.sh deleted file mode 100644 index 9f3eceb218..0000000000 --- a/scripts/get-libuv.sh +++ /dev/null @@ -1,16 +0,0 @@ -. scripts/common.sh - -uv_repo=joyent/libuv -uv_ver=v0.11.19 -uv_dir="$deps/uv-$uv_ver" -uv_sha1=5539d8e99e22b438cf4a412d4cec70ac6bb519fc - -rm -rf "$uv_dir" - -github_download "$uv_repo" "$uv_ver" "$uv_dir" "$uv_sha1" -cd "$uv_dir" -sh autogen.sh -./configure --prefix="$prefix" -make -make install -rm "$prefix/lib/"libuv*.{so,dylib} "$prefix/lib/"libuv*.{so,dylib}.* || true -- cgit From aad5f6341edb8fbe950fcc7c9a2b04bc62da4d82 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 10:04:42 +0000 Subject: Makefile: refer to renamed compile-libuv.sh get-libuv.sh was renamed to compile-libuv.sh --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6e456022c2..634c0a839c 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ test: build/src/vim deps: .deps/usr/lib/libuv.a .deps/usr/lib/libuv.a: - sh -e scripts/get-libuv.sh + sh -e scripts/compile-libuv.sh cmake: clean mkdir build -- cgit From 31cb3e09d47f2022c457a0f54a4dcb51cd4a79f4 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 10:31:37 +0000 Subject: third-party: add note on role of directory Add a brief README on the purpose of the third-party directory and some suggestions for how to manage it. The neovim bigwigs may want to re-draft the README. --- third-party/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 third-party/README.md diff --git a/third-party/README.md b/third-party/README.md new file mode 100644 index 0000000000..0d4c521e87 --- /dev/null +++ b/third-party/README.md @@ -0,0 +1,9 @@ +# Third party dependencies for neovim + +This directory contains any third party dependencies for neovim which, for one +reason or another, we cannot rely on the system to supply. + +Ideally commits within this directory will only be merge commits from upstream +projects. The "git subtree" tool is a good choice for managing such merge +commits. In order to avoid needlessly inflating the bandwidth required to clone +neovim, the ``--squash`` option for git subtree should be used. -- cgit From b76c358f3de9106a4bdbf853b4c4371f6f7a62c2 Mon Sep 17 00:00:00 2001 From: scott-linder Date: Sun, 23 Feb 2014 15:34:45 -0500 Subject: Convert function declarations from K&R to ANSI style. cproto (http://invisible-island.net/cproto/) was used to do the bulk of the work in batch; even the most recent version had some issues with typedef'd parameters; a quick "patch" was to modify `lex.l` to explicitly include all vim typedefs as known types. One example from `vim.h` is typedef unsigned char char_u; which was added in `lex.l` as char_u { save_text_offset(); return T_CHAR; } Even with these changes there were some problems: * Two files (`mbyte.c` and `os_unix.c`) were not cleanly converted. * Any function with the `UNUSED` macro in its parameter list was not converted. Rather than spend more time fixing the automated approach, the two files `mbyte.c` and `os_unix.c` were converted by hand. The `UNUSED` macros were compiler specific, and the alternative, generic version would require a different syntax, so in order to simplify the conversion all uses of `UNUSED` were stripped, and then the sources were run back through cproto. It is planned to reconsider each use of `UNUSED` manually using a new macro definition. --- config/config.h.in | 1 - src/arabic.c | 70 +- src/blowfish.c | 44 +- src/buffer.c | 394 ++++----- src/charset.c | 230 ++--- src/diff.c | 174 ++-- src/digraph.c | 34 +- src/edit.c | 508 +++++------ src/eval.c | 2511 +++++++++++++++++----------------------------------- src/ex_cmds.c | 302 +++---- src/ex_cmds2.c | 328 +++---- src/ex_docmd.c | 761 ++++++---------- src/ex_eval.c | 131 +-- src/ex_getln.c | 408 ++++----- src/farsi.c | 90 +- src/fileio.c | 535 +++++------ src/fold.c | 353 +++----- src/getchar.c | 353 ++++---- src/hangulin.c | 69 +- src/hardcopy.c | 266 ++---- src/hashtab.c | 52 +- src/if_cscope.c | 178 ++-- src/main.c | 133 ++- src/mark.c | 151 +--- src/mbyte.c | 901 +++++++++---------- src/memfile.c | 156 +--- src/memline.c | 293 +++--- src/menu.c | 138 ++- src/message.c | 388 +++----- src/misc1.c | 728 +++++++-------- src/misc2.c | 591 +++++-------- src/move.c | 158 ++-- src/normal.c | 457 ++++------ src/ops.c | 359 +++----- src/option.c | 481 +++++----- src/os_unix.c | 269 +++--- src/os_unix.h | 2 +- src/po/sjiscorr.c | 13 +- src/popupmnu.c | 24 +- src/quickfix.c | 260 ++---- src/regexp.c | 346 +++----- src/regexp_nfa.c | 303 +++---- src/screen.c | 396 +++------ src/search.c | 330 ++++--- src/sha256.c | 37 +- src/spell.c | 976 ++++++++------------ src/syntax.c | 672 ++++++-------- src/tag.c | 144 ++- src/term.c | 257 +++--- src/ui.c | 115 +-- src/undo.c | 225 ++--- src/version.c | 32 +- src/vim.h | 8 - src/window.c | 585 +++++------- 54 files changed, 6837 insertions(+), 10883 deletions(-) diff --git a/config/config.h.in b/config/config.h.in index 60729562af..34aa72a52f 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -12,7 +12,6 @@ #define SIZEOF_OFF_T @SIZEOF_OFF_T@ #define _FILE_OFFSET_BITS 64 -#define HAVE_ATTRIBUTE_UNUSED 1 #define HAVE_BCMP 1 #define HAVE_DATE_TIME 1 #define HAVE_DIRENT_H 1 diff --git a/src/arabic.c b/src/arabic.c index c8d3fc2a69..3aec35aba3 100644 --- a/src/arabic.c +++ b/src/arabic.c @@ -42,8 +42,7 @@ static int A_is_special __ARGS((int c)); /* * Returns True if c is an ISO-8859-6 shaped ARABIC letter (user entered) */ -static int A_is_a(cur_c) -int cur_c; +static int A_is_a(int cur_c) { switch (cur_c) { case a_HAMZA: @@ -93,8 +92,7 @@ int cur_c; /* * Returns True if c is an Isolated Form-B ARABIC letter */ -static int A_is_s(cur_c) -int cur_c; +static int A_is_s(int cur_c) { switch (cur_c) { case a_s_HAMZA: @@ -143,8 +141,7 @@ int cur_c; /* * Returns True if c is a Final shape of an ARABIC letter */ -static int A_is_f(cur_c) -int cur_c; +static int A_is_f(int cur_c) { switch (cur_c) { case a_f_ALEF_MADDA: @@ -195,8 +192,7 @@ int cur_c; /* * Change shape - from ISO-8859-6/Isolated to Form-B Isolated */ -static int chg_c_a2s(cur_c) -int cur_c; +static int chg_c_a2s(int cur_c) { int tempc; @@ -323,8 +319,7 @@ int cur_c; /* * Change shape - from ISO-8859-6/Isolated to Initial */ -static int chg_c_a2i(cur_c) -int cur_c; +static int chg_c_a2i(int cur_c) { int tempc; @@ -451,8 +446,7 @@ int cur_c; /* * Change shape - from ISO-8859-6/Isolated to Medial */ -static int chg_c_a2m(cur_c) -int cur_c; +static int chg_c_a2m(int cur_c) { int tempc; @@ -579,8 +573,7 @@ int cur_c; /* * Change shape - from ISO-8859-6/Isolated to final */ -static int chg_c_a2f(cur_c) -int cur_c; +static int chg_c_a2f(int cur_c) { int tempc; @@ -717,8 +710,7 @@ int cur_c; /* * Change shape - from Initial to Medial */ -static int chg_c_i2m(cur_c) -int cur_c; +static int chg_c_i2m(int cur_c) { int tempc; @@ -803,8 +795,7 @@ int cur_c; /* * Change shape - from Final to Medial */ -static int chg_c_f2m(cur_c) -int cur_c; +static int chg_c_f2m(int cur_c) { int tempc; @@ -911,8 +902,7 @@ int cur_c; /* * Change shape - from Combination (2 char) to an Isolated */ -static int chg_c_laa2i(hid_c) -int hid_c; +static int chg_c_laa2i(int hid_c) { int tempc; @@ -940,8 +930,7 @@ int hid_c; /* * Change shape - from Combination-Isolated to Final */ -static int chg_c_laa2f(hid_c) -int hid_c; +static int chg_c_laa2f(int hid_c) { int tempc; @@ -968,8 +957,7 @@ int hid_c; /* * Do "half-shaping" on character "c". Return zero if no shaping. */ -static int half_shape(c) -int c; +static int half_shape(int c) { if (A_is_a(c)) return chg_c_a2i(c); @@ -987,13 +975,7 @@ int c; * (not shaped) * in: "next_c" is the next character (not shaped). */ -int arabic_shape(c, ccp, c1p, prev_c, prev_c1, next_c) -int c; -int *ccp; -int *c1p; -int prev_c; -int prev_c1; -int next_c; +int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1, int next_c) { int curr_c; int shape_c; @@ -1054,9 +1036,11 @@ int next_c; /* * A_firstc_laa returns first character of LAA combination if it exists */ -static int A_firstc_laa(c, c1) -int c; /* base character */ -int c1; /* first composing character */ +static int +A_firstc_laa ( + int c, /* base character */ + int c1 /* first composing character */ +) { if (c1 != NUL && c == a_LAM && !A_is_harakat(c1)) return c1; @@ -1068,8 +1052,7 @@ int c1; /* first composing character */ * A_is_harakat returns TRUE if 'c' is an Arabic Harakat character * (harakat/tanween) */ -static int A_is_harakat(c) -int c; +static int A_is_harakat(int c) { return c >= a_FATHATAN && c <= a_SUKUN; } @@ -1079,8 +1062,7 @@ int c; * A_is_iso returns TRUE if 'c' is an Arabic ISO-8859-6 character * (alphabet/number/punctuation) */ -static int A_is_iso(c) -int c; +static int A_is_iso(int c) { return (c >= a_HAMZA && c <= a_GHAIN) || (c >= a_TATWEEL && c <= a_HAMZA_BELOW) @@ -1092,8 +1074,7 @@ int c; * A_is_formb returns TRUE if 'c' is an Arabic 10646-1 FormB character * (alphabet/number/punctuation) */ -static int A_is_formb(c) -int c; +static int A_is_formb(int c) { return (c >= a_s_FATHATAN && c <= a_s_DAMMATAN) || c == a_s_KASRATAN @@ -1105,8 +1086,7 @@ int c; /* * A_is_ok returns TRUE if 'c' is an Arabic 10646 (8859-6 or Form-B) */ -static int A_is_ok(c) -int c; +static int A_is_ok(int c) { return A_is_iso(c) || A_is_formb(c); } @@ -1116,8 +1096,7 @@ int c; * A_is_valid returns TRUE if 'c' is an Arabic 10646 (8859-6 or Form-B) * with some exceptions/exclusions */ -static int A_is_valid(c) -int c; +static int A_is_valid(int c) { return A_is_ok(c) && !A_is_special(c); } @@ -1127,8 +1106,7 @@ int c; * A_is_special returns TRUE if 'c' is not a special Arabic character. * Specials don't adhere to most of the rules. */ -static int A_is_special(c) -int c; +static int A_is_special(int c) { return c == a_HAMZA || c == a_s_HAMZA; } diff --git a/src/blowfish.c b/src/blowfish.c index 2e4d8cf1af..df820d1152 100644 --- a/src/blowfish.c +++ b/src/blowfish.c @@ -319,9 +319,7 @@ static UINT32_T sbi[4][256] = { sbx[3][xr & 0xFF]; -static void bf_e_block(p_xl, p_xr) -UINT32_T *p_xl; -UINT32_T *p_xr; +static void bf_e_block(UINT32_T *p_xl, UINT32_T *p_xr) { UINT32_T temp, xl = *p_xl, xr = *p_xr; @@ -346,8 +344,7 @@ UINT32_T *p_xr; # define htonl2(x) #endif -static void bf_e_cblock(block) -char_u *block; +static void bf_e_cblock(char_u *block) { block8 bk; @@ -365,10 +362,7 @@ char_u *block; * Initialize the crypt method using "password" as the encryption key and * "salt[salt_len]" as the salt. */ -void bf_key_init(password, salt, salt_len) -char_u *password; -char_u *salt; -int salt_len; +void bf_key_init(char_u *password, char_u *salt, int salt_len) { int i, j, keypos = 0; unsigned u; @@ -421,10 +415,7 @@ int salt_len; /* * BF Self test for corrupted tables or instructions */ -static int bf_check_tables(a_ipa, a_sbi, val) -UINT32_T a_ipa[18]; -UINT32_T a_sbi[4][256]; -UINT32_T val; +static int bf_check_tables(UINT32_T a_ipa[18], UINT32_T a_sbi[4][256], UINT32_T val) { int i, j; UINT32_T c = 0; @@ -464,7 +455,7 @@ static struct_bf_test_data bf_test_data[] = { /* * Return FAIL when there is something wrong with blowfish encryption. */ -static int bf_self_test() { +static int bf_self_test(void) { int i, bn; int err = 0; block8 bk; @@ -509,9 +500,7 @@ static char_u ofb_buffer[BF_OFB_LEN]; /* 64 bytes */ /* * Initialize with seed "iv[iv_len]". */ -void bf_ofb_init(iv, iv_len) -char_u *iv; -int iv_len; +void bf_ofb_init(char_u *iv, int iv_len) { int i, mi; @@ -542,10 +531,7 @@ int iv_len; * Encrypt "from[len]" into "to[len]". * "from" and "to" can be equal to encrypt in place. */ -void bf_crypt_encode(from, len, to) -char_u *from; -size_t len; -char_u *to; +void bf_crypt_encode(char_u *from, size_t len, char_u *to) { size_t i; int ztemp, t; @@ -561,9 +547,7 @@ char_u *to; /* * Decrypt "ptr[len]" in place. */ -void bf_crypt_decode(ptr, len) -char_u *ptr; -long len; +void bf_crypt_decode(char_u *ptr, long len) { char_u *p; int t; @@ -579,8 +563,10 @@ long len; * Initialize the encryption keys and the random header according to * the given password. */ -void bf_crypt_init_keys(passwd) -char_u *passwd; /* password string with which to modify keys */ +void +bf_crypt_init_keys ( + char_u *passwd /* password string with which to modify keys */ +) { char_u *p; @@ -599,7 +585,7 @@ static UINT32_T save_sbx[4][256]; * Save the current crypt state. Can only be used once before * bf_crypt_restore(). */ -void bf_crypt_save() { +void bf_crypt_save(void) { save_randbyte_offset = randbyte_offset; save_update_offset = update_offset; mch_memmove(save_ofb_buffer, ofb_buffer, BF_OFB_LEN); @@ -611,7 +597,7 @@ void bf_crypt_save() { * Restore the current crypt state. Can only be used after * bf_crypt_save(). */ -void bf_crypt_restore() { +void bf_crypt_restore(void) { randbyte_offset = save_randbyte_offset; update_offset = save_update_offset; mch_memmove(ofb_buffer, save_ofb_buffer, BF_OFB_LEN); @@ -623,7 +609,7 @@ void bf_crypt_restore() { * Run a test to check if the encryption works as expected. * Give an error and return FAIL when not. */ -int blowfish_self_test() { +int blowfish_self_test(void) { if (sha256_self_test() == FAIL) { EMSG(_("E818: sha256 test failed")); return FAIL; diff --git a/src/buffer.c b/src/buffer.c index bffae5388d..de1af62307 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -64,10 +64,12 @@ static char *e_auabort = N_("E855: Autocommands caused command to abort"); * memory. * Return FAIL for failure, OK otherwise. */ -int open_buffer(read_stdin, eap, flags) -int read_stdin; /* read file from stdin */ -exarg_T *eap; /* for forced 'ff' and 'fenc' or NULL */ -int flags; /* extra flags for readfile() */ +int +open_buffer ( + int read_stdin, /* read file from stdin */ + exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */ + int flags /* extra flags for readfile() */ +) { int retval = OK; buf_T *old_curbuf; @@ -231,8 +233,7 @@ int flags; /* extra flags for readfile() */ /* * Return TRUE if "buf" points to a valid buffer (in the buffer list). */ -int buf_valid(buf) -buf_T *buf; +int buf_valid(buf_T *buf) { buf_T *bp; @@ -259,11 +260,13 @@ buf_T *buf; * cause there to be only one window with this buffer. e.g. when ":quit" is * supposed to close the window but autocommands close all other windows. */ -void close_buffer(win, buf, action, abort_if_last) -win_T *win; /* if not NULL, set b_last_cursor */ -buf_T *buf; -int action; -int abort_if_last UNUSED; +void +close_buffer ( + win_T *win, /* if not NULL, set b_last_cursor */ + buf_T *buf, + int action, + int abort_if_last +) { int is_curbuf; int nwindows; @@ -421,8 +424,7 @@ aucmd_abort: /* * Make buffer not contain a file. */ -void buf_clear_file(buf) -buf_T *buf; +void buf_clear_file(buf_T *buf) { buf->b_ml.ml_line_count = 1; unchanged(buf, TRUE); @@ -444,9 +446,7 @@ buf_T *buf; * BFA_WIPE buffer is going to be wiped out * BFA_KEEP_UNDO do not free undo information */ -void buf_freeall(buf, flags) -buf_T *buf; -int flags; +void buf_freeall(buf_T *buf, int flags) { int is_curbuf = (buf == curbuf); @@ -506,8 +506,7 @@ int flags; * Free a buffer structure and the things it contains related to the buffer * itself (not the file, that must have been done already). */ -static void free_buffer(buf) -buf_T *buf; +static void free_buffer(buf_T *buf) { free_buffer_stuff(buf, TRUE); unref_var_dict(buf->b_vars); @@ -518,9 +517,11 @@ buf_T *buf; /* * Free stuff in the buffer for ":bdel" and when wiping out the buffer. */ -static void free_buffer_stuff(buf, free_options) -buf_T *buf; -int free_options; /* free options as well */ +static void +free_buffer_stuff ( + buf_T *buf, + int free_options /* free options as well */ +) { if (free_options) { clear_wininfo(buf); /* including window-local options */ @@ -539,8 +540,7 @@ int free_options; /* free options as well */ /* * Free the b_wininfo list for buffer "buf". */ -static void clear_wininfo(buf) -buf_T *buf; +static void clear_wininfo(buf_T *buf) { wininfo_T *wip; @@ -558,11 +558,7 @@ buf_T *buf; /* * Go to another buffer. Handles the result of the ATTENTION dialog. */ -void goto_buffer(eap, start, dir, count) -exarg_T *eap; -int start; -int dir; -int count; +void goto_buffer(exarg_T *eap, int start, int dir, int count) { # if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION) buf_T *old_curbuf = curbuf; @@ -597,8 +593,7 @@ int count; * Handle the situation of swap_exists_action being set. * It is allowed for "old_curbuf" to be NULL or invalid. */ -void handle_swap_exists(old_curbuf) -buf_T *old_curbuf; +void handle_swap_exists(buf_T *old_curbuf) { cleanup_T cs; long old_tw = curbuf->b_p_tw; @@ -659,13 +654,15 @@ buf_T *old_curbuf; * * Returns error message or NULL */ -char_u * do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit) -int command; -char_u *arg; /* pointer to extra arguments */ -int addr_count; -int start_bnr; /* first buffer number in a range */ -int end_bnr; /* buffer nr or last buffer nr in a range */ -int forceit; +char_u * +do_bufdel ( + int command, + char_u *arg, /* pointer to extra arguments */ + int addr_count, + int start_bnr, /* first buffer number in a range */ + int end_bnr, /* buffer nr or last buffer nr in a range */ + int forceit +) { int do_current = 0; /* delete current buffer? */ int deleted = 0; /* number of buffers deleted */ @@ -762,10 +759,7 @@ static int empty_curbuf __ARGS((int close_others, int forceit, int action)); * Make the current buffer empty. * Used when it is wiped out and it's the last buffer. */ -static int empty_curbuf(close_others, forceit, action) -int close_others; -int forceit; -int action; +static int empty_curbuf(int close_others, int forceit, int action) { int retval; buf_T *buf = curbuf; @@ -811,12 +805,14 @@ int action; * * Return FAIL or OK. */ -int do_buffer(action, start, dir, count, forceit) -int action; -int start; -int dir; /* FORWARD or BACKWARD */ -int count; /* buffer number or number of buffers */ -int forceit; /* TRUE for :...! */ +int +do_buffer ( + int action, + int start, + int dir, /* FORWARD or BACKWARD */ + int count, /* buffer number or number of buffers */ + int forceit /* TRUE for :...! */ +) { buf_T *buf; buf_T *bp; @@ -1100,9 +1096,7 @@ int forceit; /* TRUE for :...! */ * DOBUF_DEL delete it * DOBUF_WIPE wipe it out */ -void set_curbuf(buf, action) -buf_T *buf; -int action; +void set_curbuf(buf_T *buf, int action) { buf_T *prevbuf; int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL @@ -1158,8 +1152,7 @@ int action; * Old curbuf must have been abandoned already! This also means "curbuf" may * be pointing to freed memory. */ -void enter_buffer(buf) -buf_T *buf; +void enter_buffer(buf_T *buf) { /* Copy buffer and window local option values. Not for a help buffer. */ buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); @@ -1237,7 +1230,7 @@ buf_T *buf; /* * Change to the directory of the current buffer. */ -void do_autochdir() { +void do_autochdir(void) { if (curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname) == OK) shorten_fnames(TRUE); } @@ -1257,11 +1250,13 @@ void do_autochdir() { */ static int top_file_num = 1; /* highest file number */ -buf_T * buflist_new(ffname, sfname, lnum, flags) -char_u *ffname; /* full path of fname or relative */ -char_u *sfname; /* short fname or NULL */ -linenr_T lnum; /* preferred cursor line */ -int flags; /* BLN_ defines */ +buf_T * +buflist_new ( + char_u *ffname, /* full path of fname or relative */ + char_u *sfname, /* short fname or NULL */ + linenr_T lnum, /* preferred cursor line */ + int flags /* BLN_ defines */ +) { buf_T *buf; #ifdef UNIX @@ -1451,9 +1446,7 @@ int flags; /* BLN_ defines */ * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and * 'fileencoding'. */ -void free_buf_options(buf, free_p_ff) -buf_T *buf; -int free_p_ff; +void free_buf_options(buf_T *buf, int free_p_ff) { if (free_p_ff) { clear_string_option(&buf->b_p_fenc); @@ -1516,11 +1509,7 @@ int free_p_ff; * * return FAIL for failure, OK for success */ -int buflist_getfile(n, lnum, options, forceit) -int n; -linenr_T lnum; -int options; -int forceit; +int buflist_getfile(int n, linenr_T lnum, int options, int forceit) { buf_T *buf; win_T *wp = NULL; @@ -1596,7 +1585,7 @@ int forceit; /* * go to the last know line number for the current buffer */ -void buflist_getfpos() { +void buflist_getfpos(void) { pos_T *fpos; fpos = buflist_findfpos(curbuf); @@ -1618,8 +1607,7 @@ void buflist_getfpos() { * Find file in buffer list by name (it has to be for the current window). * Returns NULL if not found. */ -buf_T * buflist_findname_exp(fname) -char_u *fname; +buf_T *buflist_findname_exp(char_u *fname) { char_u *ffname; buf_T *buf = NULL; @@ -1645,8 +1633,7 @@ char_u *fname; * Skips dummy buffers. * Returns NULL if not found. */ -buf_T * buflist_findname(ffname) -char_u *ffname; +buf_T *buflist_findname(char_u *ffname) { #ifdef UNIX struct stat st; @@ -1661,9 +1648,7 @@ char_u *ffname; * twice for the same file. * Returns NULL if not found. */ -static buf_T * buflist_findname_stat(ffname, stp) -char_u *ffname; -struct stat *stp; +static buf_T *buflist_findname_stat(char_u *ffname, struct stat *stp) { #endif buf_T *buf; @@ -1685,12 +1670,14 @@ struct stat *stp; * Return fnum of the found buffer. * Return < 0 for error. */ -int buflist_findpat(pattern, pattern_end, unlisted, diffmode, curtab_only) -char_u *pattern; -char_u *pattern_end; /* pointer to first char after pattern */ -int unlisted; /* find unlisted buffers */ -int diffmode UNUSED; /* find diff-mode buffers only */ -int curtab_only; /* find buffers in current tab only */ +int +buflist_findpat ( + char_u *pattern, + char_u *pattern_end, /* pointer to first char after pattern */ + int unlisted, /* find unlisted buffers */ + int diffmode, /* find diff-mode buffers only */ + int curtab_only /* find buffers in current tab only */ +) { buf_T *buf; regprog_T *prog; @@ -1794,11 +1781,7 @@ int curtab_only; /* find buffers in current tab only */ * For command line expansion of ":buf" and ":sbuf". * Return OK if matches found, FAIL otherwise. */ -int ExpandBufnames(pat, num_file, file, options) -char_u *pat; -int *num_file; -char_u ***file; -int options; +int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options) { int count = 0; buf_T *buf; @@ -1886,9 +1869,7 @@ int options; /* * Check for a match on the file name for buffer "buf" with regprog "prog". */ -static char_u * buflist_match(prog, buf) -regprog_T *prog; -buf_T *buf; +static char_u *buflist_match(regprog_T *prog, buf_T *buf) { char_u *match; @@ -1904,9 +1885,7 @@ buf_T *buf; * Try matching the regexp in "prog" with file name "name". * Return "name" when there is a match, NULL when not. */ -static char_u * fname_match(prog, name) -regprog_T *prog; -char_u *name; +static char_u *fname_match(regprog_T *prog, char_u *name) { char_u *match = NULL; char_u *p; @@ -1933,8 +1912,7 @@ char_u *name; /* * find file in buffer list by number */ -buf_T * buflist_findnr(nr) -int nr; +buf_T *buflist_findnr(int nr) { buf_T *buf; @@ -1952,10 +1930,12 @@ int nr; * home_replace() is used to shorten the file name (used for marks). * Returns a pointer to allocated memory, of NULL when failed. */ -char_u * buflist_nr2name(n, fullname, helptail) -int n; -int fullname; -int helptail; /* for help buffers return tail only */ +char_u * +buflist_nr2name ( + int n, + int fullname, + int helptail /* for help buffers return tail only */ +) { buf_T *buf; @@ -1971,12 +1951,7 @@ int helptail; /* for help buffers return tail only */ * When "copy_options" is TRUE save the local window option values. * When "lnum" is 0 only do the options. */ -static void buflist_setfpos(buf, win, lnum, col, copy_options) -buf_T *buf; -win_T *win; -linenr_T lnum; -colnr_T col; -int copy_options; +static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options) { wininfo_T *wip; @@ -2032,8 +2007,7 @@ static int wininfo_other_tab_diff __ARGS((wininfo_T *wip)); * Return TRUE when "wip" has 'diff' set and the diff is only for another tab * page. That's because a diff is local to a tab page. */ -static int wininfo_other_tab_diff(wip) -wininfo_T *wip; +static int wininfo_other_tab_diff(wininfo_T *wip) { win_T *wp; @@ -2055,9 +2029,7 @@ wininfo_T *wip; * another tab page. * Returns NULL when there isn't any info. */ -static wininfo_T * find_wininfo(buf, skip_diff_buffer) -buf_T *buf; -int skip_diff_buffer UNUSED; +static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer) { wininfo_T *wip; @@ -2086,8 +2058,7 @@ int skip_diff_buffer UNUSED; * the most recently used window. If the values were never set, use the * global values for the window. */ -void get_winopts(buf) -buf_T *buf; +void get_winopts(buf_T *buf) { wininfo_T *wip; @@ -2114,8 +2085,7 @@ buf_T *buf; * window. * Returns a pointer to no_position if no position is found. */ -pos_T * buflist_findfpos(buf) -buf_T *buf; +pos_T *buflist_findfpos(buf_T *buf) { wininfo_T *wip; static pos_T no_position = INIT_POS_T(1, 0, 0); @@ -2130,8 +2100,7 @@ buf_T *buf; /* * Find the lnum for the buffer 'buf' for the current window. */ -linenr_T buflist_findlnum(buf) -buf_T *buf; +linenr_T buflist_findlnum(buf_T *buf) { return buflist_findfpos(buf)->lnum; } @@ -2139,8 +2108,7 @@ buf_T *buf; /* * List all know file names (for :files and :buffers command). */ -void buflist_list(eap) -exarg_T *eap; +void buflist_list(exarg_T *eap) { buf_T *buf; int len; @@ -2188,10 +2156,7 @@ exarg_T *eap; * Used by insert_reg() and cmdline_paste() for '#' register. * Return FAIL if not found, OK for success. */ -int buflist_name_nr(fnum, fname, lnum) -int fnum; -char_u **fname; -linenr_T *lnum; +int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum) { buf_T *buf; @@ -2211,10 +2176,13 @@ linenr_T *lnum; * Returns FAIL for failure (file name already in use by other buffer) * OK otherwise. */ -int setfname(buf, ffname, sfname, message) -buf_T *buf; -char_u *ffname, *sfname; -int message; /* give message when buffer already exists */ +int +setfname ( + buf_T *buf, + char_u *ffname, + char_u *sfname, + int message /* give message when buffer already exists */ +) { buf_T *obuf = NULL; #ifdef UNIX @@ -2300,9 +2268,7 @@ int message; /* give message when buffer already exists */ * Crude way of changing the name of a buffer. Use with care! * The name should be relative to the current directory. */ -void buf_set_name(fnum, name) -int fnum; -char_u *name; +void buf_set_name(int fnum, char_u *name) { buf_T *buf; @@ -2323,8 +2289,7 @@ char_u *name; * Take care of what needs to be done when the name of buffer "buf" has * changed. */ -void buf_name_changed(buf) -buf_T *buf; +void buf_name_changed(buf_T *buf) { /* * If the file name changed, also change the name of the swapfile @@ -2346,10 +2311,7 @@ buf_T *buf; * Used by do_one_cmd(), do_write() and do_ecmd(). * Return the buffer. */ -buf_T * setaltfname(ffname, sfname, lnum) -char_u *ffname; -char_u *sfname; -linenr_T lnum; +buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum) { buf_T *buf; @@ -2364,8 +2326,10 @@ linenr_T lnum; * Get alternate file name for current window. * Return NULL if there isn't any, and give error message if requested. */ -char_u * getaltfname(errmsg) -int errmsg; /* give error message */ +char_u * +getaltfname ( + int errmsg /* give error message */ +) { char_u *fname; linenr_T dummy; @@ -2384,9 +2348,7 @@ int errmsg; /* give error message */ * * used by qf_init(), main() and doarglist() */ -int buflist_add(fname, flags) -char_u *fname; -int flags; +int buflist_add(char_u *fname, int flags) { buf_T *buf; @@ -2400,7 +2362,7 @@ int flags; /* * Adjust slashes in file names. Called after 'shellslash' was set. */ -void buflist_slash_adjust() { +void buflist_slash_adjust(void) { buf_T *bp; for (bp = firstbuf; bp != NULL; bp = bp->b_next) { @@ -2417,8 +2379,7 @@ void buflist_slash_adjust() { * Set alternate cursor position for the current buffer and window "win". * Also save the local window option values. */ -void buflist_altfpos(win) -win_T *win; +void buflist_altfpos(win_T *win) { buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE); } @@ -2427,8 +2388,7 @@ win_T *win; * Return TRUE if 'ffname' is not the same file as current file. * Fname must have a full path (expanded by mch_FullName()). */ -int otherfile(ffname) -char_u *ffname; +int otherfile(char_u *ffname) { return otherfile_buf(curbuf, ffname #ifdef UNIX @@ -2437,16 +2397,11 @@ char_u *ffname; ); } -static int otherfile_buf(buf, ffname +static int otherfile_buf(buf_T *buf, char_u *ffname #ifdef UNIX - , stp -#endif - ) -buf_T *buf; -char_u *ffname; -#ifdef UNIX -struct stat *stp; + , struct stat *stp #endif +) { /* no name is different */ if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) @@ -2487,8 +2442,7 @@ struct stat *stp; * Set inode and device number for a buffer. * Must always be called when b_fname is changed!. */ -void buf_setino(buf) -buf_T *buf; +void buf_setino(buf_T *buf) { struct stat st; @@ -2503,9 +2457,7 @@ buf_T *buf; /* * Return TRUE if dev/ino in buffer "buf" matches with "stp". */ -static int buf_same_ino(buf, stp) -buf_T *buf; -struct stat *stp; +static int buf_same_ino(buf_T *buf, struct stat *stp) { return buf->b_dev_valid && stp->st_dev == buf->b_dev @@ -2516,10 +2468,12 @@ struct stat *stp; /* * Print info about the current buffer. */ -void fileinfo(fullname, shorthelp, dont_truncate) -int fullname; /* when non-zero print full path */ -int shorthelp; -int dont_truncate; +void +fileinfo ( + int fullname, /* when non-zero print full path */ + int shorthelp, + int dont_truncate +) { char_u *name; int n; @@ -2617,11 +2571,7 @@ int dont_truncate; vim_free(buffer); } -void col_print(buf, buflen, col, vcol) -char_u *buf; -size_t buflen; -int col; -int vcol; +void col_print(char_u *buf, size_t buflen, int col, int vcol) { if (col == vcol) vim_snprintf((char *)buf, buflen, "%d", col); @@ -2636,7 +2586,7 @@ int vcol; static char_u *lasttitle = NULL; static char_u *lasticon = NULL; -void maketitle() { +void maketitle(void) { char_u *p; char_u *t_str = NULL; char_u *i_name; @@ -2803,9 +2753,7 @@ void maketitle() { * from "str" if it does. * Return TRUE when "*last" changed. */ -static int ti_change(str, last) -char_u *str; -char_u **last; +static int ti_change(char_u *str, char_u **last) { if ((str == NULL) != (*last == NULL) || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) { @@ -2822,12 +2770,12 @@ char_u **last; /* * Put current window title back (used after calling a shell) */ -void resettitle() { +void resettitle(void) { mch_settitle(lasttitle, lasticon); } # if defined(EXITFREE) || defined(PROTO) -void free_titles() { +void free_titles(void) { vim_free(lasttitle); vim_free(lasticon); } @@ -2849,17 +2797,18 @@ void free_titles() { * If maxwidth is not zero, the string will be filled at any middle marker * or truncated if too long, fillchar is used for all whitespace. */ -int build_stl_str_hl(wp, out, outlen, fmt, use_sandbox, fillchar, - maxwidth, hltab, tabtab) -win_T *wp; -char_u *out; /* buffer to write into != NameBuff */ -size_t outlen; /* length of out[] */ -char_u *fmt; -int use_sandbox UNUSED; /* "fmt" was set insecurely, use sandbox */ -int fillchar; -int maxwidth; -struct stl_hlrec *hltab; /* return: HL attributes (can be NULL) */ -struct stl_hlrec *tabtab; /* return: tab page nrs (can be NULL) */ +int +build_stl_str_hl ( + win_T *wp, + char_u *out, /* buffer to write into != NameBuff */ + size_t outlen, /* length of out[] */ + char_u *fmt, + int use_sandbox, /* "fmt" was set insecurely, use sandbox */ + int fillchar, + int maxwidth, + struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */ + struct stl_hlrec *tabtab /* return: tab page nrs (can be NULL) */ +) { char_u *p; char_u *s; @@ -3574,10 +3523,7 @@ struct stl_hlrec *tabtab; /* return: tab page nrs (can be NULL) */ * Get relative cursor position in window into "buf[buflen]", in the form 99%, * using "Top", "Bot" or "All" when appropriate. */ -void get_rel_pos(wp, buf, buflen) -win_T *wp; -char_u *buf; -int buflen; +void get_rel_pos(win_T *wp, char_u *buf, int buflen) { long above; /* number of lines above window */ long below; /* number of lines below window */ @@ -3601,11 +3547,13 @@ int buflen; * Append (file 2 of 8) to "buf[buflen]", if editing more than one file. * Return TRUE if it was appended. */ -static int append_arg_number(wp, buf, buflen, add_file) -win_T *wp; -char_u *buf; -int buflen; -int add_file; /* Add "file" before the arg number */ +static int +append_arg_number ( + win_T *wp, + char_u *buf, + int buflen, + int add_file /* Add "file" before the arg number */ +) { char_u *p; @@ -3631,8 +3579,7 @@ int add_file; /* Add "file" before the arg number */ * If fname is not a full path, make it a full path. * Returns pointer to allocated memory (NULL for failure). */ -char_u * fix_fname(fname) -char_u *fname; +char_u *fix_fname(char_u *fname) { /* * Force expanding the path always for Unix, because symbolic links may @@ -3674,10 +3621,7 @@ char_u *fname; * Make "ffname" a full file name, set "sfname" to "ffname" if not NULL. * "ffname" becomes a pointer to allocated memory (or NULL). */ -void fname_expand(buf, ffname, sfname) -buf_T *buf UNUSED; -char_u **ffname; -char_u **sfname; +void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname) { if (*ffname == NULL) /* if no file name given, nothing to do */ return; @@ -3703,8 +3647,7 @@ char_u **sfname; /* * Get the file name for an argument list entry. */ -char_u * alist_name(aep) -aentry_T *aep; +char_u *alist_name(aentry_T *aep) { buf_T *bp; @@ -3718,10 +3661,12 @@ aentry_T *aep; /* * do_arg_all(): Open up to 'count' windows, one for each argument. */ -void do_arg_all(count, forceit, keep_tabs) -int count; -int forceit; /* hide buffers in current windows */ -int keep_tabs; /* keep current tabs, for ":tab drop file" */ +void +do_arg_all ( + int count, + int forceit, /* hide buffers in current windows */ + int keep_tabs /* keep current tabs, for ":tab drop file" */ +) { int i; win_T *wp, *wpnext; @@ -3957,8 +3902,7 @@ int keep_tabs; /* keep current tabs, for ":tab drop file" */ /* * Open a window for a number of buffers. */ -void ex_buffer_all(eap) -exarg_T *eap; +void ex_buffer_all(exarg_T *eap) { buf_T *buf; win_T *wp, *wpnext; @@ -4140,8 +4084,7 @@ static int chk_modeline __ARGS((linenr_T, int)); * * Returns immediately if the "ml" option isn't set. */ -void do_modelines(flags) -int flags; +void do_modelines(int flags) { linenr_T lnum; int nmlines; @@ -4174,9 +4117,11 @@ int flags; * chk_modeline() - check a single line for a mode string * Return FAIL if an error encountered. */ -static int chk_modeline(lnum, flags) -linenr_T lnum; -int flags; /* Same as for do_modelines(). */ +static int +chk_modeline ( + linenr_T lnum, + int flags /* Same as for do_modelines(). */ +) { char_u *s; char_u *e; @@ -4281,9 +4226,7 @@ int flags; /* Same as for do_modelines(). */ return retval; } -int read_viminfo_bufferlist(virp, writing) -vir_T *virp; -int writing; +int read_viminfo_bufferlist(vir_T *virp, int writing) { char_u *tab; linenr_T lnum; @@ -4330,8 +4273,7 @@ int writing; return viminfo_readline(virp); } -void write_viminfo_bufferlist(fp) -FILE *fp; +void write_viminfo_bufferlist(FILE *fp) { buf_T *buf; win_T *win; @@ -4379,8 +4321,7 @@ FILE *fp; * Return special buffer name. * Returns NULL when the buffer has a normal file name. */ -char_u * buf_spname(buf) -buf_T *buf; +char_u *buf_spname(buf_T *buf) { if (bt_quickfix(buf)) { win_T *win; @@ -4415,10 +4356,7 @@ buf_T *buf; * If found OK is returned and "wp" and "tp" are set to the window and tabpage. * If not found FAIL is returned. */ -int find_win_for_buf(buf, wp, tp) -buf_T *buf; -win_T **wp; -tabpage_T **tp; +int find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp) { FOR_ALL_TAB_WINDOWS(*tp, *wp) if ((*wp)->w_buffer == buf) @@ -4433,8 +4371,7 @@ win_found: /* * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. */ -void set_buflisted(on) -int on; +void set_buflisted(int on) { if (on != curbuf->b_p_bl) { curbuf->b_p_bl = on; @@ -4449,8 +4386,7 @@ int on; * Read the file for "buf" again and check if the contents changed. * Return TRUE if it changed or this could not be checked. */ -int buf_contents_changed(buf) -buf_T *buf; +int buf_contents_changed(buf_T *buf) { buf_T *newbuf; int differ = TRUE; @@ -4502,9 +4438,11 @@ buf_T *buf; * this buffer. Call this to wipe out a temp buffer that does not contain any * marks. */ -void wipe_buffer(buf, aucmd) -buf_T *buf; -int aucmd UNUSED; /* When TRUE trigger autocommands. */ +void +wipe_buffer ( + buf_T *buf, + int aucmd /* When TRUE trigger autocommands. */ +) { if (buf->b_fnum == top_file_num - 1) --top_file_num; diff --git a/src/charset.c b/src/charset.c index 1eee20f66c..1cc1a79a6f 100644 --- a/src/charset.c +++ b/src/charset.c @@ -56,13 +56,15 @@ static int chartab_initialized = FALSE; * Return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has an * error, OK otherwise. */ -int init_chartab() { +int init_chartab(void) { return buf_init_chartab(curbuf, TRUE); } -int buf_init_chartab(buf, global) -buf_T *buf; -int global; /* FALSE: only set buf->b_chartab[] */ +int +buf_init_chartab ( + buf_T *buf, + int global /* FALSE: only set buf->b_chartab[] */ +) { int c; int c2; @@ -246,9 +248,7 @@ int global; /* FALSE: only set buf->b_chartab[] */ * The result is a string with only printable characters, but if there is not * enough room, not all characters will be translated. */ -void trans_characters(buf, bufsize) -char_u *buf; -int bufsize; +void trans_characters(char_u *buf, int bufsize) { int len; /* length of string needing translation */ int room; /* room in buffer after string */ @@ -283,8 +283,7 @@ int bufsize; * Translate a string into allocated memory, replacing special chars with * printable chars. Returns NULL when out of memory. */ -char_u * transstr(s) -char_u *s; +char_u *transstr(char_u *s) { char_u *res; char_u *p; @@ -342,11 +341,7 @@ char_u *s; * When "buf" is NULL returns an allocated string (NULL for out-of-memory). * Otherwise puts the result in "buf[buflen]". */ -char_u * str_foldcase(str, orglen, buf, buflen) -char_u *str; -int orglen; -char_u *buf; -int buflen; +char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen) { garray_T ga; int i; @@ -440,8 +435,7 @@ int buflen; */ static char_u transchar_buf[7]; -char_u * transchar(c) -int c; +char_u *transchar(int c) { int i; @@ -469,8 +463,7 @@ int c; * Like transchar(), but called with a byte instead of a character. Checks * for an illegal UTF-8 byte. */ -char_u * transchar_byte(c) -int c; +char_u *transchar_byte(int c) { if (enc_utf8 && c >= 0x80) { transchar_nonprint(transchar_buf, c); @@ -484,9 +477,7 @@ int c; * "buf[]". "buf" needs to be able to hold five bytes. * Does NOT work for multi-byte characters, c must be <= 255. */ -void transchar_nonprint(buf, c) -char_u *buf; -int c; +void transchar_nonprint(char_u *buf, int c) { if (c == NL) c = NUL; /* we use newline in place of a NUL */ @@ -518,9 +509,7 @@ int c; } } -void transchar_hex(buf, c) -char_u *buf; -int c; +void transchar_hex(char_u *buf, int c) { int i = 0; @@ -540,8 +529,7 @@ int c; * Lower case letters are used to avoid the confusion of being 0xf1 or * function key 1. */ -static unsigned nr2hex(c) -unsigned c; +static unsigned nr2hex(unsigned c) { if ((c & 0xf) <= 9) return (c & 0xf) + '0'; @@ -556,8 +544,7 @@ unsigned c; * For UTF-8 mode this will return 0 for bytes >= 0x80, because the number of * cells depends on further bytes. */ -int byte2cells(b) -int b; +int byte2cells(int b) { if (enc_utf8 && b >= 0x80) return 0; @@ -569,8 +556,7 @@ int b; * "c" can be a special key (negative number) in which case 3 or 4 is returned. * A TAB is counted as two cells: "^I" or four: "<09>". */ -int char2cells(c) -int c; +int char2cells(int c) { if (IS_SPECIAL(c)) return char2cells(K_SECOND(c)) + 2; @@ -593,8 +579,7 @@ int c; * Return number of display cells occupied by character at "*p". * A TAB is counted as two cells: "^I" or four: "<09>". */ -int ptr2cells(p) -char_u *p; +int ptr2cells(char_u *p) { /* For UTF-8 we need to look at more bytes if the first byte is >= 0x80. */ if (enc_utf8 && *p >= 0x80) @@ -607,8 +592,7 @@ char_u *p; * Return the number of character cells string "s" will take on the screen, * counting TABs as two characters: "^I". */ -int vim_strsize(s) -char_u *s; +int vim_strsize(char_u *s) { return vim_strnsize(s, (int)MAXCOL); } @@ -617,9 +601,7 @@ char_u *s; * Return the number of character cells string "s[len]" will take on the * screen, counting TABs as two characters: "^I". */ -int vim_strnsize(s, len) -char_u *s; -int len; +int vim_strnsize(char_u *s, int len) { int size = 0; @@ -655,18 +637,13 @@ int len; #if defined(FEAT_VREPLACE) || defined(FEAT_EX_EXTRA) || defined(FEAT_GUI) \ || defined(FEAT_VIRTUALEDIT) || defined(PROTO) -int chartabsize(p, col) -char_u *p; -colnr_T col; +int chartabsize(char_u *p, colnr_T col) { RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col) } #endif -static int win_chartabsize(wp, p, col) -win_T *wp; -char_u *p; -colnr_T col; +static int win_chartabsize(win_T *wp, char_u *p, colnr_T col) { RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col) } @@ -675,8 +652,7 @@ colnr_T col; * Return the number of characters the string 's' will take on the screen, * taking into account the size of a tab. */ -int linetabsize(s) -char_u *s; +int linetabsize(char_u *s) { return linetabsize_col(0, s); } @@ -684,9 +660,7 @@ char_u *s; /* * Like linetabsize(), but starting at column "startcol". */ -int linetabsize_col(startcol, s) -int startcol; -char_u *s; +int linetabsize_col(int startcol, char_u *s) { colnr_T col = startcol; @@ -698,10 +672,7 @@ char_u *s; /* * Like linetabsize(), but for a given window instead of the current one. */ -int win_linetabsize(wp, p, len) -win_T *wp; -char_u *p; -colnr_T len; +int win_linetabsize(win_T *wp, char_u *p, colnr_T len) { colnr_T col = 0; char_u *s; @@ -715,8 +686,7 @@ colnr_T len; * Return TRUE if 'c' is a normal identifier character: * Letters and characters from the 'isident' option. */ -int vim_isIDc(c) -int c; +int vim_isIDc(int c) { return c > 0 && c < 0x100 && (chartab[c] & CT_ID_CHAR); } @@ -726,15 +696,12 @@ int c; * 'iskeyword' option for current buffer. * For multi-byte characters mb_get_class() is used (builtin rules). */ -int vim_iswordc(c) -int c; +int vim_iswordc(int c) { return vim_iswordc_buf(c, curbuf); } -int vim_iswordc_buf(c, buf) -int c; -buf_T *buf; +int vim_iswordc_buf(int c, buf_T *buf) { if (c >= 0x100) { if (enc_dbcs != 0) @@ -748,17 +715,14 @@ buf_T *buf; /* * Just like vim_iswordc() but uses a pointer to the (multi-byte) character. */ -int vim_iswordp(p) -char_u *p; +int vim_iswordp(char_u *p) { if (has_mbyte && MB_BYTE2LEN(*p) > 1) return mb_get_class(p) >= 2; return GET_CHARTAB(curbuf, *p) != 0; } -int vim_iswordp_buf(p, buf) -char_u *p; -buf_T *buf; +int vim_iswordp_buf(char_u *p, buf_T *buf) { if (has_mbyte && MB_BYTE2LEN(*p) > 1) return mb_get_class(p) >= 2; @@ -769,8 +733,7 @@ buf_T *buf; * return TRUE if 'c' is a valid file-name character * Assume characters above 0x100 are valid (multi-byte). */ -int vim_isfilec(c) -int c; +int vim_isfilec(int c) { return c >= 0x100 || (c > 0 && (chartab[c] & CT_FNAME_CHAR)); } @@ -781,8 +744,7 @@ int c; * Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]") * returns false. */ -int vim_isfilec_or_wc(c) -int c; +int vim_isfilec_or_wc(int c) { char_u buf[2]; @@ -796,8 +758,7 @@ int c; * Assume characters above 0x100 are printable (multi-byte), except for * Unicode. */ -int vim_isprintc(c) -int c; +int vim_isprintc(int c) { if (enc_utf8 && c >= 0x100) return utf_printable(c); @@ -808,8 +769,7 @@ int c; * Strict version of vim_isprintc(c), don't return TRUE if "c" is the head * byte of a double-byte character. */ -int vim_isprintc_strict(c) -int c; +int vim_isprintc_strict(int c) { if (enc_dbcs != 0 && c < 0x100 && MB_BYTE2LEN(c) > 1) return FALSE; @@ -821,9 +781,7 @@ int c; /* * like chartabsize(), but also check for line breaks on the screen */ -int lbr_chartabsize(s, col) -unsigned char *s; -colnr_T col; +int lbr_chartabsize(unsigned char *s, colnr_T col) { if (!curwin->w_p_lbr && *p_sbr == NUL) { if (curwin->w_p_wrap) @@ -836,9 +794,7 @@ colnr_T col; /* * Call lbr_chartabsize() and advance the pointer. */ -int lbr_chartabsize_adv(s, col) -char_u **s; -colnr_T col; +int lbr_chartabsize_adv(char_u **s, colnr_T col) { int retval; @@ -854,11 +810,7 @@ colnr_T col; * string at start of line. Warning: *headp is only set if it's a non-zero * value, init to 0 before calling. */ -int win_lbr_chartabsize(wp, s, col, headp) -win_T *wp; -char_u *s; -colnr_T col; -int *headp UNUSED; +int win_lbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) { int c; int size; @@ -967,11 +919,7 @@ int *headp UNUSED; * 'wrap' is on. This means we need to check for a double-byte character that * doesn't fit at the end of the screen line. */ -static int win_nolbr_chartabsize(wp, s, col, headp) -win_T *wp; -char_u *s; -colnr_T col; -int *headp; +static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) { int n; @@ -994,9 +942,7 @@ int *headp; * Return TRUE if virtual column "vcol" is in the rightmost column of window * "wp". */ -int in_win_border(wp, vcol) -win_T *wp; -colnr_T vcol; +int in_win_border(win_T *wp, colnr_T vcol) { int width1; /* width of first line (after line number) */ int width2; /* width of further lines */ @@ -1022,12 +968,7 @@ colnr_T vcol; * * This is used very often, keep it fast! */ -void getvcol(wp, pos, start, cursor, end) -win_T *wp; -pos_T *pos; -colnr_T *start; -colnr_T *cursor; -colnr_T *end; +void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) { colnr_T vcol; char_u *ptr; /* points to current char */ @@ -1129,8 +1070,7 @@ colnr_T *end; /* * Get virtual cursor column in the current window, pretending 'list' is off. */ -colnr_T getvcol_nolist(posp) -pos_T *posp; +colnr_T getvcol_nolist(pos_T *posp) { int list_save = curwin->w_p_list; colnr_T vcol; @@ -1144,12 +1084,7 @@ pos_T *posp; /* * Get virtual column in virtual mode. */ -void getvvcol(wp, pos, start, cursor, end) -win_T *wp; -pos_T *pos; -colnr_T *start; -colnr_T *cursor; -colnr_T *end; +void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) { colnr_T col; colnr_T coladd; @@ -1190,10 +1125,7 @@ colnr_T *end; * Get the leftmost and rightmost virtual column of pos1 and pos2. * Used for Visual block mode. */ -void getvcols(wp, pos1, pos2, left, right) -win_T *wp; -pos_T *pos1, *pos2; -colnr_T *left, *right; +void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right) { colnr_T from1, from2, to1, to2; @@ -1220,8 +1152,7 @@ colnr_T *left, *right; /* * skipwhite: skip over ' ' and '\t'. */ -char_u * skipwhite(q) -char_u *q; +char_u *skipwhite(char_u *q) { char_u *p = q; @@ -1233,8 +1164,7 @@ char_u *q; /* * skip over digits */ -char_u * skipdigits(q) -char_u *q; +char_u *skipdigits(char_u *q) { char_u *p = q; @@ -1246,8 +1176,7 @@ char_u *q; /* * skip over digits and hex characters */ -char_u * skiphex(q) -char_u *q; +char_u *skiphex(char_u *q) { char_u *p = q; @@ -1259,8 +1188,7 @@ char_u *q; /* * skip to digit (or NUL after the string) */ -char_u * skiptodigit(q) -char_u *q; +char_u *skiptodigit(char_u *q) { char_u *p = q; @@ -1272,8 +1200,7 @@ char_u *q; /* * skip to hex character (or NUL after the string) */ -char_u * skiptohex(q) -char_u *q; +char_u *skiptohex(char_u *q) { char_u *p = q; @@ -1288,8 +1215,7 @@ char_u *q; * superscript 1 to be a digit. * Use the VIM_ISDIGIT() macro for simple arguments. */ -int vim_isdigit(c) -int c; +int vim_isdigit(int c) { return c >= '0' && c <= '9'; } @@ -1299,8 +1225,7 @@ int c; * We don't use isxdigit() here, because on some systems it also considers * superscript 1 to be a digit. */ -int vim_isxdigit(c) -int c; +int vim_isxdigit(int c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') @@ -1323,8 +1248,7 @@ static char_u latin1upper[257] = static char_u latin1lower[257] = " !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xd7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; -int vim_islower(c) -int c; +int vim_islower(int c) { if (c <= '@') return FALSE; @@ -1345,8 +1269,7 @@ int c; return islower(c); } -int vim_isupper(c) -int c; +int vim_isupper(int c) { if (c <= '@') return FALSE; @@ -1367,8 +1290,7 @@ int c; return isupper(c); } -int vim_toupper(c) -int c; +int vim_toupper(int c) { if (c <= '@') return c; @@ -1389,8 +1311,7 @@ int c; return TOUPPER_LOC(c); } -int vim_tolower(c) -int c; +int vim_tolower(int c) { if (c <= '@') return c; @@ -1414,8 +1335,7 @@ int c; /* * skiptowhite: skip over text until ' ' or '\t' or NUL. */ -char_u * skiptowhite(p) -char_u *p; +char_u *skiptowhite(char_u *p) { while (*p != ' ' && *p != '\t' && *p != NUL) ++p; @@ -1427,8 +1347,7 @@ char_u *p; /* * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars */ -char_u * skiptowhite_esc(p) -char_u *p; +char_u *skiptowhite_esc(char_u *p) { while (*p != ' ' && *p != '\t' && *p != NUL) { if ((*p == '\\' || *p == Ctrl_V) && *(p + 1) != NUL) @@ -1443,8 +1362,7 @@ char_u *p; * Getdigits: Get a number from a string and skip over it. * Note: the argument is a pointer to a char_u pointer! */ -long getdigits(pp) -char_u **pp; +long getdigits(char_u **pp) { char_u *p; long retval; @@ -1461,8 +1379,7 @@ char_u **pp; /* * Return TRUE if "lbuf" is empty or only contains blanks. */ -int vim_isblankline(lbuf) -char_u *lbuf; +int vim_isblankline(char_u *lbuf) { char_u *p; @@ -1486,15 +1403,17 @@ char_u *lbuf; * If "dohex" is non-zero recognize hex numbers, when > 1 always assume * hex number. */ -void vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr) -char_u *start; -int *hexp; /* return: type of number 0 = decimal, 'x' +void +vim_str2nr ( + char_u *start, + int *hexp, /* return: type of number 0 = decimal, 'x' or 'X' is hex, '0' = octal */ -int *len; /* return: detected length of number */ -int dooct; /* recognize octal number */ -int dohex; /* recognize hex number */ -long *nptr; /* return: signed result */ -unsigned long *unptr; /* return: unsigned result */ + int *len, /* return: detected length of number */ + int dooct, /* recognize octal number */ + int dohex, /* recognize hex number */ + long *nptr, /* return: signed result */ + unsigned long *unptr /* return: unsigned result */ +) { char_u *ptr = start; int hex = 0; /* default is decimal */ @@ -1569,8 +1488,7 @@ unsigned long *unptr; /* return: unsigned result */ * Return the value of a single hex character. * Only valid when the argument is '0' - '9', 'A' - 'F' or 'a' - 'f'. */ -int hex2nr(c) -int c; +int hex2nr(int c) { if (c >= 'a' && c <= 'f') return c - 'a' + 10; @@ -1585,8 +1503,7 @@ int c; * Convert two hex characters to a byte. * Return -1 if one of the characters is not hex. */ -int hexhex2nr(p) -char_u *p; +int hexhex2nr(char_u *p) { if (!vim_isxdigit(p[0]) || !vim_isxdigit(p[1])) return -1; @@ -1607,8 +1524,7 @@ char_u *p; * character, assume that all multi-byte characters are valid file name * characters. */ -int rem_backslash(str) -char_u *str; +int rem_backslash(char_u *str) { #ifdef BACKSLASH_IN_FILENAME return str[0] == '\\' @@ -1628,8 +1544,7 @@ char_u *str; * For MS-DOS we only do this if the character after the backslash * is not a normal file character. */ -void backslash_halve(p) -char_u *p; +void backslash_halve(char_u *p) { for (; *p; ++p) if (rem_backslash(p)) @@ -1639,8 +1554,7 @@ char_u *p; /* * backslash_halve() plus save the result in allocated memory. */ -char_u * backslash_halve_save(p) -char_u *p; +char_u *backslash_halve_save(char_u *p) { char_u *res; diff --git a/src/diff.c b/src/diff.c index ad31128575..61c91f248d 100644 --- a/src/diff.c +++ b/src/diff.c @@ -55,8 +55,7 @@ static diff_T *diff_alloc_new __ARGS((tabpage_T *tp, diff_T *dprev, diff_T *dp)) /* * Called when deleting or unloading a buffer: No longer make a diff with it. */ -void diff_buf_delete(buf) -buf_T *buf; +void diff_buf_delete(buf_T *buf) { int i; tabpage_T *tp; @@ -76,8 +75,7 @@ buf_T *buf; * Check if the current buffer should be added to or removed from the list of * diff buffers. */ -void diff_buf_adjust(win) -win_T *win; +void diff_buf_adjust(win_T *win) { win_T *wp; int i; @@ -108,8 +106,7 @@ win_T *win; * This must be done before any autocmd, because a command may use info * about the screen contents. */ -void diff_buf_add(buf) -buf_T *buf; +void diff_buf_add(buf_T *buf) { int i; @@ -131,8 +128,7 @@ buf_T *buf; * Find buffer "buf" in the list of diff buffers for the current tab page. * Return its index or DB_COUNT if not found. */ -static int diff_buf_idx(buf) -buf_T *buf; +static int diff_buf_idx(buf_T *buf) { int idx; @@ -146,9 +142,7 @@ buf_T *buf; * Find buffer "buf" in the list of diff buffers for tab page "tp". * Return its index or DB_COUNT if not found. */ -static int diff_buf_idx_tp(buf, tp) -buf_T *buf; -tabpage_T *tp; +static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp) { int idx; @@ -162,8 +156,7 @@ tabpage_T *tp; * Mark the diff info involving buffer "buf" as invalid, it will be updated * when info is requested. */ -void diff_invalidate(buf) -buf_T *buf; +void diff_invalidate(buf_T *buf) { tabpage_T *tp; int i; @@ -181,11 +174,7 @@ buf_T *buf; /* * Called by mark_adjust(): update line numbers in "curbuf". */ -void diff_mark_adjust(line1, line2, amount, amount_after) -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) { int idx; tabpage_T *tp; @@ -205,13 +194,7 @@ long amount_after; * new change block and update the line numbers in following blocks. * When inserting/deleting lines in existing change blocks, update them. */ -static void diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after) -tabpage_T *tp; -int idx; -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount, long amount_after) { diff_T *dp; diff_T *dprev; @@ -417,10 +400,7 @@ long amount_after; /* * Allocate a new diff block and link it between "dprev" and "dp". */ -static diff_T * diff_alloc_new(tp, dprev, dp) -tabpage_T *tp; -diff_T *dprev; -diff_T *dp; +static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp) { diff_T *dnew; @@ -441,9 +421,7 @@ diff_T *dp; * This may result in a change where all buffers have zero lines, the caller * must take care of removing it. */ -static void diff_check_unchanged(tp, dp) -tabpage_T *tp; -diff_T *dp; +static void diff_check_unchanged(tabpage_T *tp, diff_T *dp) { int i_org; int i_new; @@ -512,9 +490,7 @@ diff_T *dp; * Check if a diff block doesn't contain invalid line numbers. * This can happen when the diff program returns invalid results. */ -static int diff_check_sanity(tp, dp) -tabpage_T *tp; -diff_T *dp; +static int diff_check_sanity(tabpage_T *tp, diff_T *dp) { int i; @@ -529,8 +505,10 @@ diff_T *dp; /* * Mark all diff buffers in the current tab page for redraw. */ -static void diff_redraw(dofold) -int dofold; /* also recompute the folds */ +static void +diff_redraw ( + int dofold /* also recompute the folds */ +) { win_T *wp; int n; @@ -557,9 +535,7 @@ int dofold; /* also recompute the folds */ * Always use 'fileformat' set to "unix". * Return FAIL for failure */ -static int diff_write(buf, fname) -buf_T *buf; -char_u *fname; +static int diff_write(buf_T *buf, char_u *fname) { int r; char_u *save_ff; @@ -579,8 +555,10 @@ char_u *fname; * The buffers are written to a file, also for unmodified buffers (the file * could have been produced by autocommands, e.g. the netrw plugin). */ -void ex_diffupdate(eap) -exarg_T *eap UNUSED; /* can be NULL */ +void +ex_diffupdate ( + exarg_T *eap /* can be NULL */ +) { buf_T *buf; int idx_orig; @@ -726,10 +704,7 @@ theend: /* * Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff". */ -static void diff_file(tmp_orig, tmp_new, tmp_diff) -char_u *tmp_orig; -char_u *tmp_new; -char_u *tmp_diff; +static void diff_file(char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff) { char_u *cmd; size_t len; @@ -769,8 +744,7 @@ char_u *tmp_diff; * The buffer is written to a file, also for unmodified buffers (the file * could have been produced by autocommands, e.g. the netrw plugin). */ -void ex_diffpatch(eap) -exarg_T *eap; +void ex_diffpatch(exarg_T *eap) { char_u *tmp_orig; /* name of original temp file */ char_u *tmp_new; /* name of patched temp file */ @@ -925,8 +899,7 @@ theend: /* * Split the window and edit another file, setting options to show the diffs. */ -void ex_diffsplit(eap) -exarg_T *eap; +void ex_diffsplit(exarg_T *eap) { win_T *old_curwin = curwin; @@ -950,8 +923,7 @@ exarg_T *eap; /* * Set options to show diffs for the current window. */ -void ex_diffthis(eap) -exarg_T *eap UNUSED; +void ex_diffthis(exarg_T *eap) { /* Set 'diff', 'scrollbind' on and 'wrap' off. */ diff_win_options(curwin, TRUE); @@ -960,9 +932,11 @@ exarg_T *eap UNUSED; /* * Set options in window "wp" for diff mode. */ -void diff_win_options(wp, addbuf) -win_T *wp; -int addbuf; /* Add buffer to diff. */ +void +diff_win_options ( + win_T *wp, + int addbuf /* Add buffer to diff. */ +) { win_T *old_curwin = curwin; @@ -1016,8 +990,7 @@ int addbuf; /* Add buffer to diff. */ * Set options not to show diffs. For the current window or all windows. * Only in the current tab page. */ -void ex_diffoff(eap) -exarg_T *eap; +void ex_diffoff(exarg_T *eap) { win_T *wp; win_T *old_curwin = curwin; @@ -1079,10 +1052,12 @@ exarg_T *eap; /* * Read the diff output and add each entry to the diff list. */ -static void diff_read(idx_orig, idx_new, fname) -int idx_orig; /* idx of original file */ -int idx_new; /* idx of new file */ -char_u *fname; /* name of diff output file */ +static void +diff_read ( + int idx_orig, /* idx of original file */ + int idx_new, /* idx of new file */ + char_u *fname /* name of diff output file */ +) { FILE *fd; diff_T *dprev = NULL; @@ -1251,11 +1226,7 @@ done: /* * Copy an entry at "dp" from "idx_orig" to "idx_new". */ -static void diff_copy_entry(dprev, dp, idx_orig, idx_new) -diff_T *dprev; -diff_T *dp; -int idx_orig; -int idx_new; +static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig, int idx_new) { long off; @@ -1271,8 +1242,7 @@ int idx_new; /* * Clear the list of diffblocks for tab page "tp". */ -void diff_clear(tp) -tabpage_T *tp; +void diff_clear(tabpage_T *tp) { diff_T *p, *next_p; @@ -1292,9 +1262,7 @@ tabpage_T *tp; * when 'diffopt' doesn't contain "filler"). * This should only be used for windows where 'diff' is set. */ -int diff_check(wp, lnum) -win_T *wp; -linenr_T lnum; +int diff_check(win_T *wp, linenr_T lnum) { int idx; /* index in tp_diffbuf[] for this buffer */ diff_T *dp; @@ -1379,10 +1347,7 @@ linenr_T lnum; /* * Compare two entries in diff "*dp" and return TRUE if they are equal. */ -static int diff_equal_entry(dp, idx1, idx2) -diff_T *dp; -int idx1; -int idx2; +static int diff_equal_entry(diff_T *dp, int idx1, int idx2) { int i; char_u *line; @@ -1410,9 +1375,7 @@ int idx2; * Compare strings "s1" and "s2" according to 'diffopt'. * Return non-zero when they are different. */ -static int diff_cmp(s1, s2) -char_u *s1; -char_u *s2; +static int diff_cmp(char_u *s1, char_u *s2) { char_u *p1, *p2; int l; @@ -1463,9 +1426,7 @@ char_u *s2; /* * Return the number of filler lines above "lnum". */ -int diff_check_fill(wp, lnum) -win_T *wp; -linenr_T lnum; +int diff_check_fill(win_T *wp, linenr_T lnum) { int n; @@ -1482,9 +1443,7 @@ linenr_T lnum; * Set the topline of "towin" to match the position in "fromwin", so that they * show the same diff'ed lines. */ -void diff_set_topline(fromwin, towin) -win_T *fromwin; -win_T *towin; +void diff_set_topline(win_T *fromwin, win_T *towin) { buf_T *frombuf = fromwin->w_buffer; linenr_T lnum = fromwin->w_topline; @@ -1586,7 +1545,7 @@ win_T *towin; /* * This is called when 'diffopt' is changed. */ -int diffopt_changed() { +int diffopt_changed(void) { char_u *p; int diff_context_new = 6; int diff_flags_new = 0; @@ -1648,7 +1607,7 @@ int diffopt_changed() { /* * Return TRUE if 'diffopt' contains "horizontal". */ -int diffopt_horizontal() { +int diffopt_horizontal(void) { return (diff_flags & DIFF_HORIZONTAL) != 0; } @@ -1656,11 +1615,13 @@ int diffopt_horizontal() { * Find the difference within a changed line. * Returns TRUE if the line was added, no other buffer has it. */ -int diff_find_change(wp, lnum, startp, endp) -win_T *wp; -linenr_T lnum; -int *startp; /* first char of the change */ -int *endp; /* last char of the change */ +int +diff_find_change ( + win_T *wp, + linenr_T lnum, + int *startp, /* first char of the change */ + int *endp /* last char of the change */ +) { char_u *line_org; char_u *line_new; @@ -1763,9 +1724,7 @@ int *endp; /* last char of the change */ * be in a fold. * Return FALSE if there are no diff blocks at all in this window. */ -int diff_infold(wp, lnum) -win_T *wp; -linenr_T lnum; +int diff_infold(win_T *wp, linenr_T lnum) { int i; int idx = -1; @@ -1808,8 +1767,7 @@ linenr_T lnum; /* * "dp" and "do" commands. */ -void nv_diffgetput(put) -int put; +void nv_diffgetput(int put) { exarg_T ea; @@ -1828,8 +1786,7 @@ int put; * ":diffget" * ":diffput" */ -void ex_diffgetput(eap) -exarg_T *eap; +void ex_diffgetput(exarg_T *eap) { linenr_T lnum; int count; @@ -2107,9 +2064,7 @@ exarg_T *eap; * Skip buffer with index "skip_idx". * When there are no diffs, all folds are removed. */ -static void diff_fold_update(dp, skip_idx) -diff_T *dp; -int skip_idx; +static void diff_fold_update(diff_T *dp, int skip_idx) { int i; win_T *wp; @@ -2124,8 +2079,7 @@ int skip_idx; /* * Return TRUE if buffer "buf" is in diff-mode. */ -int diff_mode_buf(buf) -buf_T *buf; +int diff_mode_buf(buf_T *buf) { tabpage_T *tp; @@ -2139,9 +2093,7 @@ buf_T *buf; * Move "count" times in direction "dir" to the next diff block. * Return FAIL if there isn't such a diff block. */ -int diff_move_to(dir, count) -int dir; -long count; +int diff_move_to(int dir, long count) { int idx; linenr_T lnum = curwin->w_cursor.lnum; @@ -2190,11 +2142,7 @@ long count; return OK; } -linenr_T diff_get_corresponding_line(buf1, lnum1, buf2, lnum3) -buf_T *buf1; -linenr_T lnum1; -buf_T *buf2; -linenr_T lnum3; +linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1, buf_T *buf2, linenr_T lnum3) { int idx1; int idx2; @@ -2257,9 +2205,7 @@ linenr_T lnum3; * For line "lnum" in the current window find the equivalent lnum in window * "wp", compensating for inserted/deleted lines. */ -linenr_T diff_lnum_win(lnum, wp) -linenr_T lnum; -win_T *wp; +linenr_T diff_lnum_win(linenr_T lnum, win_T *wp) { diff_T *dp; int idx; diff --git a/src/digraph.c b/src/digraph.c index 4584973526..4a1e1e4d04 100644 --- a/src/digraph.c +++ b/src/digraph.c @@ -1623,8 +1623,7 @@ static digr_T digraphdefault[] = /* * handle digraphs after typing a character */ -int do_digraph(c) -int c; +int do_digraph(int c) { static int backspaced; /* character before K_BS */ static int lastchar; /* last typed character */ @@ -1647,8 +1646,10 @@ int c; * mode. * Returns composed character, or NUL when ESC was used. */ -int get_digraph(cmdline) -int cmdline; /* TRUE when called from the cmdline */ +int +get_digraph ( + int cmdline /* TRUE when called from the cmdline */ +) { int c, cc; @@ -1683,10 +1684,7 @@ int cmdline; /* TRUE when called from the cmdline */ * If no match, return "char2". * If "meta_char" is TRUE and "char1" is a space, return "char2" | 0x80. */ -static int getexactdigraph(char1, char2, meta_char) -int char1; -int char2; -int meta_char; +static int getexactdigraph(int char1, int char2, int meta_char) { int i; int retval = 0; @@ -1759,10 +1757,7 @@ int meta_char; * Get digraph. * Allow for both char1-char2 and char2-char1 */ -int getdigraph(char1, char2, meta_char) -int char1; -int char2; -int meta_char; +int getdigraph(int char1, int char2, int meta_char) { int retval; @@ -1777,8 +1772,7 @@ int meta_char; * Add the digraphs in the argument to the digraph table. * format: {c1}{c2} char {c1}{c2} char ... */ -void putdigraph(str) -char_u *str; +void putdigraph(char_u *str) { int char1, char2, n; int i; @@ -1828,7 +1822,7 @@ char_u *str; } } -void listdigraphs() { +void listdigraphs(void) { int i; digr_T *dp; @@ -1867,8 +1861,7 @@ void listdigraphs() { wrong, in which case we messed up ScreenLines */ } -static void printdigraph(dp) -digr_T *dp; +static void printdigraph(digr_T *dp) { char_u buf[30]; char_u *p; @@ -1925,7 +1918,7 @@ static void keymap_unload __ARGS((void)); * used when setting the option, not later when the value has already been * checked. */ -char_u * keymap_init() { +char_u *keymap_init(void) { curbuf->b_kmap_state &= ~KEYMAP_INIT; if (*curbuf->b_p_keymap == NUL) { @@ -1967,8 +1960,7 @@ char_u * keymap_init() { /* * ":loadkeymap" command: load the following lines as the keymap. */ -void ex_loadkeymap(eap) -exarg_T *eap; +void ex_loadkeymap(exarg_T *eap) { char_u *line; char_u *p; @@ -2044,7 +2036,7 @@ exarg_T *eap; /* * Stop using 'keymap'. */ -static void keymap_unload() { +static void keymap_unload(void) { char_u buf[KMAP_MAXLEN + 10]; int i; char_u *save_cpo = p_cpo; diff --git a/src/edit.c b/src/edit.c index 4d245fbfaf..eec47b3637 100644 --- a/src/edit.c +++ b/src/edit.c @@ -284,10 +284,12 @@ static int did_add_space = FALSE; /* auto_format() added an extra space * * Return TRUE if a CTRL-O command caused the return (insert mode pending). */ -int edit(cmdchar, startln, count) -int cmdchar; -int startln; /* if set, insert at start of line */ -long count; +int +edit ( + int cmdchar, + int startln, /* if set, insert at start of line */ + long count +) { int c = 0; char_u *ptr; @@ -1264,8 +1266,10 @@ force_cindent: * Only redraw when there are no characters available. This speeds up * inserting sequences of characters (e.g., for CTRL-R). */ -static void ins_redraw(ready) -int ready UNUSED; /* not busy with something */ +static void +ins_redraw ( + int ready /* not busy with something */ +) { linenr_T conceal_old_cursor_line = 0; linenr_T conceal_new_cursor_line = 0; @@ -1333,7 +1337,7 @@ int ready UNUSED; /* not busy with something */ /* * Handle a CTRL-V or CTRL-Q typed in Insert mode. */ -static void ins_ctrl_v() { +static void ins_ctrl_v(void) { int c; int did_putchar = FALSE; @@ -1373,9 +1377,7 @@ static int pc_attr; static int pc_row; static int pc_col; -void edit_putchar(c, highlight) -int c; -int highlight; +void edit_putchar(int c, int highlight) { int attr; @@ -1418,7 +1420,7 @@ int highlight; /* * Undo the previous edit_putchar(). */ -void edit_unputchar() { +void edit_unputchar(void) { if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) { if (pc_status == PC_STATUS_RIGHT) ++curwin->w_wcol; @@ -1433,8 +1435,7 @@ void edit_unputchar() { * Called when p_dollar is set: display a '$' at the end of the changed text * Only works when cursor is in the line that changes. */ -void display_dollar(col) -colnr_T col; +void display_dollar(colnr_T col) { colnr_T save_col; @@ -1463,7 +1464,7 @@ colnr_T col; * Call this function before moving the cursor from the normal insert position * in insert mode. */ -static void undisplay_dollar() { +static void undisplay_dollar(void) { if (dollar_vcol >= 0) { dollar_vcol = -1; redrawWinline(curwin->w_cursor.lnum, FALSE); @@ -1478,12 +1479,14 @@ static void undisplay_dollar() { * type == INDENT_SET set indent to "amount" * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec). */ -void change_indent(type, amount, round, replaced, call_changed_bytes) -int type; -int amount; -int round; -int replaced; /* replaced character, put on replace stack */ -int call_changed_bytes; /* call changed_bytes() */ +void +change_indent ( + int type, + int amount, + int round, + int replaced, /* replaced character, put on replace stack */ + int call_changed_bytes /* call changed_bytes() */ +) { int vcol; int last_vcol; @@ -1701,8 +1704,7 @@ int call_changed_bytes; /* call changed_bytes() */ * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE * modes. */ -void truncate_spaces(line) -char_u *line; +void truncate_spaces(char_u *line) { int i; @@ -1722,8 +1724,7 @@ char_u *line; * Will attempt not to go before "col" even when there is a composing * character. */ -void backspace_until_column(col) -int col; +void backspace_until_column(int col) { while ((int)curwin->w_cursor.col > col) { curwin->w_cursor.col--; @@ -1740,8 +1741,7 @@ int col; * Only matters when there are composing characters. * Return TRUE when something was deleted. */ -static int del_char_after_col(limit_col) -int limit_col UNUSED; +static int del_char_after_col(int limit_col) { if (enc_utf8 && limit_col >= 0) { colnr_T ecol = curwin->w_cursor.col + 1; @@ -1768,7 +1768,7 @@ int limit_col UNUSED; /* * CTRL-X pressed in Insert mode. */ -static void ins_ctrl_x() { +static void ins_ctrl_x(void) { /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X * CTRL-V works like CTRL-N */ if (ctrl_x_mode != CTRL_X_CMDLINE) { @@ -1789,8 +1789,7 @@ static void ins_ctrl_x() { /* * Return TRUE if the 'dict' or 'tsr' option can be used. */ -static int has_compl_option(dict_opt) -int dict_opt; +static int has_compl_option(int dict_opt) { if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell @@ -1816,8 +1815,7 @@ int dict_opt; * Is the character 'c' a valid key to go to or keep us in CTRL-X mode? * This depends on the current mode. */ -int vim_is_ctrl_x_key(c) -int c; +int vim_is_ctrl_x_key(int c) { /* Always allow ^R - let it's results then be checked */ if (c == Ctrl_R) @@ -1872,8 +1870,7 @@ int c; * completed. Used to decide whether to abandon complete mode when the menu * is visible. */ -static int ins_compl_accept_char(c) -int c; +static int ins_compl_accept_char(int c) { if (ctrl_x_mode & CTRL_X_WANT_IDENT) /* When expanding an identifier only accept identifier chars. */ @@ -1905,13 +1902,7 @@ int c; * text is inferred, ie this tries to work out what case you probably wanted * the rest of the word to be in -- webb */ -int ins_compl_add_infercase(str, len, icase, fname, dir, flags) -char_u *str; -int len; -int icase; -char_u *fname; -int dir; -int flags; +int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags) { char_u *p; int i, c; @@ -2044,15 +2035,17 @@ int flags; * NOTDONE, otherwise add it to the list and return OK. If there is an error, * maybe because alloc() returns NULL, then FAIL is returned. */ -static int ins_compl_add(str, len, icase, fname, cptext, cdir, flags, adup) -char_u *str; -int len; -int icase; -char_u *fname; -char_u **cptext; /* extra text for popup menu or NULL */ -int cdir; -int flags; -int adup; /* accept duplicate match */ +static int +ins_compl_add ( + char_u *str, + int len, + int icase, + char_u *fname, + char_u **cptext, /* extra text for popup menu or NULL */ + int cdir, + int flags, + int adup /* accept duplicate match */ +) { compl_T *match; int dir = (cdir == 0 ? compl_direction : cdir); @@ -2153,10 +2146,7 @@ int adup; /* accept duplicate match */ * Return TRUE if "str[len]" matches with match->cp_str, considering * match->cp_icase. */ -static int ins_compl_equal(match, str, len) -compl_T *match; -char_u *str; -int len; +static int ins_compl_equal(compl_T *match, char_u *str, int len) { if (match->cp_icase) return STRNICMP(match->cp_str, str, (size_t)len) == 0; @@ -2166,8 +2156,7 @@ int len; /* * Reduce the longest common string for match "match". */ -static void ins_compl_longest_match(match) -compl_T *match; +static void ins_compl_longest_match(compl_T *match) { char_u *p, *s; int c1, c2; @@ -2234,10 +2223,7 @@ compl_T *match; * Add an array of matches to the list of matches. * Frees matches[]. */ -static void ins_compl_add_matches(num_matches, matches, icase) -int num_matches; -char_u **matches; -int icase; +static void ins_compl_add_matches(int num_matches, char_u **matches, int icase) { int i; int add_r = OK; @@ -2254,7 +2240,7 @@ int icase; /* Make the completion list cyclic. * Return the number of matches (excluding the original). */ -static int ins_compl_make_cyclic() { +static int ins_compl_make_cyclic(void) { compl_T *match; int count = 0; @@ -2279,9 +2265,7 @@ static int ins_compl_make_cyclic() { * "startcol" is where the matched text starts (1 is first column). * "list" is the list of matches. */ -void set_completion(startcol, list) -colnr_T startcol; -list_T *list; +void set_completion(colnr_T startcol, list_T *list) { /* If already doing completions stop it. */ if (ctrl_x_mode != 0) @@ -2325,7 +2309,7 @@ static int compl_match_arraysize; /* * Update the screen and when there is any scrolling remove the popup menu. */ -static void ins_compl_upd_pum() { +static void ins_compl_upd_pum(void) { int h; if (compl_match_array != NULL) { @@ -2339,7 +2323,7 @@ static void ins_compl_upd_pum() { /* * Remove any popup menu. */ -static void ins_compl_del_pum() { +static void ins_compl_del_pum(void) { if (compl_match_array != NULL) { pum_undisplay(); vim_free(compl_match_array); @@ -2350,7 +2334,7 @@ static void ins_compl_del_pum() { /* * Return TRUE if the popup menu should be displayed. */ -static int pum_wanted() { +static int pum_wanted(void) { /* 'completeopt' must contain "menu" or "menuone" */ if (vim_strchr(p_cot, 'm') == NULL) return FALSE; @@ -2366,7 +2350,7 @@ static int pum_wanted() { * Return TRUE if there are two or more matches to be shown in the popup menu. * One if 'completopt' contains "menuone". */ -static int pum_enough_matches() { +static int pum_enough_matches(void) { compl_T *compl; int i; @@ -2390,7 +2374,7 @@ static int pum_enough_matches() { * Show the popup menu for the list of matches. * Also adjusts "compl_shown_match" to an entry that is actually displayed. */ -void ins_compl_show_pum() { +void ins_compl_show_pum(void) { compl_T *compl; compl_T *shown_compl = NULL; int did_find_shown_match = FALSE; @@ -2516,11 +2500,13 @@ void ins_compl_show_pum() { * Add any identifiers that match the given pattern in the list of dictionary * files "dict_start" to the list of completions. */ -static void ins_compl_dictionaries(dict_start, pat, flags, thesaurus) -char_u *dict_start; -char_u *pat; -int flags; /* DICT_FIRST and/or DICT_EXACT */ -int thesaurus; /* Thesaurus completion */ +static void +ins_compl_dictionaries ( + char_u *dict_start, + char_u *pat, + int flags, /* DICT_FIRST and/or DICT_EXACT */ + int thesaurus /* Thesaurus completion */ +) { char_u *dict = dict_start; char_u *ptr; @@ -2619,14 +2605,7 @@ theend: vim_free(buf); } -static void ins_compl_files(count, files, thesaurus, flags, regmatch, buf, dir) -int count; -char_u **files; -int thesaurus; -int flags; -regmatch_T *regmatch; -char_u *buf; -int *dir; +static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir) { char_u *ptr; int i; @@ -2717,8 +2696,7 @@ int *dir; * Find the start of the next word. * Returns a pointer to the first char of the word. Also stops at a NUL. */ -char_u * find_word_start(ptr) -char_u *ptr; +char_u *find_word_start(char_u *ptr) { if (has_mbyte) while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1) @@ -2733,8 +2711,7 @@ char_u *ptr; * Find the end of the word. Assumes it starts inside a word. * Returns a pointer to just after the word. */ -char_u * find_word_end(ptr) -char_u *ptr; +char_u *find_word_end(char_u *ptr) { int start_class; @@ -2756,8 +2733,7 @@ char_u *ptr; * Find the end of the line, omitting CR and NL at the end. * Returns a pointer to just after the line. */ -static char_u * find_line_end(ptr) -char_u *ptr; +static char_u *find_line_end(char_u *ptr) { char_u *s; @@ -2770,7 +2746,7 @@ char_u *ptr; /* * Free the list of completions */ -static void ins_compl_free() { +static void ins_compl_free(void) { compl_T *match; int i; @@ -2801,7 +2777,7 @@ static void ins_compl_free() { compl_shown_match = NULL; } -static void ins_compl_clear() { +static void ins_compl_clear(void) { compl_cont_status = 0; compl_started = FALSE; compl_matches = 0; @@ -2818,7 +2794,7 @@ static void ins_compl_clear() { /* * Return TRUE when Insert completion is active. */ -int ins_compl_active() { +int ins_compl_active(void) { return compl_started; } @@ -2828,7 +2804,7 @@ int ins_compl_active() { * Returns the character to be used, NUL if the work is done and another char * to be got from the user. */ -static int ins_compl_bs() { +static int ins_compl_bs(void) { char_u *line; char_u *p; @@ -2865,7 +2841,7 @@ static int ins_compl_bs() { * Return TRUE when we need to find matches again, ins_compl_restart() is to * be called. */ -static int ins_compl_need_restart() { +static int ins_compl_need_restart(void) { /* Return TRUE if we didn't complete finding matches or when the * 'completefunc' returned "always" in the "refresh" dictionary item. */ return compl_was_interrupted @@ -2878,7 +2854,7 @@ static int ins_compl_need_restart() { * Show the popup menu with a different set of matches. * May also search for matches again if the previous search was interrupted. */ -static void ins_compl_new_leader() { +static void ins_compl_new_leader(void) { ins_compl_del_pum(); ins_compl_delete(); ins_bytes(compl_leader + ins_compl_len()); @@ -2914,7 +2890,7 @@ static void ins_compl_new_leader() { * Return the length of the completion, from the completion start column to * the cursor column. Making sure it never goes below zero. */ -static int ins_compl_len() { +static int ins_compl_len(void) { int off = (int)curwin->w_cursor.col - (int)compl_col; if (off < 0) @@ -2926,8 +2902,7 @@ static int ins_compl_len() { * Append one character to the match leader. May reduce the number of * matches. */ -static void ins_compl_addleader(c) -int c; +static void ins_compl_addleader(int c) { int cc; @@ -2965,7 +2940,7 @@ int c; * Setup for finding completions again without leaving CTRL-X mode. Used when * BS or a key was typed while still searching for matches. */ -static void ins_compl_restart() { +static void ins_compl_restart(void) { ins_compl_free(); compl_started = FALSE; compl_matches = 0; @@ -2976,8 +2951,7 @@ static void ins_compl_restart() { /* * Set the first match, the original text. */ -static void ins_compl_set_original_text(str) -char_u *str; +static void ins_compl_set_original_text(char_u *str) { char_u *p; @@ -2995,7 +2969,7 @@ char_u *str; * Append one character to the match leader. May reduce the number of * matches. */ -static void ins_compl_addfrommatch() { +static void ins_compl_addfrommatch(void) { char_u *p; int len = (int)curwin->w_cursor.col - (int)compl_col; int c; @@ -3031,8 +3005,7 @@ static void ins_compl_addfrommatch() { * Called just after typing a character in Insert mode. * Returns TRUE when the character is not to be inserted; */ -static int ins_compl_prep(c) -int c; +static int ins_compl_prep(int c) { char_u *ptr; int want_cindent; @@ -3273,8 +3246,7 @@ int c; * text. This inserts backspaces and appends the changed text. * "ptr" is the known leader text or NUL. */ -static void ins_compl_fixRedoBufForLeader(ptr_arg) -char_u *ptr_arg; +static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg) { int len; char_u *p; @@ -3308,9 +3280,7 @@ char_u *ptr_arg; * * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo */ -static buf_T * ins_compl_next_buf(buf, flag) -buf_T *buf; -int flag; +static buf_T *ins_compl_next_buf(buf_T *buf, int flag) { static win_T *wp; @@ -3341,9 +3311,11 @@ static void expand_by_function __ARGS((int type, char_u *base)); * Execute user defined complete function 'completefunc' or 'omnifunc', and * get matches in "matches". */ -static void expand_by_function(type, base) -int type; /* CTRL_X_OMNI or CTRL_X_FUNCTION */ -char_u *base; +static void +expand_by_function ( + int type, /* CTRL_X_OMNI or CTRL_X_FUNCTION */ + char_u *base +) { list_T *matchlist = NULL; dict_T *matchdict = NULL; @@ -3408,8 +3380,7 @@ theend: /* * Add completions from a list. */ -static void ins_compl_add_list(list) -list_T *list; +static void ins_compl_add_list(list_T *list) { listitem_T *li; int dir = compl_direction; @@ -3427,8 +3398,7 @@ list_T *list; /* * Add completions from a dict. */ -static void ins_compl_add_dict(dict) -dict_T *dict; +static void ins_compl_add_dict(dict_T *dict) { dictitem_T *di_refresh; dictitem_T *di_words; @@ -3455,9 +3425,7 @@ dict_T *dict; * NOTDONE, otherwise add it to the list and return OK. If there is an error, * maybe because alloc() returns NULL, then FAIL is returned. */ -int ins_compl_add_tv(tv, dir) -typval_T *tv; -int dir; +int ins_compl_add_tv(typval_T *tv, int dir) { char_u *word; int icase = FALSE; @@ -3499,8 +3467,7 @@ int dir; * This may return before finding all the matches. * Return the total number of matches or -1 if still unknown -- Acevedo */ -static int ins_compl_get_exp(ini) -pos_T *ini; +static int ins_compl_get_exp(pos_T *ini) { static pos_T first_match_pos; static pos_T last_match_pos; @@ -3877,7 +3844,7 @@ pos_T *ini; } /* Delete the old text being completed. */ -static void ins_compl_delete() { +static void ins_compl_delete(void) { int i; /* @@ -3890,7 +3857,7 @@ static void ins_compl_delete() { } /* Insert the new text being completed. */ -static void ins_compl_insert() { +static void ins_compl_insert(void) { ins_bytes(compl_shown_match->cp_str + ins_compl_len()); if (compl_shown_match->cp_flags & ORIGINAL_TEXT) compl_used_match = FALSE; @@ -3914,11 +3881,13 @@ static void ins_compl_insert() { * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn * calls this function with "allow_get_expansion" FALSE. */ -static int ins_compl_next(allow_get_expansion, count, insert_match) -int allow_get_expansion; -int count; /* repeat completion this many times; should +static int +ins_compl_next ( + int allow_get_expansion, + int count, /* repeat completion this many times; should be at least 1 */ -int insert_match; /* Insert the newly selected match */ + int insert_match /* Insert the newly selected match */ +) { int num_matches = -1; int i; @@ -4094,8 +4063,7 @@ int insert_match; /* Insert the newly selected match */ * possible. -- webb * "frequency" specifies out of how many calls we actually check. */ -void ins_compl_check_keys(frequency) -int frequency; +void ins_compl_check_keys(int frequency) { static int count = 0; @@ -4146,8 +4114,7 @@ int frequency; * Decide the direction of Insert mode complete from the key typed. * Returns BACKWARD or FORWARD. */ -static int ins_compl_key2dir(c) -int c; +static int ins_compl_key2dir(int c) { if (c == Ctrl_P || c == Ctrl_L || (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP @@ -4160,8 +4127,7 @@ int c; * Return TRUE for keys that are used for completion only when the popup menu * is visible. */ -static int ins_compl_pum_key(c) -int c; +static int ins_compl_pum_key(int c) { return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == @@ -4173,8 +4139,7 @@ int c; * Decide the number of completions to move forward. * Returns 1 for most keys, height of the popup menu for page-up/down keys. */ -static int ins_compl_key2count(c) -int c; +static int ins_compl_key2count(int c) { int h; @@ -4191,8 +4156,7 @@ int c; * Return TRUE if completion with "c" should insert the match, FALSE if only * to change the currently selected completion. */ -static int ins_compl_use_match(c) -int c; +static int ins_compl_use_match(int c) { switch (c) { case K_UP: @@ -4213,8 +4177,7 @@ int c; * Called when character "c" was typed, which has a meaning for completion. * Returns OK if completion was done, FAIL if something failed (out of mem). */ -static int ins_complete(c) -int c; +static int ins_complete(int c) { char_u *line; int startcol = 0; /* column where searched text starts */ @@ -4740,10 +4703,7 @@ int c; * a backslash) the metachars, and dest would be NUL terminated. * Returns the length (needed) of dest */ -static unsigned quote_meta(dest, src, len) -char_u *dest; -char_u *src; -int len; +static unsigned quote_meta(char_u *dest, char_u *src, int len) { unsigned m = (unsigned)len + 1; /* one extra for the NUL */ @@ -4797,7 +4757,7 @@ int len; * If one or two digits are entered, the next character is given to vungetc(). * For Unicode a character > 255 may be returned. */ -int get_literal() { +int get_literal(void) { int cc; int nc; int i; @@ -4887,10 +4847,12 @@ int get_literal() { /* * Insert character, taking care of special keys and mod_mask */ -static void insert_special(c, allow_modmask, ctrlv) -int c; -int allow_modmask; -int ctrlv; /* c was typed after CTRL-V */ +static void +insert_special ( + int c, + int allow_modmask, + int ctrlv /* c was typed after CTRL-V */ +) { char_u *p; int len; @@ -4944,10 +4906,12 @@ int ctrlv; /* c was typed after CTRL-V */ * INSCHAR_DO_COM - format comments * INSCHAR_COM_LIST - format comments with num list or 2nd line indent */ -void insertchar(c, flags, second_indent) -int c; /* character to insert or NUL */ -int flags; /* INSCHAR_FORMAT, etc. */ -int second_indent; /* indent for second line if >= 0 */ +void +insertchar ( + int c, /* character to insert or NUL */ + int flags, /* INSCHAR_FORMAT, etc. */ + int second_indent /* indent for second line if >= 0 */ +) { int textwidth; char_u *p; @@ -5145,12 +5109,14 @@ int second_indent; /* indent for second line if >= 0 */ * If the INSCHAR_COM_LIST flag is present, then the value of second_indent * will be the comment leader length sent to open_line(). */ -static void internal_format(textwidth, second_indent, flags, format_only, c) -int textwidth; -int second_indent; -int flags; -int format_only; -int c; /* character to be inserted (can be NUL) */ +static void +internal_format ( + int textwidth, + int second_indent, + int flags, + int format_only, + int c /* character to be inserted (can be NUL) */ +) { int cc; int save_char = NUL; @@ -5466,9 +5432,11 @@ int c; /* character to be inserted (can be NUL) */ * The caller must have saved the cursor line for undo, following ones will be * saved here. */ -void auto_format(trailblank, prev_line) -int trailblank; /* when TRUE also format with trailing blank */ -int prev_line; /* may start in previous line */ +void +auto_format ( + int trailblank, /* when TRUE also format with trailing blank */ + int prev_line /* may start in previous line */ +) { pos_T pos; colnr_T len; @@ -5566,8 +5534,10 @@ int prev_line; /* may start in previous line */ * delete it now. The space must be under the cursor, just after the insert * position. */ -static void check_auto_format(end_insert) -int end_insert; /* TRUE when ending Insert mode */ +static void +check_auto_format ( + int end_insert /* TRUE when ending Insert mode */ +) { int c = ' '; int cc; @@ -5599,8 +5569,10 @@ int end_insert; /* TRUE when ending Insert mode */ * if invalid value, use 0. * Set default to window width (maximum 79) for "gq" operator. */ -int comp_textwidth(ff) -int ff; /* force formatting (for "gq" command) */ +int +comp_textwidth ( + int ff /* force formatting (for "gq" command) */ +) { int textwidth; @@ -5628,8 +5600,7 @@ int ff; /* force formatting (for "gq" command) */ /* * Put a character in the redo buffer, for when just after a CTRL-V. */ -static void redo_literal(c) -int c; +static void redo_literal(int c) { char_u buf[10]; @@ -5646,8 +5617,10 @@ int c; * start_arrow() is called when an arrow key is used in insert mode. * For undo/redo it resembles hitting the key. */ -static void start_arrow(end_insert_pos) -pos_T *end_insert_pos; /* can be NULL */ +static void +start_arrow ( + pos_T *end_insert_pos /* can be NULL */ +) { if (!arrow_used) { /* something has been inserted */ AppendToRedobuff(ESC_STR); @@ -5661,7 +5634,7 @@ pos_T *end_insert_pos; /* can be NULL */ * If we skipped highlighting word at cursor, do it now. * It may be skipped again, thus reset spell_redraw_lnum first. */ -static void check_spell_redraw() { +static void check_spell_redraw(void) { if (spell_redraw_lnum != 0) { linenr_T lnum = spell_redraw_lnum; @@ -5674,7 +5647,7 @@ static void check_spell_redraw() { * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly * spelled word, if there is one. */ -static void spell_back_to_badword() { +static void spell_back_to_badword(void) { pos_T tpos = curwin->w_cursor; spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL); @@ -5687,7 +5660,7 @@ static void spell_back_to_badword() { * If an arrow key has been used, start a new insertion. * Returns FAIL if undo is impossible, shouldn't insert then. */ -int stop_arrow() { +int stop_arrow(void) { if (arrow_used) { if (u_save_cursor() == OK) { arrow_used = FALSE; @@ -5719,10 +5692,12 @@ int stop_arrow() { * "end_insert_pos" is where insert ended. It is NULL when we already jumped * to another window/buffer. */ -static void stop_insert(end_insert_pos, esc, nomove) -pos_T *end_insert_pos; -int esc; /* called by ins_esc() */ -int nomove; /* , don't move cursor */ +static void +stop_insert ( + pos_T *end_insert_pos, + int esc, /* called by ins_esc() */ + int nomove /* , don't move cursor */ +) { int cc; char_u *ptr; @@ -5836,8 +5811,7 @@ int nomove; /* , don't move cursor */ * Set the last inserted text to a single character. * Used for the replace command. */ -void set_last_insert(c) -int c; +void set_last_insert(int c) { char_u *s; @@ -5856,7 +5830,7 @@ int c; } #if defined(EXITFREE) || defined(PROTO) -void free_last_insert() { +void free_last_insert(void) { vim_free(last_insert); last_insert = NULL; vim_free(compl_orig_text); @@ -5870,9 +5844,7 @@ void free_last_insert() { * and CSI. Handle multi-byte characters. * Returns a pointer to after the added bytes. */ -char_u * add_char2buf(c, s) -int c; -char_u *s; +char_u *add_char2buf(int c, char_u *s) { char_u temp[MB_MAXBYTES + 1]; int i; @@ -5899,8 +5871,7 @@ char_u *s; * otherwise keep "curswant" column * if flags & BL_FIX don't leave the cursor on a NUL. */ -void beginline(flags) -int flags; +void beginline(int flags) { if ((flags & BL_SOL) && !p_sol) coladvance(curwin->w_curswant); @@ -5927,7 +5898,7 @@ int flags; * Return OK when successful, FAIL when we hit a line of file boundary. */ -int oneright() { +int oneright(void) { char_u *ptr; int l; @@ -5967,7 +5938,7 @@ int oneright() { return OK; } -int oneleft() { +int oneleft(void) { if (virtual_active()) { int width; int v = getviscol(); @@ -6016,9 +5987,11 @@ int oneleft() { return OK; } -int cursor_up(n, upd_topline) -long n; -int upd_topline; /* When TRUE: update topline */ +int +cursor_up ( + long n, + int upd_topline /* When TRUE: update topline */ +) { linenr_T lnum; @@ -6067,9 +6040,11 @@ int upd_topline; /* When TRUE: update topline */ /* * Cursor down a number of logical lines. */ -int cursor_down(n, upd_topline) -long n; -int upd_topline; /* When TRUE: update topline */ +int +cursor_down ( + long n, + int upd_topline /* When TRUE: update topline */ +) { linenr_T lnum; @@ -6118,10 +6093,12 @@ int upd_topline; /* When TRUE: update topline */ * Last_insert actually is a copy of the redo buffer, so we * first have to remove the command. */ -int stuff_inserted(c, count, no_esc) -int c; /* Command character to be inserted */ -long count; /* Repeat this many times */ -int no_esc; /* Don't add an ESC at the end */ +int +stuff_inserted ( + int c, /* Command character to be inserted */ + long count, /* Repeat this many times */ + int no_esc /* Don't add an ESC at the end */ +) { char_u *esc_ptr; char_u *ptr; @@ -6173,7 +6150,7 @@ int no_esc; /* Don't add an ESC at the end */ return OK; } -char_u * get_last_insert() { +char_u *get_last_insert(void) { if (last_insert == NULL) return NULL; return last_insert + last_insert_skip; @@ -6183,7 +6160,7 @@ char_u * get_last_insert() { * Get last inserted string, and remove trailing . * Returns pointer to allocated memory (must be freed) or NULL. */ -char_u * get_last_insert_save() { +char_u *get_last_insert_save(void) { char_u *s; int len; @@ -6204,8 +6181,7 @@ char_u * get_last_insert_save() { * When an abbreviation is recognized it is removed from the text and * the replacement string is inserted in typebuf.tb_buf[], followed by "c". */ -static int echeck_abbr(c) -int c; +static int echeck_abbr(int c) { /* Don't check for abbreviation in paste mode, when disabled and just * after moving around with cursor keys. */ @@ -6239,8 +6215,10 @@ static char_u *replace_stack = NULL; static long replace_stack_nr = 0; /* next entry in replace stack */ static long replace_stack_len = 0; /* max. number of entries */ -void replace_push(c) -int c; /* character that is replaced (NUL is none) */ +void +replace_push ( + int c /* character that is replaced (NUL is none) */ +) { char_u *p; @@ -6272,8 +6250,7 @@ int c; /* character that is replaced (NUL is none) */ * reverse byte order, so that the first byte is popped off first. * Return the number of bytes done (includes composing characters). */ -int replace_push_mb(p) -char_u *p; +int replace_push_mb(char_u *p) { int l = (*mb_ptr2len)(p); int j; @@ -6288,7 +6265,7 @@ char_u *p; * return -1 if stack empty * return replaced character or NUL otherwise */ -static int replace_pop() { +static int replace_pop(void) { if (replace_stack_nr == 0) return -1; return (int)replace_stack[--replace_stack_nr]; @@ -6298,8 +6275,10 @@ static int replace_pop() { * Join the top two items on the replace stack. This removes to "off"'th NUL * encountered. */ -static void replace_join(off) -int off; /* offset for which NUL to remove */ +static void +replace_join ( + int off /* offset for which NUL to remove */ +) { int i; @@ -6316,7 +6295,7 @@ int off; /* offset for which NUL to remove */ * Pop bytes from the replace stack until a NUL is found, and insert them * before the cursor. Can only be used in REPLACE or VREPLACE mode. */ -static void replace_pop_ins() { +static void replace_pop_ins(void) { int cc; int oldState = State; @@ -6332,8 +6311,7 @@ static void replace_pop_ins() { * Insert bytes popped from the replace stack. "cc" is the first byte. If it * indicates a multi-byte char, pop the other bytes too. */ -static void mb_replace_pop_ins(cc) -int cc; +static void mb_replace_pop_ins(int cc) { int n; char_u buf[MB_MAXBYTES + 1]; @@ -6378,7 +6356,7 @@ int cc; * make the replace stack empty * (called when exiting replace mode) */ -static void replace_flush() { +static void replace_flush(void) { vim_free(replace_stack); replace_stack = NULL; replace_stack_len = 0; @@ -6394,8 +6372,7 @@ static void replace_flush() { * When "limit_col" is >= 0, don't delete before this column. Matters when * using composing characters, use del_char_after_col() instead of del_char(). */ -static void replace_do_bs(limit_col) -int limit_col; +static void replace_do_bs(int limit_col) { int cc; int orig_len = 0; @@ -6456,7 +6433,7 @@ int limit_col; /* * Return TRUE if C-indenting is on. */ -static int cindent_on() { +static int cindent_on(void) { return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL ); @@ -6477,7 +6454,7 @@ int (*get_the_indent)__ARGS((void)); did_ai = TRUE; /* delete the indent if the line stays empty */ } -void fix_indent() { +void fix_indent(void) { if (p_paste) return; if (curbuf->b_p_lisp && curbuf->b_p_ai) @@ -6499,10 +6476,7 @@ void fix_indent() { * * If line_is_empty is TRUE accept keys with '0' before them. */ -int in_cinkeys(keytyped, when, line_is_empty) -int keytyped; -int when; -int line_is_empty; +int in_cinkeys(int keytyped, int when, int line_is_empty) { char_u *look; int try_match; @@ -6716,8 +6690,7 @@ int line_is_empty; /* * Map Hebrew keyboard when in hkmap mode. */ -int hkmap(c) -int c; +int hkmap(int c) { if (p_hkmapp) { /* phonetic mapping, by Ilya Dogolazky */ enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, @@ -6782,7 +6755,7 @@ int c; } } -static void ins_reg() { +static void ins_reg(void) { int need_redraw = FALSE; int regname; int literally = 0; @@ -6878,7 +6851,7 @@ static void ins_reg() { /* * CTRL-G commands in Insert mode. */ -static void ins_ctrl_g() { +static void ins_ctrl_g(void) { int c; /* Right after CTRL-X the cursor will be after the ruler. */ @@ -6921,7 +6894,7 @@ static void ins_ctrl_g() { /* * CTRL-^ in Insert mode. */ -static void ins_ctrl_hat() { +static void ins_ctrl_hat(void) { if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) { /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */ if (State & LANGMAP) { @@ -6959,10 +6932,12 @@ static void ins_ctrl_hat() { * Returns TRUE when leaving insert mode, FALSE when going to repeat the * insert. */ -static int ins_esc(count, cmdchar, nomove) -long *count; -int cmdchar; -int nomove; /* don't move cursor */ +static int +ins_esc ( + long *count, + int cmdchar, + int nomove /* don't move cursor */ +) { int temp; static int disabled_redraw = FALSE; @@ -7085,7 +7060,7 @@ int nomove; /* don't move cursor */ * Toggle language: hkmap and revins_on. * Move to end of reverse inserted text. */ -static void ins_ctrl_() { +static void ins_ctrl_(void) { if (revins_on && revins_chars && revins_scol >= 0) { while (gchar_cursor() != NUL && revins_chars--) ++curwin->w_cursor.col; @@ -7119,8 +7094,7 @@ static void ins_ctrl_() { * If 'keymodel' contains "startsel", may start selection. * Returns TRUE when a CTRL-O and other keys stuffed. */ -static int ins_start_select(c) -int c; +static int ins_start_select(int c) { if (km_startsel) switch (c) { @@ -7163,8 +7137,7 @@ int c; /* * key in Insert mode: toggle insert/replace mode. */ -static void ins_insert(replaceState) -int replaceState; +static void ins_insert(int replaceState) { if (p_fkmap && p_ri) { beep_flush(); @@ -7191,7 +7164,7 @@ int replaceState; /* * Pressed CTRL-O in Insert mode. */ -static void ins_ctrl_o() { +static void ins_ctrl_o(void) { if (State & VREPLACE_FLAG) restart_edit = 'V'; else if (State & REPLACE_FLAG) @@ -7211,9 +7184,7 @@ static void ins_ctrl_o() { * with vi. But vi only supports ^T and ^D after an * autoindent, we support it everywhere. */ -static void ins_shift(c, lastc) -int c; -int lastc; +static void ins_shift(int c, int lastc) { if (stop_arrow() == FAIL) return; @@ -7243,7 +7214,7 @@ int lastc; can_cindent = FALSE; /* no cindenting after ^D or ^T */ } -static void ins_del() { +static void ins_del(void) { int temp; if (stop_arrow() == FAIL) @@ -7269,8 +7240,7 @@ static void ins_bs_one __ARGS((colnr_T *vcolp)); /* * Delete one character for ins_bs(). */ -static void ins_bs_one(vcolp) -colnr_T *vcolp; +static void ins_bs_one(colnr_T *vcolp) { dec_cursor(); getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); @@ -7288,10 +7258,7 @@ colnr_T *vcolp; * Handle Backspace, delete-word and delete-line in Insert mode. * Return TRUE when backspace was actually used. */ -static int ins_bs(c, mode, inserted_space_p) -int c; -int mode; -int *inserted_space_p; +static int ins_bs(int c, int mode, int *inserted_space_p) { linenr_T lnum; int cc; @@ -7600,8 +7567,7 @@ int *inserted_space_p; return did_backspace; } -static void ins_mouse(c) -int c; +static void ins_mouse(int c) { pos_T tpos; win_T *old_curwin = curwin; @@ -7632,8 +7598,7 @@ int c; redraw_statuslines(); } -static void ins_mousescroll(dir) -int dir; +static void ins_mousescroll(int dir) { pos_T tpos; win_T *old_curwin = curwin; @@ -7689,7 +7654,7 @@ int dir; -static void ins_left() { +static void ins_left(void) { pos_T tpos; if ((fdo_flags & FDO_HOR) && KeyTyped) @@ -7716,8 +7681,7 @@ static void ins_left() { vim_beep(); } -static void ins_home(c) -int c; +static void ins_home(int c) { pos_T tpos; @@ -7733,8 +7697,7 @@ int c; start_arrow(&tpos); } -static void ins_end(c) -int c; +static void ins_end(int c) { pos_T tpos; @@ -7750,7 +7713,7 @@ int c; start_arrow(&tpos); } -static void ins_s_left() { +static void ins_s_left(void) { if ((fdo_flags & FDO_HOR) && KeyTyped) foldOpenCursor(); undisplay_dollar(); @@ -7762,7 +7725,7 @@ static void ins_s_left() { vim_beep(); } -static void ins_right() { +static void ins_right(void) { if ((fdo_flags & FDO_HOR) && KeyTyped) foldOpenCursor(); undisplay_dollar(); @@ -7796,7 +7759,7 @@ static void ins_right() { vim_beep(); } -static void ins_s_right() { +static void ins_s_right(void) { if ((fdo_flags & FDO_HOR) && KeyTyped) foldOpenCursor(); undisplay_dollar(); @@ -7809,8 +7772,10 @@ static void ins_s_right() { vim_beep(); } -static void ins_up(startcol) -int startcol; /* when TRUE move to Insstart.col */ +static void +ins_up ( + int startcol /* when TRUE move to Insstart.col */ +) { pos_T tpos; linenr_T old_topline = curwin->w_topline; @@ -7831,7 +7796,7 @@ int startcol; /* when TRUE move to Insstart.col */ vim_beep(); } -static void ins_pageup() { +static void ins_pageup(void) { pos_T tpos; undisplay_dollar(); @@ -7853,8 +7818,10 @@ static void ins_pageup() { vim_beep(); } -static void ins_down(startcol) -int startcol; /* when TRUE move to Insstart.col */ +static void +ins_down ( + int startcol /* when TRUE move to Insstart.col */ +) { pos_T tpos; linenr_T old_topline = curwin->w_topline; @@ -7875,7 +7842,7 @@ int startcol; /* when TRUE move to Insstart.col */ vim_beep(); } -static void ins_pagedown() { +static void ins_pagedown(void) { pos_T tpos; undisplay_dollar(); @@ -7901,7 +7868,7 @@ static void ins_pagedown() { * Handle TAB in Insert or Replace mode. * Return TRUE when the TAB needs to be inserted like a normal character. */ -static int ins_tab() { +static int ins_tab(void) { int ind; int i; int temp; @@ -8085,8 +8052,7 @@ static int ins_tab() { * Handle CR or NL in insert mode. * Return TRUE when out of memory or can't undo. */ -static int ins_eol(c) -int c; +static int ins_eol(int c) { int i; @@ -8142,7 +8108,7 @@ int c; * Returns character still to be inserted, or NUL when nothing remaining to be * done. */ -static int ins_digraph() { +static int ins_digraph(void) { int c; int cc; int did_putchar = FALSE; @@ -8215,8 +8181,7 @@ static int ins_digraph() { * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. * Returns the char to be inserted, or NUL if none found. */ -int ins_copychar(lnum) -linenr_T lnum; +int ins_copychar(linenr_T lnum) { int c; int temp; @@ -8248,8 +8213,7 @@ linenr_T lnum; /* * CTRL-Y or CTRL-E typed in Insert mode. */ -static int ins_ctrl_ey(tc) -int tc; +static int ins_ctrl_ey(int tc) { int c = tc; @@ -8287,8 +8251,7 @@ int tc; * Try to do some very smart auto-indenting. * Used when inserting a "normal" character. */ -static void ins_try_si(c) -int c; +static void ins_try_si(int c) { pos_T *pos, old_pos; char_u *ptr; @@ -8369,7 +8332,7 @@ int c; * Get the value that w_virtcol would have when 'list' is off. * Unless 'cpo' contains the 'L' flag. */ -static colnr_T get_nolist_virtcol() { +static colnr_T get_nolist_virtcol(void) { if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) return getvcol_nolist(&curwin->w_cursor); validate_virtcol(); @@ -8382,8 +8345,7 @@ static colnr_T get_nolist_virtcol() { * Return a pointer to allocated memory with the replacement string. * Return NULL to continue inserting "c". */ -static char_u * do_insert_char_pre(c) -int c; +static char_u *do_insert_char_pre(int c) { char_u *res; char_u buf[MB_MAXBYTES + 1]; diff --git a/src/eval.c b/src/eval.c index bcf9c75730..1e177e361d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -816,7 +816,7 @@ static void setwinvar __ARGS((typval_T *argvars, typval_T *rettv, int off)); /* * Initialize the global and v: variables. */ -void eval_init() { +void eval_init(void) { int i; struct vimvar *p; @@ -850,7 +850,7 @@ void eval_init() { } #if defined(EXITFREE) || defined(PROTO) -void eval_clear() { +void eval_clear(void) { int i; struct vimvar *p; @@ -899,8 +899,7 @@ void eval_clear() { /* * Return the name of the executed function. */ -char_u * func_name(cookie) -void *cookie; +char_u *func_name(void *cookie) { return ((funccall_T *)cookie)->func->uf_name; } @@ -908,8 +907,7 @@ void *cookie; /* * Return the address holding the next breakpoint line for a funccall cookie. */ -linenr_T * func_breakpoint(cookie) -void *cookie; +linenr_T *func_breakpoint(void *cookie) { return &((funccall_T *)cookie)->breakpoint; } @@ -917,8 +915,7 @@ void *cookie; /* * Return the address holding the debug tick for a funccall cookie. */ -int * func_dbg_tick(cookie) -void *cookie; +int *func_dbg_tick(void *cookie) { return &((funccall_T *)cookie)->dbg_tick; } @@ -926,8 +923,7 @@ void *cookie; /* * Return the nesting level for a funccall cookie. */ -int func_level(cookie) -void *cookie; +int func_level(void *cookie) { return ((funccall_T *)cookie)->level; } @@ -942,7 +938,7 @@ funccall_T *previous_funccal = NULL; /* * Return TRUE when a function was ended by a ":return" command. */ -int current_func_returned() { +int current_func_returned(void) { return current_funccal->returned; } @@ -950,9 +946,7 @@ int current_func_returned() { * Set an internal variable to a string value. Creates the variable if it does * not already exist. */ -void set_internal_string_var(name, value) -char_u *name; -char_u *value; +void set_internal_string_var(char_u *name, char_u *value) { char_u *val; typval_T *tvp; @@ -976,9 +970,11 @@ static char_u *redir_varname = NULL; * Start recording command output to a variable * Returns OK if successfully completed the setup. FAIL otherwise. */ -int var_redir_start(name, append) -char_u *name; -int append; /* append to an existing variable */ +int +var_redir_start ( + char_u *name, + int append /* append to an existing variable */ +) { int save_emsg; int err; @@ -1051,9 +1047,7 @@ int append; /* append to an existing variable */ * :let foo * :redir END */ -void var_redir_str(value, value_len) -char_u *value; -int value_len; +void var_redir_str(char_u *value, int value_len) { int len; @@ -1076,7 +1070,7 @@ int value_len; * Stop redirecting command output to a variable. * Frees the allocated memory. */ -void var_redir_stop() { +void var_redir_stop(void) { typval_T tv; if (redir_lval != NULL) { @@ -1105,11 +1099,7 @@ void var_redir_stop() { redir_varname = NULL; } -int eval_charconvert(enc_from, enc_to, fname_from, fname_to) -char_u *enc_from; -char_u *enc_to; -char_u *fname_from; -char_u *fname_to; +int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, char_u *fname_to) { int err = FALSE; @@ -1129,9 +1119,7 @@ char_u *fname_to; return OK; } -int eval_printexpr(fname, args) -char_u *fname; -char_u *args; +int eval_printexpr(char_u *fname, char_u *args) { int err = FALSE; @@ -1149,10 +1137,7 @@ char_u *args; return OK; } -void eval_diff(origfile, newfile, outfile) -char_u *origfile; -char_u *newfile; -char_u *outfile; +void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile) { int err = FALSE; @@ -1165,10 +1150,7 @@ char_u *outfile; set_vim_var_string(VV_FNAME_OUT, NULL, -1); } -void eval_patch(origfile, difffile, outfile) -char_u *origfile; -char_u *difffile; -char_u *outfile; +void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile) { int err; @@ -1186,11 +1168,13 @@ char_u *outfile; * Sets "error" to TRUE if there was an error. * Return TRUE or FALSE. */ -int eval_to_bool(arg, error, nextcmd, skip) -char_u *arg; -int *error; -char_u **nextcmd; -int skip; /* only parse, don't execute */ +int +eval_to_bool ( + char_u *arg, + int *error, + char_u **nextcmd, + int skip /* only parse, don't execute */ +) { typval_T tv; int retval = FALSE; @@ -1217,10 +1201,12 @@ int skip; /* only parse, don't execute */ * only parsing to "nextcmd" is done, without reporting errors. Return * pointer to allocated memory, or NULL for failure or when "skip" is TRUE. */ -char_u * eval_to_string_skip(arg, nextcmd, skip) -char_u *arg; -char_u **nextcmd; -int skip; /* only parse, don't execute */ +char_u * +eval_to_string_skip ( + char_u *arg, + char_u **nextcmd, + int skip /* only parse, don't execute */ +) { typval_T tv; char_u *retval; @@ -1243,8 +1229,7 @@ int skip; /* only parse, don't execute */ * Skip over an expression at "*pp". * Return FAIL for an error, OK otherwise. */ -int skip_expr(pp) -char_u **pp; +int skip_expr(char_u **pp) { typval_T rettv; @@ -1258,10 +1243,7 @@ char_u **pp; * a Float to a String. * Return pointer to allocated memory, or NULL for failure. */ -char_u * eval_to_string(arg, nextcmd, convert) -char_u *arg; -char_u **nextcmd; -int convert; +char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert) { typval_T tv; char_u *retval; @@ -1295,10 +1277,7 @@ int convert; * Call eval_to_string() without using current local variables and using * textlock. When "use_sandbox" is TRUE use the sandbox. */ -char_u * eval_to_string_safe(arg, nextcmd, use_sandbox) -char_u *arg; -char_u **nextcmd; -int use_sandbox; +char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox) { char_u *retval; void *save_funccalp; @@ -1320,8 +1299,7 @@ int use_sandbox; * Evaluates "expr" silently. * Returns -1 for an error. */ -int eval_to_number(expr) -char_u *expr; +int eval_to_number(char_u *expr) { typval_T rettv; int retval; @@ -1345,9 +1323,7 @@ char_u *expr; * Save the current typeval in "save_tv". * When not used yet add the variable to the v: hashtable. */ -static void prepare_vimvar(idx, save_tv) -int idx; -typval_T *save_tv; +static void prepare_vimvar(int idx, typval_T *save_tv) { *save_tv = vimvars[idx].vv_tv; if (vimvars[idx].vv_type == VAR_UNKNOWN) @@ -1358,9 +1334,7 @@ typval_T *save_tv; * Restore v: variable "idx" to typeval "save_tv". * When no longer defined, remove the variable from the v: hashtable. */ -static void restore_vimvar(idx, save_tv) -int idx; -typval_T *save_tv; +static void restore_vimvar(int idx, typval_T *save_tv) { hashitem_T *hi; @@ -1379,9 +1353,7 @@ typval_T *save_tv; * For the "expr:" part of 'spellsuggest'. * Returns NULL when there is an error. */ -list_T * eval_spell_expr(badword, expr) -char_u *badword; -char_u *expr; +list_T *eval_spell_expr(char_u *badword, char_u *expr) { typval_T save_val; typval_T rettv; @@ -1415,9 +1387,7 @@ char_u *expr; * Return -1 if anything isn't right. * Used to get the good word and score from the eval_spell_expr() result. */ -int get_spellword(list, pp) -list_T *list; -char_u **pp; +int get_spellword(list_T *list, char_u **pp) { listitem_T *li; @@ -1437,9 +1407,7 @@ char_u **pp; * Returns an allocated typval_T with the result. * Returns NULL when there is an error. */ -typval_T * eval_expr(arg, nextcmd) -char_u *arg; -char_u **nextcmd; +typval_T *eval_expr(char_u *arg, char_u **nextcmd) { typval_T *tv; @@ -1459,13 +1427,15 @@ char_u **nextcmd; * arguments are currently supported. * Returns OK or FAIL. */ -int call_vim_function(func, argc, argv, safe, str_arg_only, rettv) -char_u *func; -int argc; -char_u **argv; -int safe; /* use the sandbox */ -int str_arg_only; /* all arguments are strings */ -typval_T *rettv; +int +call_vim_function ( + char_u *func, + int argc, + char_u **argv, + int safe, /* use the sandbox */ + int str_arg_only, /* all arguments are strings */ + typval_T *rettv +) { typval_T *argvars; long n; @@ -1527,11 +1497,13 @@ typval_T *rettv; * Returns -1 when calling the function fails. * Uses argv[argc] for the function arguments. */ -long call_func_retnr(func, argc, argv, safe) -char_u *func; -int argc; -char_u **argv; -int safe; /* use the sandbox */ +long +call_func_retnr ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) { typval_T rettv; long retval; @@ -1553,11 +1525,13 @@ int safe; /* use the sandbox */ * Returns NULL when calling the function fails. * Uses argv[argc] for the function arguments. */ -void * call_func_retstr(func, argc, argv, safe) -char_u *func; -int argc; -char_u **argv; -int safe; /* use the sandbox */ +void * +call_func_retstr ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) { typval_T rettv; char_u *retval; @@ -1576,11 +1550,13 @@ int safe; /* use the sandbox */ * Uses argv[argc] for the function arguments. * Returns NULL when there is something wrong. */ -void * call_func_retlist(func, argc, argv, safe) -char_u *func; -int argc; -char_u **argv; -int safe; /* use the sandbox */ +void * +call_func_retlist ( + char_u *func, + int argc, + char_u **argv, + int safe /* use the sandbox */ +) { typval_T rettv; @@ -1601,15 +1577,14 @@ int safe; /* use the sandbox */ * Save the current function call pointer, and set it to NULL. * Used when executing autocommands and for ":source". */ -void * save_funccal() { +void *save_funccal(void) { funccall_T *fc = current_funccal; current_funccal = NULL; return (void *)fc; } -void restore_funccal(vfc) -void *vfc; +void restore_funccal(void *vfc) { funccall_T *fc = (funccall_T *)vfc; @@ -1654,9 +1629,7 @@ proftime_T *tm; /* where waittime was stored */ * Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding * it in "*cp". Doesn't give error messages. */ -int eval_foldexpr(arg, cp) -char_u *arg; -int *cp; +int eval_foldexpr(char_u *arg, int *cp) { typval_T tv; int retval; @@ -1704,8 +1677,7 @@ int *cp; * ":let var .= expr" assignment command. * ":let [var1, var2] = expr" unpack list. */ -void ex_let(eap) -exarg_T *eap; +void ex_let(exarg_T *eap) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -1775,13 +1747,15 @@ exarg_T *eap; * or concatenate. * Returns OK or FAIL; */ -static int ex_let_vars(arg_start, tv, copy, semicolon, var_count, nextchars) -char_u *arg_start; -typval_T *tv; -int copy; /* copy values from "tv", don't move */ -int semicolon; /* from skip_var_list() */ -int var_count; /* from skip_var_list() */ -char_u *nextchars; +static int +ex_let_vars ( + char_u *arg_start, + typval_T *tv, + int copy, /* copy values from "tv", don't move */ + int semicolon, /* from skip_var_list() */ + int var_count, /* from skip_var_list() */ + char_u *nextchars +) { char_u *arg = arg_start; list_T *l; @@ -1863,10 +1837,7 @@ char_u *nextchars; * for "[var, var; var]" set "semicolon". * Return NULL for an error. */ -static char_u * skip_var_list(arg, var_count, semicolon) -char_u *arg; -int *var_count; -int *semicolon; +static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon) { char_u *p, *s; @@ -1905,8 +1876,7 @@ int *semicolon; * Skip one (assignable) variable name, including @r, $VAR, &option, d.key, * l[idx]. */ -static char_u * skip_var_one(arg) -char_u *arg; +static char_u *skip_var_one(char_u *arg) { if (*arg == '@' && arg[1] != NUL) return arg + 2; @@ -1918,11 +1888,7 @@ char_u *arg; * List variables for hashtab "ht" with prefix "prefix". * If "empty" is TRUE also list NULL strings as empty strings. */ -static void list_hashtable_vars(ht, prefix, empty, first) -hashtab_T *ht; -char_u *prefix; -int empty; -int *first; +static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first) { hashitem_T *hi; dictitem_T *di; @@ -1943,8 +1909,7 @@ int *first; /* * List global variables. */ -static void list_glob_vars(first) -int *first; +static void list_glob_vars(int *first) { list_hashtable_vars(&globvarht, (char_u *)"", TRUE, first); } @@ -1952,8 +1917,7 @@ int *first; /* * List buffer variables. */ -static void list_buf_vars(first) -int *first; +static void list_buf_vars(int *first) { char_u numbuf[NUMBUFLEN]; @@ -1968,8 +1932,7 @@ int *first; /* * List window variables. */ -static void list_win_vars(first) -int *first; +static void list_win_vars(int *first) { list_hashtable_vars(&curwin->w_vars->dv_hashtab, (char_u *)"w:", TRUE, first); @@ -1978,8 +1941,7 @@ int *first; /* * List tab page variables. */ -static void list_tab_vars(first) -int *first; +static void list_tab_vars(int *first) { list_hashtable_vars(&curtab->tp_vars->dv_hashtab, (char_u *)"t:", TRUE, first); @@ -1988,8 +1950,7 @@ int *first; /* * List Vim variables. */ -static void list_vim_vars(first) -int *first; +static void list_vim_vars(int *first) { list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE, first); } @@ -1997,8 +1958,7 @@ int *first; /* * List script-local variables, if there is a script. */ -static void list_script_vars(first) -int *first; +static void list_script_vars(int *first) { if (current_SID > 0 && current_SID <= ga_scripts.ga_len) list_hashtable_vars(&SCRIPT_VARS(current_SID), @@ -2008,8 +1968,7 @@ int *first; /* * List function variables, if there is a function. */ -static void list_func_vars(first) -int *first; +static void list_func_vars(int *first) { if (current_funccal != NULL) list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, @@ -2019,10 +1978,7 @@ int *first; /* * List variables in "arg". */ -static char_u * list_arg_vars(eap, arg, first) -exarg_T *eap; -char_u *arg; -int *first; +static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) { int error = FALSE; int len; @@ -2112,12 +2068,14 @@ int *first; * Returns a pointer to the char just after the var name. * Returns NULL if there is an error. */ -static char_u * ex_let_one(arg, tv, copy, endchars, op) -char_u *arg; /* points to variable name */ -typval_T *tv; /* value to assign to variable */ -int copy; /* copy value from "tv" */ -char_u *endchars; /* valid chars after variable name or NULL */ -char_u *op; /* "+", "-", "." or NULL*/ +static char_u * +ex_let_one ( + char_u *arg, /* points to variable name */ + typval_T *tv, /* value to assign to variable */ + int copy, /* copy value from "tv" */ + char_u *endchars, /* valid chars after variable name or NULL */ + char_u *op /* "+", "-", "." or NULL*/ +) { int c1; char_u *name; @@ -2278,8 +2236,7 @@ char_u *op; /* "+", "-", "." or NULL*/ /* * If "arg" is equal to "b:changedtick" give an error and return TRUE. */ -static int check_changedtick(arg) -char_u *arg; +static int check_changedtick(char_u *arg) { if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) { EMSG2(_(e_readonlyvar), arg); @@ -2306,14 +2263,16 @@ char_u *arg; * When an evaluation error occurs "lp->ll_name" is NULL; * Returns NULL for a parsing error. Still need to free items in "lp"! */ -static char_u * get_lval(name, rettv, lp, unlet, skip, flags, fne_flags) -char_u *name; -typval_T *rettv; -lval_T *lp; -int unlet; -int skip; -int flags; /* GLV_ values */ -int fne_flags; /* flags for find_name_end() */ +static char_u * +get_lval ( + char_u *name, + typval_T *rettv, + lval_T *lp, + int unlet, + int skip, + int flags, /* GLV_ values */ + int fne_flags /* flags for find_name_end() */ +) { char_u *p; char_u *expr_start, *expr_end; @@ -2608,8 +2567,7 @@ int fne_flags; /* flags for find_name_end() */ /* * Clear lval "lp" that was filled by get_lval(). */ -static void clear_lval(lp) -lval_T *lp; +static void clear_lval(lval_T *lp) { vim_free(lp->ll_exp_name); vim_free(lp->ll_newkey); @@ -2620,12 +2578,7 @@ lval_T *lp; * "endp" points to just after the parsed name. * "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=". */ -static void set_var_lval(lp, endp, rettv, copy, op) -lval_T *lp; -char_u *endp; -typval_T *rettv; -int copy; -char_u *op; +static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op) { int cc; listitem_T *ri; @@ -2725,10 +2678,7 @@ char_u *op; * Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2" * Returns OK or FAIL. */ -static int tv_op(tv1, tv2, op) -typval_T *tv1; -typval_T *tv2; -char_u *op; +static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op) { long n; char_u numbuf[NUMBUFLEN]; @@ -2816,9 +2766,7 @@ char_u *op; /* * Add a watcher to a list. */ -void list_add_watch(l, lw) -list_T *l; -listwatch_T *lw; +void list_add_watch(list_T *l, listwatch_T *lw) { lw->lw_next = l->lv_watch; l->lv_watch = lw; @@ -2828,9 +2776,7 @@ listwatch_T *lw; * Remove a watcher from a list. * No warning when it isn't found... */ -void list_rem_watch(l, lwrem) -list_T *l; -listwatch_T *lwrem; +void list_rem_watch(list_T *l, listwatch_T *lwrem) { listwatch_T *lw, **lwp; @@ -2848,9 +2794,7 @@ listwatch_T *lwrem; * Just before removing an item from a list: advance watchers to the next * item. */ -static void list_fix_watch(l, item) -list_T *l; -listitem_T *item; +static void list_fix_watch(list_T *l, listitem_T *item) { listwatch_T *lw; @@ -2865,11 +2809,7 @@ listitem_T *item; * Set "*errp" to TRUE for an error, FALSE otherwise; * Return a pointer that holds the info. Null when there is an error. */ -void * eval_for_line(arg, errp, nextcmdp, skip) -char_u *arg; -int *errp; -char_u **nextcmdp; -int skip; +void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip) { forinfo_T *fi; char_u *expr; @@ -2922,9 +2862,7 @@ int skip; * Return TRUE when a valid item was found, FALSE when at end of list or * something wrong. */ -int next_for_item(fi_void, arg) -void *fi_void; -char_u *arg; +int next_for_item(void *fi_void, char_u *arg) { forinfo_T *fi = (forinfo_T *)fi_void; int result; @@ -2944,8 +2882,7 @@ char_u *arg; /* * Free the structure used to store info used by ":for". */ -void free_for_info(fi_void) -void *fi_void; +void free_for_info(void *fi_void) { forinfo_T *fi = (forinfo_T *)fi_void; @@ -2957,10 +2894,7 @@ void *fi_void; } -void set_context_for_expression(xp, arg, cmdidx) -expand_T *xp; -char_u *arg; -cmdidx_T cmdidx; +void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) { int got_eq = FALSE; int c; @@ -3042,8 +2976,7 @@ cmdidx_T cmdidx; /* * ":1,25call func(arg1, arg2)" function call. */ -void ex_call(eap) -exarg_T *eap; +void ex_call(exarg_T *eap) { char_u *arg = eap->arg; char_u *startarg; @@ -3157,8 +3090,7 @@ end: /* * ":unlet[!] var1 ... " command. */ -void ex_unlet(eap) -exarg_T *eap; +void ex_unlet(exarg_T *eap) { ex_unletlock(eap, eap->arg, 0); } @@ -3166,8 +3098,7 @@ exarg_T *eap; /* * ":lockvar" and ":unlockvar" commands */ -void ex_lockvar(eap) -exarg_T *eap; +void ex_lockvar(exarg_T *eap) { char_u *arg = eap->arg; int deep = 2; @@ -3185,10 +3116,7 @@ exarg_T *eap; /* * ":unlet", ":lockvar" and ":unlockvar" are quite similar. */ -static void ex_unletlock(eap, argstart, deep) -exarg_T *eap; -char_u *argstart; -int deep; +static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) { char_u *arg = argstart; char_u *name_end; @@ -3232,10 +3160,7 @@ int deep; eap->nextcmd = check_nextcmd(arg); } -static int do_unlet_var(lp, name_end, forceit) -lval_T *lp; -char_u *name_end; -int forceit; +static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit) { int ret = OK; int cc; @@ -3278,9 +3203,7 @@ int forceit; * "unlet" a variable. Return OK if it existed, FAIL if not. * When "forceit" is TRUE don't complain if the variable doesn't exist. */ -int do_unlet(name, forceit) -char_u *name; -int forceit; +int do_unlet(char_u *name, int forceit) { hashtab_T *ht; hashitem_T *hi; @@ -3310,11 +3233,7 @@ int forceit; * "deep" is the levels to go (-1 for unlimited); * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar". */ -static int do_lock_var(lp, name_end, deep, lock) -lval_T *lp; -char_u *name_end; -int deep; -int lock; +static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock) { int ret = OK; int cc; @@ -3365,10 +3284,7 @@ int lock; /* * Lock or unlock an item. "deep" is nr of levels to go. */ -static void item_lock(tv, deep, lock) -typval_T *tv; -int deep; -int lock; +static void item_lock(typval_T *tv, int deep, int lock) { static int recurse = 0; list_T *l; @@ -3429,8 +3345,7 @@ int lock; * Return TRUE if typeval "tv" is locked: Either that value is locked itself * or it refers to a List or Dictionary that is locked. */ -static int tv_islocked(tv) -typval_T *tv; +static int tv_islocked(typval_T *tv) { return (tv->v_lock & VAR_LOCKED) || (tv->v_type == VAR_LIST @@ -3444,7 +3359,7 @@ typval_T *tv; /* * Delete all "menutrans_" variables. */ -void del_menutrans_vars() { +void del_menutrans_vars(void) { hashitem_T *hi; int todo; @@ -3474,9 +3389,7 @@ static int varnamebuflen = 0; /* * Function to concatenate a prefix and a variable name. */ -static char_u * cat_prefix_varname(prefix, name) -int prefix; -char_u *name; +static char_u *cat_prefix_varname(int prefix, char_u *name) { int len; @@ -3501,9 +3414,7 @@ char_u *name; * Function given to ExpandGeneric() to obtain the list of user defined * (global/buffer/window/built-in) variable names. */ -char_u * get_user_var_name(xp, idx) -expand_T *xp; -int idx; +char_u *get_user_var_name(expand_T *xp, int idx) { static long_u gdone; static long_u bdone; @@ -3610,11 +3521,7 @@ typedef enum { * Note: "rettv.v_lock" is not set. * Return OK or FAIL. */ -static int eval0(arg, rettv, nextcmd, evaluate) -char_u *arg; -typval_T *rettv; -char_u **nextcmd; -int evaluate; +static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate) { int ret; char_u *p; @@ -3650,10 +3557,7 @@ int evaluate; * * Return OK or FAIL. */ -static int eval1(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int eval1(char_u **arg, typval_T *rettv, int evaluate) { int result; typval_T var2; @@ -3718,10 +3622,7 @@ int evaluate; * * Return OK or FAIL. */ -static int eval2(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int eval2(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; long result; @@ -3784,10 +3685,7 @@ int evaluate; * * Return OK or FAIL. */ -static int eval3(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int eval3(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; long result; @@ -3859,10 +3757,7 @@ int evaluate; * * Return OK or FAIL. */ -static int eval4(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int eval4(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; char_u *p; @@ -4121,10 +4016,7 @@ int evaluate; * * Return OK or FAIL. */ -static int eval5(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int eval5(char_u **arg, typval_T *rettv, int evaluate) { typval_T var2; typval_T var3; @@ -4268,11 +4160,13 @@ int evaluate; * * Return OK or FAIL. */ -static int eval6(arg, rettv, evaluate, want_string) -char_u **arg; -typval_T *rettv; -int evaluate; -int want_string; /* after "." operator */ +static int +eval6 ( + char_u **arg, + typval_T *rettv, + int evaluate, + int want_string /* after "." operator */ +) { typval_T var2; int op; @@ -4403,11 +4297,13 @@ int want_string; /* after "." operator */ * * Return OK or FAIL. */ -static int eval7(arg, rettv, evaluate, want_string) -char_u **arg; -typval_T *rettv; -int evaluate; -int want_string UNUSED; /* after "." operator */ +static int +eval7 ( + char_u **arg, + typval_T *rettv, + int evaluate, + int want_string /* after "." operator */ +) { long n; int len; @@ -4656,11 +4552,13 @@ int want_string UNUSED; /* after "." operator */ * "*arg" points to the '[' or '.'. * Returns FAIL or OK. "*arg" is advanced to after the ']'. */ -static int eval_index(arg, rettv, evaluate, verbose) -char_u **arg; -typval_T *rettv; -int evaluate; -int verbose; /* give error messages */ +static int +eval_index ( + char_u **arg, + typval_T *rettv, + int evaluate, + int verbose /* give error messages */ +) { int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; @@ -4883,10 +4781,12 @@ int verbose; /* give error messages */ * "arg" is advanced to character after the option name. * Return OK or FAIL. */ -static int get_option_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; /* when NULL, only check if option exists */ -int evaluate; +static int +get_option_tv ( + char_u **arg, + typval_T *rettv, /* when NULL, only check if option exists */ + int evaluate +) { char_u *option_end; long numval; @@ -4948,10 +4848,7 @@ int evaluate; * Allocate a variable for a string constant. * Return OK or FAIL. */ -static int get_string_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) { char_u *p; char_u *name; @@ -5070,10 +4967,7 @@ int evaluate; * Allocate a variable for a 'str''ing' constant. * Return OK or FAIL. */ -static int get_lit_string_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate) { char_u *p; char_u *str; @@ -5129,10 +5023,7 @@ int evaluate; * Allocate a variable for a List and fill it from "*arg". * Return OK or FAIL. */ -static int get_list_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate) { list_T *l = NULL; typval_T tv; @@ -5189,7 +5080,7 @@ failret: * Allocate an empty header for a list. * Caller should take care of the reference count. */ -list_T * list_alloc() { +list_T *list_alloc(void) { list_T *l; l = (list_T *)alloc_clear(sizeof(list_T)); @@ -5208,8 +5099,7 @@ list_T * list_alloc() { * Allocate an empty list for a return value. * Returns OK or FAIL. */ -static int rettv_list_alloc(rettv) -typval_T *rettv; +static int rettv_list_alloc(typval_T *rettv) { list_T *l = list_alloc(); @@ -5226,8 +5116,7 @@ typval_T *rettv; * Unreference a list: decrement the reference count and free it when it * becomes zero. */ -void list_unref(l) -list_T *l; +void list_unref(list_T *l) { if (l != NULL && --l->lv_refcount <= 0) list_free(l, TRUE); @@ -5237,9 +5126,11 @@ list_T *l; * Free a list, including all items it points to. * Ignores the reference count. */ -void list_free(l, recurse) -list_T *l; -int recurse; /* Free Lists and Dictionaries recursively. */ +void +list_free ( + list_T *l, + int recurse /* Free Lists and Dictionaries recursively. */ +) { listitem_T *item; @@ -5265,15 +5156,14 @@ int recurse; /* Free Lists and Dictionaries recursively. */ /* * Allocate a list item. */ -listitem_T * listitem_alloc() { +listitem_T *listitem_alloc(void) { return (listitem_T *)alloc(sizeof(listitem_T)); } /* * Free a list item. Also clears the value. Does not notify watchers. */ -void listitem_free(item) -listitem_T *item; +void listitem_free(listitem_T *item) { clear_tv(&item->li_tv); vim_free(item); @@ -5282,9 +5172,7 @@ listitem_T *item; /* * Remove a list item from a List and free it. Also clears the value. */ -void listitem_remove(l, item) -list_T *l; -listitem_T *item; +void listitem_remove(list_T *l, listitem_T *item) { list_remove(l, item, item); listitem_free(item); @@ -5293,8 +5181,7 @@ listitem_T *item; /* * Get the number of items in a list. */ -static long list_len(l) -list_T *l; +static long list_len(list_T *l) { if (l == NULL) return 0L; @@ -5304,11 +5191,13 @@ list_T *l; /* * Return TRUE when two lists have exactly the same values. */ -static int list_equal(l1, l2, ic, recursive) -list_T *l1; -list_T *l2; -int ic; /* ignore case for strings */ -int recursive; /* TRUE when used recursively */ +static int +list_equal ( + list_T *l1, + list_T *l2, + int ic, /* ignore case for strings */ + int recursive /* TRUE when used recursively */ +) { listitem_T *item1, *item2; @@ -5332,8 +5221,7 @@ int recursive; /* TRUE when used recursively */ /* * Return the dictitem that an entry in a hashtable points to. */ -dictitem_T * dict_lookup(hi) -hashitem_T *hi; +dictitem_T *dict_lookup(hashitem_T *hi) { return HI2DI(hi); } @@ -5342,11 +5230,13 @@ hashitem_T *hi; /* * Return TRUE when two dictionaries have exactly the same key/values. */ -static int dict_equal(d1, d2, ic, recursive) -dict_T *d1; -dict_T *d2; -int ic; /* ignore case for strings */ -int recursive; /* TRUE when used recursively */ +static int +dict_equal ( + dict_T *d1, + dict_T *d2, + int ic, /* ignore case for strings */ + int recursive /* TRUE when used recursively */ +) { hashitem_T *hi; dictitem_T *item2; @@ -5380,11 +5270,13 @@ static int tv_equal_recurse_limit; * Compares the items just like "==" would compare them, but strings and * numbers are different. Floats and numbers are also different. */ -static int tv_equal(tv1, tv2, ic, recursive) -typval_T *tv1; -typval_T *tv2; -int ic; /* ignore case */ -int recursive; /* TRUE when used recursively */ +static int +tv_equal ( + typval_T *tv1, + typval_T *tv2, + int ic, /* ignore case */ + int recursive /* TRUE when used recursively */ +) { char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; char_u *s1, *s2; @@ -5446,9 +5338,7 @@ int recursive; /* TRUE when used recursively */ * A negative index is counted from the end; -1 is the last item. * Returns NULL when "n" is out of range. */ -listitem_T * list_find(l, n) -list_T *l; -long n; +listitem_T *list_find(list_T *l, long n) { listitem_T *item; long idx; @@ -5512,10 +5402,12 @@ long n; /* * Get list item "l[idx]" as a number. */ -static long list_find_nr(l, idx, errorp) -list_T *l; -long idx; -int *errorp; /* set to TRUE when something wrong */ +static long +list_find_nr ( + list_T *l, + long idx, + int *errorp /* set to TRUE when something wrong */ +) { listitem_T *li; @@ -5531,9 +5423,7 @@ int *errorp; /* set to TRUE when something wrong */ /* * Get list item "l[idx - 1]" as a string. Returns NULL for failure. */ -char_u * list_find_str(l, idx) -list_T *l; -long idx; +char_u *list_find_str(list_T *l, long idx) { listitem_T *li; @@ -5549,9 +5439,7 @@ long idx; * Locate "item" list "l" and return its index. * Returns -1 when "item" is not in the list. */ -static long list_idx_of_item(l, item) -list_T *l; -listitem_T *item; +static long list_idx_of_item(list_T *l, listitem_T *item) { long idx = 0; listitem_T *li; @@ -5569,9 +5457,7 @@ listitem_T *item; /* * Append item "item" to the end of list "l". */ -void list_append(l, item) -list_T *l; -listitem_T *item; +void list_append(list_T *l, listitem_T *item) { if (l->lv_last == NULL) { /* empty list */ @@ -5591,9 +5477,7 @@ listitem_T *item; * Append typval_T "tv" to the end of list "l". * Return FAIL when out of memory. */ -int list_append_tv(l, tv) -list_T *l; -typval_T *tv; +int list_append_tv(list_T *l, typval_T *tv) { listitem_T *li = listitem_alloc(); @@ -5608,9 +5492,7 @@ typval_T *tv; * Add a dictionary to a list. Used by getqflist(). * Return FAIL when out of memory. */ -int list_append_dict(list, dict) -list_T *list; -dict_T *dict; +int list_append_dict(list_T *list, dict_T *dict) { listitem_T *li = listitem_alloc(); @@ -5629,10 +5511,7 @@ dict_T *dict; * When "len" >= 0 use "str[len]". * Returns FAIL when out of memory. */ -int list_append_string(l, str, len) -list_T *l; -char_u *str; -int len; +int list_append_string(list_T *l, char_u *str, int len) { listitem_T *li = listitem_alloc(); @@ -5653,9 +5532,7 @@ int len; * Append "n" to list "l". * Returns FAIL when out of memory. */ -static int list_append_number(l, n) -list_T *l; -varnumber_T n; +static int list_append_number(list_T *l, varnumber_T n) { listitem_T *li; @@ -5674,10 +5551,7 @@ varnumber_T n; * If "item" is NULL append at the end. * Return FAIL when out of memory. */ -int list_insert_tv(l, tv, item) -list_T *l; -typval_T *tv; -listitem_T *item; +int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) { listitem_T *ni = listitem_alloc(); @@ -5688,10 +5562,7 @@ listitem_T *item; return OK; } -void list_insert(l, ni, item) -list_T *l; -listitem_T *ni; -listitem_T *item; +void list_insert(list_T *l, listitem_T *ni, listitem_T *item) { if (item == NULL) /* Append new item at end of list. */ @@ -5717,10 +5588,7 @@ listitem_T *item; * If "bef" is NULL append at the end, otherwise insert before this item. * Returns FAIL when out of memory. */ -static int list_extend(l1, l2, bef) -list_T *l1; -list_T *l2; -listitem_T *bef; +static int list_extend(list_T *l1, list_T *l2, listitem_T *bef) { listitem_T *item; int todo = l2->lv_len; @@ -5737,10 +5605,7 @@ listitem_T *bef; * Concatenate lists "l1" and "l2" into a new list, stored in "tv". * Return FAIL when out of memory. */ -static int list_concat(l1, l2, tv) -list_T *l1; -list_T *l2; -typval_T *tv; +static int list_concat(list_T *l1, list_T *l2, typval_T *tv) { list_T *l; @@ -5764,10 +5629,7 @@ typval_T *tv; * See item_copy() for "copyID". * Returns NULL when out of memory. */ -static list_T * list_copy(orig, deep, copyID) -list_T *orig; -int deep; -int copyID; +static list_T *list_copy(list_T *orig, int deep, int copyID) { list_T *copy; listitem_T *item; @@ -5812,10 +5674,7 @@ int copyID; * Remove items "item" to "item2" from list "l". * Does not free the listitem or the value! */ -void list_remove(l, item, item2) -list_T *l; -listitem_T *item; -listitem_T *item2; +void list_remove(list_T *l, listitem_T *item, listitem_T *item2) { listitem_T *ip; @@ -5842,9 +5701,7 @@ listitem_T *item2; * Return an allocated string with the string representation of a list. * May return NULL. */ -static char_u * list2string(tv, copyID) -typval_T *tv; -int copyID; +static char_u *list2string(typval_T *tv, int copyID) { garray_T ga; @@ -5866,13 +5723,15 @@ typedef struct join_S { char_u *tofree; } join_T; -static int list_join_inner(gap, l, sep, echo_style, copyID, join_gap) -garray_T *gap; /* to store the result in */ -list_T *l; -char_u *sep; -int echo_style; -int copyID; -garray_T *join_gap; /* to keep each list item string */ +static int +list_join_inner ( + garray_T *gap, /* to store the result in */ + list_T *l, + char_u *sep, + int echo_style, + int copyID, + garray_T *join_gap /* to keep each list item string */ +) { int i; join_T *p; @@ -5936,12 +5795,7 @@ garray_T *join_gap; /* to keep each list item string */ * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. * Return FAIL or OK. */ -static int list_join(gap, l, sep, echo_style, copyID) -garray_T *gap; -list_T *l; -char_u *sep; -int echo_style; -int copyID; +static int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int copyID) { garray_T join_ga; int retval; @@ -5988,7 +5842,7 @@ int copyID; * Do garbage collection for lists and dicts. * Return TRUE if some memory was freed. */ -int garbage_collect() { +int garbage_collect(void) { int copyID; buf_T *buf; win_T *wp; @@ -6083,8 +5937,7 @@ int garbage_collect() { /* * Free lists and dictionaries that are no longer referenced. */ -static int free_unref_items(copyID) -int copyID; +static int free_unref_items(int copyID) { dict_T *dd; list_T *ll; @@ -6131,9 +5984,7 @@ int copyID; /* * Mark all lists and dicts referenced through hashtab "ht" with "copyID". */ -void set_ref_in_ht(ht, copyID) -hashtab_T *ht; -int copyID; +void set_ref_in_ht(hashtab_T *ht, int copyID) { int todo; hashitem_T *hi; @@ -6149,9 +6000,7 @@ int copyID; /* * Mark all lists and dicts referenced through list "l" with "copyID". */ -void set_ref_in_list(l, copyID) -list_T *l; -int copyID; +void set_ref_in_list(list_T *l, int copyID) { listitem_T *li; @@ -6162,9 +6011,7 @@ int copyID; /* * Mark all lists and dicts referenced through typval "tv" with "copyID". */ -void set_ref_in_item(tv, copyID) -typval_T *tv; -int copyID; +void set_ref_in_item(typval_T *tv, int copyID) { dict_T *dd; list_T *ll; @@ -6194,7 +6041,7 @@ int copyID; /* * Allocate an empty header for a dictionary. */ -dict_T * dict_alloc() { +dict_T *dict_alloc(void) { dict_T *d; d = (dict_T *)alloc(sizeof(dict_T)); @@ -6219,8 +6066,7 @@ dict_T * dict_alloc() { * Allocate an empty dict for a return value. * Returns OK or FAIL. */ -static int rettv_dict_alloc(rettv) -typval_T *rettv; +static int rettv_dict_alloc(typval_T *rettv) { dict_T *d = dict_alloc(); @@ -6238,8 +6084,7 @@ typval_T *rettv; * Unreference a Dictionary: decrement the reference count and free it when it * becomes zero. */ -void dict_unref(d) -dict_T *d; +void dict_unref(dict_T *d) { if (d != NULL && --d->dv_refcount <= 0) dict_free(d, TRUE); @@ -6249,9 +6094,11 @@ dict_T *d; * Free a Dictionary, including all items it contains. * Ignores the reference count. */ -void dict_free(d, recurse) -dict_T *d; -int recurse; /* Free Lists and Dictionaries recursively. */ +void +dict_free ( + dict_T *d, + int recurse /* Free Lists and Dictionaries recursively. */ +) { int todo; hashitem_T *hi; @@ -6291,8 +6138,7 @@ int recurse; /* Free Lists and Dictionaries recursively. */ * Note that the value of the item "di_tv" still needs to be initialized! * Returns NULL when out of memory. */ -dictitem_T * dictitem_alloc(key) -char_u *key; +dictitem_T *dictitem_alloc(char_u *key) { dictitem_T *di; @@ -6307,8 +6153,7 @@ char_u *key; /* * Make a copy of a Dictionary item. */ -static dictitem_T * dictitem_copy(org) -dictitem_T *org; +static dictitem_T *dictitem_copy(dictitem_T *org) { dictitem_T *di; @@ -6325,9 +6170,7 @@ dictitem_T *org; /* * Remove item "item" from Dictionary "dict" and free it. */ -static void dictitem_remove(dict, item) -dict_T *dict; -dictitem_T *item; +static void dictitem_remove(dict_T *dict, dictitem_T *item) { hashitem_T *hi; @@ -6342,8 +6185,7 @@ dictitem_T *item; /* * Free a dict item. Also clears the value. */ -void dictitem_free(item) -dictitem_T *item; +void dictitem_free(dictitem_T *item) { clear_tv(&item->di_tv); vim_free(item); @@ -6355,10 +6197,7 @@ dictitem_T *item; * See item_copy() for "copyID". * Returns NULL when out of memory. */ -static dict_T * dict_copy(orig, deep, copyID) -dict_T *orig; -int deep; -int copyID; +static dict_T *dict_copy(dict_T *orig, int deep, int copyID) { dict_T *copy; dictitem_T *di; @@ -6411,9 +6250,7 @@ int copyID; * Add item "item" to Dictionary "d". * Returns FAIL when out of memory and when key already exists. */ -int dict_add(d, item) -dict_T *d; -dictitem_T *item; +int dict_add(dict_T *d, dictitem_T *item) { return hash_add(&d->dv_hashtab, item->di_key); } @@ -6423,11 +6260,7 @@ dictitem_T *item; * When "str" is NULL use number "nr", otherwise use "str". * Returns FAIL when out of memory and when key already exists. */ -int dict_add_nr_str(d, key, nr, str) -dict_T *d; -char *key; -long nr; -char_u *str; +int dict_add_nr_str(dict_T *d, char *key, long nr, char_u *str) { dictitem_T *item; @@ -6453,10 +6286,7 @@ char_u *str; * Add a list entry to dictionary "d". * Returns FAIL when out of memory and when key already exists. */ -int dict_add_list(d, key, list) -dict_T *d; -char *key; -list_T *list; +int dict_add_list(dict_T *d, char *key, list_T *list) { dictitem_T *item; @@ -6477,8 +6307,7 @@ list_T *list; /* * Get the number of items in a Dictionary. */ -static long dict_len(d) -dict_T *d; +static long dict_len(dict_T *d) { if (d == NULL) return 0L; @@ -6490,10 +6319,7 @@ dict_T *d; * If "len" is negative use strlen(key). * Returns NULL when not found. */ -dictitem_T * dict_find(d, key, len) -dict_T *d; -char_u *key; -int len; +dictitem_T *dict_find(dict_T *d, char_u *key, int len) { #define AKEYLEN 200 char_u buf[AKEYLEN]; @@ -6525,10 +6351,7 @@ int len; * When "save" is TRUE allocate memory for it. * Returns NULL if the entry doesn't exist or out of memory. */ -char_u * get_dict_string(d, key, save) -dict_T *d; -char_u *key; -int save; +char_u *get_dict_string(dict_T *d, char_u *key, int save) { dictitem_T *di; char_u *s; @@ -6546,9 +6369,7 @@ int save; * Get a number item from a dictionary. * Returns 0 if the entry doesn't exist or out of memory. */ -long get_dict_number(d, key) -dict_T *d; -char_u *key; +long get_dict_number(dict_T *d, char_u *key) { dictitem_T *di; @@ -6562,9 +6383,7 @@ char_u *key; * Return an allocated string with the string representation of a Dictionary. * May return NULL. */ -static char_u * dict2string(tv, copyID) -typval_T *tv; -int copyID; +static char_u *dict2string(typval_T *tv, int copyID) { garray_T ga; int first = TRUE; @@ -6618,10 +6437,7 @@ int copyID; * Allocate a variable for a Dictionary and fill it from "*arg". * Return OK or FAIL. Returns NOTDONE for {expr}. */ -static int get_dict_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate) { dict_T *d = NULL; typval_T tvkey; @@ -6732,11 +6548,7 @@ failret: * When "copyID" is not NULL replace recursive lists and dicts with "...". * May return NULL. */ -static char_u * echo_string(tv, tofree, numbuf, copyID) -typval_T *tv; -char_u **tofree; -char_u *numbuf; -int copyID; +static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID) { static int recurse = 0; char_u *r = NULL; @@ -6810,11 +6622,7 @@ int copyID; * Puts quotes around strings, so that they can be parsed back by eval(). * May return NULL. */ -static char_u * tv2string(tv, tofree, numbuf, copyID) -typval_T *tv; -char_u **tofree; -char_u *numbuf; -int copyID; +static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID) { switch (tv->v_type) { case VAR_FUNC: @@ -6842,9 +6650,7 @@ int copyID; * If "str" is NULL an empty string is assumed. * If "function" is TRUE make it function('string'). */ -static char_u * string_quote(str, function) -char_u *str; -int function; +static char_u *string_quote(char_u *str, int function) { unsigned len; char_u *p, *r, *s; @@ -6883,9 +6689,11 @@ int function; * this always uses a decimal point. * Returns the length of the text that was consumed. */ -static int string2float(text, value) -char_u *text; -float_T *value; /* result stored here */ +static int +string2float ( + char_u *text, + float_T *value /* result stored here */ +) { char *s = (char *)text; float_T f; @@ -6901,10 +6709,7 @@ float_T *value; /* result stored here */ * If the environment variable was not set, silently assume it is empty. * Always return OK. */ -static int get_env_tv(arg, rettv, evaluate) -char_u **arg; -typval_T *rettv; -int evaluate; +static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate) { char_u *string = NULL; int len; @@ -7233,9 +7038,7 @@ static struct fst { * Function given to ExpandGeneric() to obtain the list of internal * or user defined function names. */ -char_u * get_function_name(xp, idx) -expand_T *xp; -int idx; +char_u *get_function_name(expand_T *xp, int idx) { static int intidx = -1; char_u *name; @@ -7262,9 +7065,7 @@ int idx; * Function given to ExpandGeneric() to obtain the list of internal or * user defined variable or function names. */ -char_u * get_expr_name(xp, idx) -expand_T *xp; -int idx; +char_u *get_expr_name(expand_T *xp, int idx) { static int intidx = -1; char_u *name; @@ -7286,8 +7087,10 @@ int idx; * Find internal function in table above. * Return index, or -1 if not found */ -static int find_internal_func(name) -char_u *name; /* name of the function */ +static int +find_internal_func ( + char_u *name /* name of the function */ +) { int first = 0; int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; @@ -7314,10 +7117,7 @@ char_u *name; /* name of the function */ * Check if "name" is a variable of type VAR_FUNC. If so, return the function * name it contains, otherwise return "name". */ -static char_u * deref_func_name(name, lenp, no_autoload) -char_u *name; -int *lenp; -int no_autoload; +static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload) { dictitem_T *v; int cc; @@ -7342,17 +7142,18 @@ int no_autoload; * Allocate a variable for the result of a function. * Return OK or FAIL. */ -static int get_func_tv(name, len, rettv, arg, firstline, lastline, doesrange, - evaluate, selfdict) -char_u *name; /* name of the function */ -int len; /* length of "name" */ -typval_T *rettv; -char_u **arg; /* argument, pointing to the '(' */ -linenr_T firstline; /* first line of range */ -linenr_T lastline; /* last line of range */ -int *doesrange; /* return: function handled range */ -int evaluate; -dict_T *selfdict; /* Dictionary for "self" */ +static int +get_func_tv ( + char_u *name, /* name of the function */ + int len, /* length of "name" */ + typval_T *rettv, + char_u **arg, /* argument, pointing to the '(' */ + linenr_T firstline, /* first line of range */ + linenr_T lastline, /* last line of range */ + int *doesrange, /* return: function handled range */ + int evaluate, + dict_T *selfdict /* Dictionary for "self" */ +) { char_u *argp; int ret = OK; @@ -7403,21 +7204,20 @@ dict_T *selfdict; /* Dictionary for "self" */ * Return FAIL when the function can't be called, OK otherwise. * Also returns OK when an error was encountered while executing the function. */ -static int call_func(funcname, len, rettv, argcount, argvars, firstline, - lastline, - doesrange, evaluate, - selfdict) -char_u *funcname; /* name of the function */ -int len; /* length of "name" */ -typval_T *rettv; /* return value goes here */ -int argcount; /* number of "argvars" */ -typval_T *argvars; /* vars for arguments, must have "argcount" +static int +call_func ( + char_u *funcname, /* name of the function */ + int len, /* length of "name" */ + typval_T *rettv, /* return value goes here */ + int argcount, /* number of "argvars" */ + typval_T *argvars, /* vars for arguments, must have "argcount" PLUS ONE elements! */ -linenr_T firstline; /* first line of range */ -linenr_T lastline; /* last line of range */ -int *doesrange; /* return: function handled range */ -int evaluate; -dict_T *selfdict; /* Dictionary for "self" */ + linenr_T firstline, /* first line of range */ + linenr_T lastline, /* last line of range */ + int *doesrange, /* return: function handled range */ + int evaluate, + dict_T *selfdict /* Dictionary for "self" */ +) { int ret = FAIL; #define ERROR_UNKNOWN 0 @@ -7606,9 +7406,7 @@ dict_T *selfdict; /* Dictionary for "self" */ * Give an error message with a function name. Handle things. * "ermsg" is to be passed without translation, use N_() instead of _(). */ -static void emsg_funcname(ermsg, name) -char *ermsg; -char_u *name; +static void emsg_funcname(char *ermsg, char_u *name) { char_u *p; @@ -7624,8 +7422,7 @@ char_u *name; /* * Return TRUE for a non-zero Number and a non-empty String. */ -static int non_zero_arg(argvars) -typval_T *argvars; +static int non_zero_arg(typval_T *argvars) { return (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number != 0) @@ -7644,9 +7441,7 @@ static int get_float_arg __ARGS((typval_T *argvars, float_T *f)); * Get the float value of "argvars[0]" into "f". * Returns FAIL when the argument is not a Number or Float. */ -static int get_float_arg(argvars, f) -typval_T *argvars; -float_T *f; +static int get_float_arg(typval_T *argvars, float_T *f) { if (argvars[0].v_type == VAR_FLOAT) { *f = argvars[0].vval.v_float; @@ -7663,9 +7458,7 @@ float_T *f; /* * "abs(expr)" function */ -static void f_abs(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_abs(typval_T *argvars, typval_T *rettv) { if (argvars[0].v_type == VAR_FLOAT) { rettv->v_type = VAR_FLOAT; @@ -7687,9 +7480,7 @@ typval_T *rettv; /* * "acos()" function */ -static void f_acos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_acos(typval_T *argvars, typval_T *rettv) { float_T f; @@ -7703,9 +7494,7 @@ typval_T *rettv; /* * "add(list, item)" function */ -static void f_add(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_add(typval_T *argvars, typval_T *rettv) { list_T *l; @@ -7722,9 +7511,7 @@ typval_T *rettv; /* * "and(expr, expr)" function */ -static void f_and(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_and(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) & get_tv_number_chk(&argvars[1], NULL); @@ -7733,9 +7520,7 @@ typval_T *rettv; /* * "append(lnum, string/list)" function */ -static void f_append(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_append(typval_T *argvars, typval_T *rettv) { long lnum; char_u *line; @@ -7790,9 +7575,7 @@ typval_T *rettv; /* * "argc()" function */ -static void f_argc(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_argc(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = ARGCOUNT; } @@ -7800,9 +7583,7 @@ typval_T *rettv; /* * "argidx()" function */ -static void f_argidx(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_argidx(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = curwin->w_arg_idx; } @@ -7810,9 +7591,7 @@ typval_T *rettv; /* * "argv(nr)" function */ -static void f_argv(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_argv(typval_T *argvars, typval_T *rettv) { int idx; @@ -7832,9 +7611,7 @@ typval_T *rettv; /* * "asin()" function */ -static void f_asin(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_asin(typval_T *argvars, typval_T *rettv) { float_T f; @@ -7848,9 +7625,7 @@ typval_T *rettv; /* * "atan()" function */ -static void f_atan(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_atan(typval_T *argvars, typval_T *rettv) { float_T f; @@ -7864,9 +7639,7 @@ typval_T *rettv; /* * "atan2()" function */ -static void f_atan2(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_atan2(typval_T *argvars, typval_T *rettv) { float_T fx, fy; @@ -7881,9 +7654,7 @@ typval_T *rettv; /* * "browse(save, title, initdir, default)" function */ -static void f_browse(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_browse(typval_T *argvars, typval_T *rettv) { rettv->vval.v_string = NULL; rettv->v_type = VAR_STRING; @@ -7892,9 +7663,7 @@ typval_T *rettv; /* * "browsedir(title, initdir)" function */ -static void f_browsedir(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_browsedir(typval_T *argvars, typval_T *rettv) { rettv->vval.v_string = NULL; rettv->v_type = VAR_STRING; @@ -7905,8 +7674,7 @@ static buf_T *find_buffer __ARGS((typval_T *avar)); /* * Find a buffer by number or exact name. */ -static buf_T * find_buffer(avar) -typval_T *avar; +static buf_T *find_buffer(typval_T *avar) { buf_T *buf = NULL; @@ -7932,9 +7700,7 @@ typval_T *avar; /* * "bufexists(expr)" function */ -static void f_bufexists(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_bufexists(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); } @@ -7942,9 +7708,7 @@ typval_T *rettv; /* * "buflisted(expr)" function */ -static void f_buflisted(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_buflisted(typval_T *argvars, typval_T *rettv) { buf_T *buf; @@ -7955,9 +7719,7 @@ typval_T *rettv; /* * "bufloaded(expr)" function */ -static void f_bufloaded(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_bufloaded(typval_T *argvars, typval_T *rettv) { buf_T *buf; @@ -7970,9 +7732,7 @@ static buf_T *get_buf_tv __ARGS((typval_T *tv, int curtab_only)); /* * Get buffer by number or pattern. */ -static buf_T * get_buf_tv(tv, curtab_only) -typval_T *tv; -int curtab_only; +static buf_T *get_buf_tv(typval_T *tv, int curtab_only) { char_u *name = tv->vval.v_string; int save_magic; @@ -8010,9 +7770,7 @@ int curtab_only; /* * "bufname(expr)" function */ -static void f_bufname(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_bufname(typval_T *argvars, typval_T *rettv) { buf_T *buf; @@ -8030,9 +7788,7 @@ typval_T *rettv; /* * "bufnr(expr)" function */ -static void f_bufnr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_bufnr(typval_T *argvars, typval_T *rettv) { buf_T *buf; int error = FALSE; @@ -8062,9 +7818,7 @@ typval_T *rettv; /* * "bufwinnr(nr)" function */ -static void f_bufwinnr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_bufwinnr(typval_T *argvars, typval_T *rettv) { win_T *wp; int winnr = 0; @@ -8085,9 +7839,7 @@ typval_T *rettv; /* * "byte2line(byte)" function */ -static void f_byte2line(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_byte2line(typval_T *argvars, typval_T *rettv) { long boff = 0; @@ -8099,10 +7851,7 @@ typval_T *rettv; (linenr_T)0, &boff); } -static void byteidx(argvars, rettv, comp) -typval_T *argvars; -typval_T *rettv; -int comp; +static void byteidx(typval_T *argvars, typval_T *rettv, int comp) { char_u *t; char_u *str; @@ -8129,9 +7878,7 @@ int comp; /* * "byteidx()" function */ -static void f_byteidx(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_byteidx(typval_T *argvars, typval_T *rettv) { byteidx(argvars, rettv, FALSE); } @@ -8139,18 +7886,12 @@ typval_T *rettv; /* * "byteidxcomp()" function */ -static void f_byteidxcomp(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_byteidxcomp(typval_T *argvars, typval_T *rettv) { byteidx(argvars, rettv, TRUE); } -int func_call(name, args, selfdict, rettv) -char_u *name; -typval_T *args; -dict_T *selfdict; -typval_T *rettv; +int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv) { listitem_T *item; typval_T argv[MAX_FUNC_ARGS + 1]; @@ -8185,9 +7926,7 @@ typval_T *rettv; /* * "call(func, arglist)" function */ -static void f_call(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_call(typval_T *argvars, typval_T *rettv) { char_u *func; dict_T *selfdict = NULL; @@ -8220,9 +7959,7 @@ typval_T *rettv; /* * "ceil({float})" function */ -static void f_ceil(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_ceil(typval_T *argvars, typval_T *rettv) { float_T f; @@ -8236,9 +7973,7 @@ typval_T *rettv; /* * "changenr()" function */ -static void f_changenr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_changenr(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = curbuf->b_u_seq_cur; } @@ -8246,9 +7981,7 @@ typval_T *rettv; /* * "char2nr(string)" function */ -static void f_char2nr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_char2nr(typval_T *argvars, typval_T *rettv) { if (has_mbyte) { int utf8 = 0; @@ -8267,9 +8000,7 @@ typval_T *rettv; /* * "cindent(lnum)" function */ -static void f_cindent(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_cindent(typval_T *argvars, typval_T *rettv) { pos_T pos; linenr_T lnum; @@ -8287,9 +8018,7 @@ typval_T *rettv; /* * "clearmatches()" function */ -static void f_clearmatches(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_clearmatches(typval_T *argvars, typval_T *rettv) { clear_matches(curwin); } @@ -8297,9 +8026,7 @@ typval_T *rettv UNUSED; /* * "col(string)" function */ -static void f_col(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_col(typval_T *argvars, typval_T *rettv) { colnr_T col = 0; pos_T *fp; @@ -8336,9 +8063,7 @@ typval_T *rettv; /* * "complete()" function */ -static void f_complete(argvars, rettv) -typval_T *argvars; -typval_T *rettv UNUSED; +static void f_complete(typval_T *argvars, typval_T *rettv) { int startcol; @@ -8367,9 +8092,7 @@ typval_T *rettv UNUSED; /* * "complete_add()" function */ -static void f_complete_add(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_complete_add(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); } @@ -8377,9 +8100,7 @@ typval_T *rettv; /* * "complete_check()" function */ -static void f_complete_check(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_complete_check(typval_T *argvars, typval_T *rettv) { int saved = RedrawingDisabled; @@ -8392,9 +8113,7 @@ typval_T *rettv; /* * "confirm(message, buttons[, default [, type]])" function */ -static void f_confirm(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_confirm(typval_T *argvars, typval_T *rettv) { char_u *message; char_u *buttons = NULL; @@ -8442,9 +8161,7 @@ typval_T *rettv UNUSED; /* * "copy()" function */ -static void f_copy(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_copy(typval_T *argvars, typval_T *rettv) { item_copy(&argvars[0], rettv, FALSE, 0); } @@ -8452,9 +8169,7 @@ typval_T *rettv; /* * "cos()" function */ -static void f_cos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_cos(typval_T *argvars, typval_T *rettv) { float_T f; @@ -8468,9 +8183,7 @@ typval_T *rettv; /* * "cosh()" function */ -static void f_cosh(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_cosh(typval_T *argvars, typval_T *rettv) { float_T f; @@ -8484,9 +8197,7 @@ typval_T *rettv; /* * "count()" function */ -static void f_count(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_count(typval_T *argvars, typval_T *rettv) { long n = 0; int ic = FALSE; @@ -8551,9 +8262,7 @@ typval_T *rettv; * * Checks the existence of a cscope connection. */ -static void f_cscope_connection(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_cscope_connection(typval_T *argvars, typval_T *rettv) { int num = 0; char_u *dbpath = NULL; @@ -8577,9 +8286,7 @@ typval_T *rettv UNUSED; * Moves the cursor to the specified line and column. * Returns 0 when the position could be set, -1 otherwise. */ -static void f_cursor(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_cursor(typval_T *argvars, typval_T *rettv) { long line, col; long coladd = 0; @@ -8622,9 +8329,7 @@ typval_T *rettv; /* * "deepcopy()" function */ -static void f_deepcopy(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_deepcopy(typval_T *argvars, typval_T *rettv) { int noref = 0; @@ -8641,9 +8346,7 @@ typval_T *rettv; /* * "delete()" function */ -static void f_delete(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_delete(typval_T *argvars, typval_T *rettv) { if (check_restricted() || check_secure()) rettv->vval.v_number = -1; @@ -8654,9 +8357,7 @@ typval_T *rettv; /* * "did_filetype()" function */ -static void f_did_filetype(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_did_filetype(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = did_filetype; } @@ -8664,9 +8365,7 @@ typval_T *rettv UNUSED; /* * "diff_filler()" function */ -static void f_diff_filler(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_diff_filler(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars)); } @@ -8674,9 +8373,7 @@ typval_T *rettv UNUSED; /* * "diff_hlID()" function */ -static void f_diff_hlID(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_diff_hlID(typval_T *argvars, typval_T *rettv) { linenr_T lnum = get_tv_lnum(argvars); static linenr_T prev_lnum = 0; @@ -8725,9 +8422,7 @@ typval_T *rettv UNUSED; /* * "empty({expr})" function */ -static void f_empty(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_empty(typval_T *argvars, typval_T *rettv) { int n; @@ -8762,9 +8457,7 @@ typval_T *rettv; /* * "escape({string}, {chars})" function */ -static void f_escape(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_escape(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; @@ -8776,9 +8469,7 @@ typval_T *rettv; /* * "eval()" function */ -static void f_eval(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_eval(typval_T *argvars, typval_T *rettv) { char_u *s; @@ -8796,9 +8487,7 @@ typval_T *rettv; /* * "eventhandler()" function */ -static void f_eventhandler(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_eventhandler(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = vgetc_busy; } @@ -8806,9 +8495,7 @@ typval_T *rettv; /* * "executable()" function */ -static void f_executable(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_executable(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = mch_can_exe(get_tv_string(&argvars[0])); } @@ -8816,9 +8503,7 @@ typval_T *rettv; /* * "exists()" function */ -static void f_exists(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_exists(typval_T *argvars, typval_T *rettv) { char_u *p; char_u *name; @@ -8880,9 +8565,7 @@ typval_T *rettv; /* * "exp()" function */ -static void f_exp(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_exp(typval_T *argvars, typval_T *rettv) { float_T f; @@ -8896,9 +8579,7 @@ typval_T *rettv; /* * "expand()" function */ -static void f_expand(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_expand(typval_T *argvars, typval_T *rettv) { char_u *s; int len; @@ -8962,10 +8643,7 @@ typval_T *rettv; * When "action" is "force" then a duplicate key is overwritten. * Otherwise duplicate keys are ignored ("action" is "keep"). */ -void dict_extend(d1, d2, action) -dict_T *d1; -dict_T *d2; -char_u *action; +void dict_extend(dict_T *d1, dict_T *d2, char_u *action) { dictitem_T *di1; hashitem_T *hi2; @@ -9007,9 +8685,7 @@ char_u *action; * "extend(list, list [, idx])" function * "extend(dict, dict [, action])" function */ -static void f_extend(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_extend(typval_T *argvars, typval_T *rettv) { char *arg_errmsg = N_("extend() argument"); @@ -9081,9 +8757,7 @@ typval_T *rettv; /* * "feedkeys()" function */ -static void f_feedkeys(argvars, rettv) -typval_T *argvars; -typval_T *rettv UNUSED; +static void f_feedkeys(typval_T *argvars, typval_T *rettv) { int remap = TRUE; char_u *keys, *flags; @@ -9126,9 +8800,7 @@ typval_T *rettv UNUSED; /* * "filereadable()" function */ -static void f_filereadable(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_filereadable(typval_T *argvars, typval_T *rettv) { int fd; char_u *p; @@ -9152,9 +8824,7 @@ typval_T *rettv; * Return 0 for not writable, 1 for writable file, 2 for a dir which we have * rights to write into. */ -static void f_filewritable(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_filewritable(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = filewritable(get_tv_string(&argvars[0])); } @@ -9162,10 +8832,7 @@ typval_T *rettv; static void findfilendir __ARGS((typval_T *argvars, typval_T *rettv, int find_what)); -static void findfilendir(argvars, rettv, find_what) -typval_T *argvars UNUSED; -typval_T *rettv; -int find_what UNUSED; +static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what) { char_u *fname; char_u *fresult = NULL; @@ -9227,10 +8894,7 @@ static int filter_map_one __ARGS((typval_T *tv, char_u *expr, int map, /* * Implementation of map() and filter(). */ -static void filter_map(argvars, rettv, map) -typval_T *argvars; -typval_T *rettv; -int map; +static void filter_map(typval_T *argvars, typval_T *rettv, int map) { char_u buf[NUMBUFLEN]; char_u *expr; @@ -9326,11 +8990,7 @@ int map; copy_tv(&argvars[0], rettv); } -static int filter_map_one(tv, expr, map, remp) -typval_T *tv; -char_u *expr; -int map; -int *remp; +static int filter_map_one(typval_T *tv, char_u *expr, int map, int *remp) { typval_T rettv; char_u *s; @@ -9369,9 +9029,7 @@ theend: /* * "filter()" function */ -static void f_filter(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_filter(typval_T *argvars, typval_T *rettv) { filter_map(argvars, rettv, FALSE); } @@ -9379,9 +9037,7 @@ typval_T *rettv; /* * "finddir({fname}[, {path}[, {count}]])" function */ -static void f_finddir(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_finddir(typval_T *argvars, typval_T *rettv) { findfilendir(argvars, rettv, FINDFILE_DIR); } @@ -9389,9 +9045,7 @@ typval_T *rettv; /* * "findfile({fname}[, {path}[, {count}]])" function */ -static void f_findfile(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_findfile(typval_T *argvars, typval_T *rettv) { findfilendir(argvars, rettv, FINDFILE_FILE); } @@ -9399,9 +9053,7 @@ typval_T *rettv; /* * "float2nr({float})" function */ -static void f_float2nr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_float2nr(typval_T *argvars, typval_T *rettv) { float_T f; @@ -9418,9 +9070,7 @@ typval_T *rettv; /* * "floor({float})" function */ -static void f_floor(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_floor(typval_T *argvars, typval_T *rettv) { float_T f; @@ -9434,9 +9084,7 @@ typval_T *rettv; /* * "fmod()" function */ -static void f_fmod(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_fmod(typval_T *argvars, typval_T *rettv) { float_T fx, fy; @@ -9451,9 +9099,7 @@ typval_T *rettv; /* * "fnameescape({string})" function */ -static void f_fnameescape(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_fnameescape(typval_T *argvars, typval_T *rettv) { rettv->vval.v_string = vim_strsave_fnameescape( get_tv_string(&argvars[0]), FALSE); @@ -9463,9 +9109,7 @@ typval_T *rettv; /* * "fnamemodify({fname}, {mods})" function */ -static void f_fnamemodify(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_fnamemodify(typval_T *argvars, typval_T *rettv) { char_u *fname; char_u *mods; @@ -9496,10 +9140,7 @@ static void foldclosed_both __ARGS((typval_T *argvars, typval_T *rettv, int end) /* * "foldclosed()" function */ -static void foldclosed_both(argvars, rettv, end) -typval_T *argvars UNUSED; -typval_T *rettv; -int end UNUSED; +static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end) { linenr_T lnum; linenr_T first, last; @@ -9520,9 +9161,7 @@ int end UNUSED; /* * "foldclosed()" function */ -static void f_foldclosed(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_foldclosed(typval_T *argvars, typval_T *rettv) { foldclosed_both(argvars, rettv, FALSE); } @@ -9530,9 +9169,7 @@ typval_T *rettv; /* * "foldclosedend()" function */ -static void f_foldclosedend(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_foldclosedend(typval_T *argvars, typval_T *rettv) { foldclosed_both(argvars, rettv, TRUE); } @@ -9540,9 +9177,7 @@ typval_T *rettv; /* * "foldlevel()" function */ -static void f_foldlevel(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_foldlevel(typval_T *argvars, typval_T *rettv) { linenr_T lnum; @@ -9554,9 +9189,7 @@ typval_T *rettv UNUSED; /* * "foldtext()" function */ -static void f_foldtext(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_foldtext(typval_T *argvars, typval_T *rettv) { linenr_T lnum; char_u *s; @@ -9611,9 +9244,7 @@ typval_T *rettv; /* * "foldtextresult(lnum)" function */ -static void f_foldtextresult(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_foldtextresult(typval_T *argvars, typval_T *rettv) { linenr_T lnum; char_u *text; @@ -9640,18 +9271,14 @@ typval_T *rettv; /* * "foreground()" function */ -static void f_foreground(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_foreground(typval_T *argvars, typval_T *rettv) { } /* * "function()" function */ -static void f_function(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_function(typval_T *argvars, typval_T *rettv) { char_u *s; @@ -9686,9 +9313,7 @@ typval_T *rettv; /* * "garbagecollect()" function */ -static void f_garbagecollect(argvars, rettv) -typval_T *argvars; -typval_T *rettv UNUSED; +static void f_garbagecollect(typval_T *argvars, typval_T *rettv) { /* This is postponed until we are back at the toplevel, because we may be * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ @@ -9701,9 +9326,7 @@ typval_T *rettv UNUSED; /* * "get()" function */ -static void f_get(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_get(typval_T *argvars, typval_T *rettv) { listitem_T *li; list_T *l; @@ -9745,12 +9368,7 @@ static void get_buffer_lines __ARGS((buf_T *buf, linenr_T start, linenr_T end, * buffer. * If 'retlist' is TRUE, then the lines are returned as a Vim List. */ -static void get_buffer_lines(buf, start, end, retlist, rettv) -buf_T *buf; -linenr_T start; -linenr_T end; -int retlist; -typval_T *rettv; +static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv) { char_u *p; @@ -9786,9 +9404,7 @@ typval_T *rettv; /* * "getbufline()" function */ -static void f_getbufline(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getbufline(typval_T *argvars, typval_T *rettv) { linenr_T lnum; linenr_T end; @@ -9811,9 +9427,7 @@ typval_T *rettv; /* * "getbufvar()" function */ -static void f_getbufvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getbufvar(typval_T *argvars, typval_T *rettv) { buf_T *buf; buf_T *save_curbuf; @@ -9866,9 +9480,7 @@ typval_T *rettv; /* * "getchar()" function */ -static void f_getchar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getchar(typval_T *argvars, typval_T *rettv) { varnumber_T n; int error = FALSE; @@ -9951,9 +9563,7 @@ typval_T *rettv; /* * "getcharmod()" function */ -static void f_getcharmod(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getcharmod(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = mod_mask; } @@ -9961,9 +9571,7 @@ typval_T *rettv; /* * "getcmdline()" function */ -static void f_getcmdline(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getcmdline(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = get_cmdline_str(); @@ -9972,9 +9580,7 @@ typval_T *rettv; /* * "getcmdpos()" function */ -static void f_getcmdpos(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getcmdpos(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = get_cmdline_pos() + 1; } @@ -9982,9 +9588,7 @@ typval_T *rettv; /* * "getcmdtype()" function */ -static void f_getcmdtype(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getcmdtype(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = alloc(2); @@ -9997,9 +9601,7 @@ typval_T *rettv; /* * "getcwd()" function */ -static void f_getcwd(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getcwd(typval_T *argvars, typval_T *rettv) { char_u *cwd; @@ -10021,9 +9623,7 @@ typval_T *rettv; /* * "getfontname()" function */ -static void f_getfontname(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getfontname(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -10032,9 +9632,7 @@ typval_T *rettv; /* * "getfperm({fname})" function */ -static void f_getfperm(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getfperm(typval_T *argvars, typval_T *rettv) { char_u *fname; struct stat st; @@ -10060,9 +9658,7 @@ typval_T *rettv; /* * "getfsize({fname})" function */ -static void f_getfsize(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getfsize(typval_T *argvars, typval_T *rettv) { char_u *fname; struct stat st; @@ -10088,9 +9684,7 @@ typval_T *rettv; /* * "getftime({fname})" function */ -static void f_getftime(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getftime(typval_T *argvars, typval_T *rettv) { char_u *fname; struct stat st; @@ -10106,9 +9700,7 @@ typval_T *rettv; /* * "getftype({fname})" function */ -static void f_getftype(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getftype(typval_T *argvars, typval_T *rettv) { char_u *fname; struct stat st; @@ -10183,9 +9775,7 @@ typval_T *rettv; /* * "getline(lnum, [end])" function */ -static void f_getline(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getline(typval_T *argvars, typval_T *rettv) { linenr_T lnum; linenr_T end; @@ -10206,9 +9796,7 @@ typval_T *rettv; /* * "getmatches()" function */ -static void f_getmatches(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_getmatches(typval_T *argvars, typval_T *rettv) { dict_T *dict; matchitem_T *cur = curwin->w_match_head; @@ -10231,9 +9819,7 @@ typval_T *rettv UNUSED; /* * "getpid()" function */ -static void f_getpid(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getpid(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = mch_get_pid(); } @@ -10241,9 +9827,7 @@ typval_T *rettv; /* * "getpos(string)" function */ -static void f_getpos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getpos(typval_T *argvars, typval_T *rettv) { pos_T *fp; list_T *l; @@ -10271,9 +9855,7 @@ typval_T *rettv; /* * "getqflist()" and "getloclist()" functions */ -static void f_getqflist(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_getqflist(typval_T *argvars, typval_T *rettv) { win_T *wp; @@ -10292,9 +9874,7 @@ typval_T *rettv UNUSED; /* * "getreg()" function */ -static void f_getreg(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getreg(typval_T *argvars, typval_T *rettv) { char_u *strregname; int regname; @@ -10320,9 +9900,7 @@ typval_T *rettv; /* * "getregtype()" function */ -static void f_getregtype(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getregtype(typval_T *argvars, typval_T *rettv) { char_u *strregname; int regname; @@ -10361,9 +9939,7 @@ typval_T *rettv; /* * "gettabvar()" function */ -static void f_gettabvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_gettabvar(typval_T *argvars, typval_T *rettv) { tabpage_T *tp; dictitem_T *v; @@ -10391,9 +9967,7 @@ typval_T *rettv; /* * "gettabwinvar()" function */ -static void f_gettabwinvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_gettabwinvar(typval_T *argvars, typval_T *rettv) { getwinvar(argvars, rettv, 1); } @@ -10401,9 +9975,7 @@ typval_T *rettv; /* * "getwinposx()" function */ -static void f_getwinposx(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getwinposx(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = -1; } @@ -10411,9 +9983,7 @@ typval_T *rettv; /* * "getwinposy()" function */ -static void f_getwinposy(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_getwinposy(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = -1; } @@ -10421,9 +9991,11 @@ typval_T *rettv; /* * Find window specified by "vp" in tabpage "tp". */ -static win_T * find_win_by_nr(vp, tp) -typval_T *vp; -tabpage_T *tp UNUSED; /* NULL for current tab page */ +static win_T * +find_win_by_nr ( + typval_T *vp, + tabpage_T *tp /* NULL for current tab page */ +) { win_T *wp; int nr; @@ -10445,9 +10017,7 @@ tabpage_T *tp UNUSED; /* NULL for current tab page */ /* * "getwinvar()" function */ -static void f_getwinvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_getwinvar(typval_T *argvars, typval_T *rettv) { getwinvar(argvars, rettv, 0); } @@ -10455,10 +10025,12 @@ typval_T *rettv; /* * getwinvar() and gettabwinvar() */ -static void getwinvar(argvars, rettv, off) -typval_T *argvars; -typval_T *rettv; -int off; /* 1 for gettabwinvar() */ +static void +getwinvar ( + typval_T *argvars, + typval_T *rettv, + int off /* 1 for gettabwinvar() */ +) { win_T *win, *oldcurwin; char_u *varname; @@ -10510,9 +10082,7 @@ int off; /* 1 for gettabwinvar() */ /* * "glob()" function */ -static void f_glob(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_glob(typval_T *argvars, typval_T *rettv) { int options = WILD_SILENT|WILD_USE_NL; expand_T xpc; @@ -10555,9 +10125,7 @@ typval_T *rettv; /* * "globpath()" function */ -static void f_globpath(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_globpath(typval_T *argvars, typval_T *rettv) { int flags = 0; char_u buf1[NUMBUFLEN]; @@ -10580,9 +10148,7 @@ typval_T *rettv; /* * "has()" function */ -static void f_has(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_has(typval_T *argvars, typval_T *rettv) { int i; char_u *name; @@ -10773,9 +10339,7 @@ typval_T *rettv; /* * "has_key()" function */ -static void f_has_key(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_has_key(typval_T *argvars, typval_T *rettv) { if (argvars[0].v_type != VAR_DICT) { EMSG(_(e_dictreq)); @@ -10791,9 +10355,7 @@ typval_T *rettv; /* * "haslocaldir()" function */ -static void f_haslocaldir(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_haslocaldir(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = (curwin->w_localdir != NULL); } @@ -10801,9 +10363,7 @@ typval_T *rettv; /* * "hasmapto()" function */ -static void f_hasmapto(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_hasmapto(typval_T *argvars, typval_T *rettv) { char_u *name; char_u *mode; @@ -10828,9 +10388,7 @@ typval_T *rettv; /* * "histadd()" function */ -static void f_histadd(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_histadd(typval_T *argvars, typval_T *rettv) { int histype; char_u *str; @@ -10855,9 +10413,7 @@ typval_T *rettv; /* * "histdel()" function */ -static void f_histdel(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_histdel(typval_T *argvars, typval_T *rettv) { int n; char_u buf[NUMBUFLEN]; @@ -10883,9 +10439,7 @@ typval_T *rettv UNUSED; /* * "histget()" function */ -static void f_histget(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_histget(typval_T *argvars, typval_T *rettv) { int type; int idx; @@ -10909,9 +10463,7 @@ typval_T *rettv; /* * "histnr()" function */ -static void f_histnr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_histnr(typval_T *argvars, typval_T *rettv) { int i; @@ -10928,9 +10480,7 @@ typval_T *rettv; /* * "highlightID(name)" function */ -static void f_hlID(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_hlID(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0])); } @@ -10938,9 +10488,7 @@ typval_T *rettv; /* * "highlight_exists()" function */ -static void f_hlexists(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_hlexists(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0])); } @@ -10948,9 +10496,7 @@ typval_T *rettv; /* * "hostname()" function */ -static void f_hostname(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_hostname(typval_T *argvars, typval_T *rettv) { char_u hostname[256]; @@ -10962,9 +10508,7 @@ typval_T *rettv; /* * iconv() function */ -static void f_iconv(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_iconv(typval_T *argvars, typval_T *rettv) { char_u buf1[NUMBUFLEN]; char_u buf2[NUMBUFLEN]; @@ -10994,9 +10538,7 @@ typval_T *rettv; /* * "indent()" function */ -static void f_indent(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_indent(typval_T *argvars, typval_T *rettv) { linenr_T lnum; @@ -11010,9 +10552,7 @@ typval_T *rettv; /* * "index()" function */ -static void f_index(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_index(typval_T *argvars, typval_T *rettv) { list_T *l; listitem_T *item; @@ -11059,10 +10599,7 @@ static void get_user_input __ARGS((typval_T *argvars, typval_T *rettv, * prompt. The third argument to f_inputdialog() specifies the value to return * when the user cancels the prompt. */ -static void get_user_input(argvars, rettv, inputdialog) -typval_T *argvars; -typval_T *rettv; -int inputdialog; +static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog) { char_u *prompt = get_tv_string_chk(&argvars[0]); char_u *p = NULL; @@ -11154,9 +10691,7 @@ int inputdialog; * "input()" function * Also handles inputsecret() when inputsecret is set. */ -static void f_input(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_input(typval_T *argvars, typval_T *rettv) { get_user_input(argvars, rettv, FALSE); } @@ -11164,9 +10699,7 @@ typval_T *rettv; /* * "inputdialog()" function */ -static void f_inputdialog(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_inputdialog(typval_T *argvars, typval_T *rettv) { get_user_input(argvars, rettv, TRUE); } @@ -11174,9 +10707,7 @@ typval_T *rettv; /* * "inputlist()" function */ -static void f_inputlist(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_inputlist(typval_T *argvars, typval_T *rettv) { listitem_T *li; int selected; @@ -11217,9 +10748,7 @@ static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; /* * "inputrestore()" function */ -static void f_inputrestore(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_inputrestore(typval_T *argvars, typval_T *rettv) { if (ga_userinput.ga_len > 0) { --ga_userinput.ga_len; @@ -11235,9 +10764,7 @@ typval_T *rettv; /* * "inputsave()" function */ -static void f_inputsave(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_inputsave(typval_T *argvars, typval_T *rettv) { /* Add an entry to the stack of typeahead storage. */ if (ga_grow(&ga_userinput, 1) == OK) { @@ -11252,9 +10779,7 @@ typval_T *rettv; /* * "inputsecret()" function */ -static void f_inputsecret(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_inputsecret(typval_T *argvars, typval_T *rettv) { ++cmdline_star; ++inputsecret_flag; @@ -11266,9 +10791,7 @@ typval_T *rettv; /* * "insert()" function */ -static void f_insert(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_insert(typval_T *argvars, typval_T *rettv) { long before = 0; listitem_T *item; @@ -11303,9 +10826,7 @@ typval_T *rettv; /* * "invert(expr)" function */ -static void f_invert(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_invert(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL); } @@ -11313,9 +10834,7 @@ typval_T *rettv; /* * "isdirectory()" function */ -static void f_isdirectory(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_isdirectory(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); } @@ -11323,9 +10842,7 @@ typval_T *rettv; /* * "islocked()" function */ -static void f_islocked(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_islocked(typval_T *argvars, typval_T *rettv) { lval_T lv; char_u *end; @@ -11377,10 +10894,7 @@ static void dict_list __ARGS((typval_T *argvars, typval_T *rettv, int what)); * "what" == 1: list of values * "what" == 2: list of items */ -static void dict_list(argvars, rettv, what) -typval_T *argvars; -typval_T *rettv; -int what; +static void dict_list(typval_T *argvars, typval_T *rettv, int what) { list_T *l2; dictitem_T *di; @@ -11450,9 +10964,7 @@ int what; /* * "items(dict)" function */ -static void f_items(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_items(typval_T *argvars, typval_T *rettv) { dict_list(argvars, rettv, 2); } @@ -11460,9 +10972,7 @@ typval_T *rettv; /* * "join()" function */ -static void f_join(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_join(typval_T *argvars, typval_T *rettv) { garray_T ga; char_u *sep; @@ -11492,9 +11002,7 @@ typval_T *rettv; /* * "keys()" function */ -static void f_keys(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_keys(typval_T *argvars, typval_T *rettv) { dict_list(argvars, rettv, 0); } @@ -11502,9 +11010,7 @@ typval_T *rettv; /* * "last_buffer_nr()" function. */ -static void f_last_buffer_nr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv) { int n = 0; buf_T *buf; @@ -11519,9 +11025,7 @@ typval_T *rettv; /* * "len()" function */ -static void f_len(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_len(typval_T *argvars, typval_T *rettv) { switch (argvars[0].v_type) { case VAR_STRING: @@ -11543,10 +11047,7 @@ typval_T *rettv; static void libcall_common __ARGS((typval_T *argvars, typval_T *rettv, int type)); -static void libcall_common(argvars, rettv, type) -typval_T *argvars; -typval_T *rettv; -int type; +static void libcall_common(typval_T *argvars, typval_T *rettv, int type) { #ifdef FEAT_LIBCALL char_u *string_in; @@ -11586,9 +11087,7 @@ int type; /* * "libcall()" function */ -static void f_libcall(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_libcall(typval_T *argvars, typval_T *rettv) { libcall_common(argvars, rettv, VAR_STRING); } @@ -11596,9 +11095,7 @@ typval_T *rettv; /* * "libcallnr()" function */ -static void f_libcallnr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_libcallnr(typval_T *argvars, typval_T *rettv) { libcall_common(argvars, rettv, VAR_NUMBER); } @@ -11606,9 +11103,7 @@ typval_T *rettv; /* * "line(string)" function */ -static void f_line(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_line(typval_T *argvars, typval_T *rettv) { linenr_T lnum = 0; pos_T *fp; @@ -11623,9 +11118,7 @@ typval_T *rettv; /* * "line2byte(lnum)" function */ -static void f_line2byte(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_line2byte(typval_T *argvars, typval_T *rettv) { linenr_T lnum; @@ -11641,9 +11134,7 @@ typval_T *rettv; /* * "lispindent(lnum)" function */ -static void f_lispindent(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_lispindent(typval_T *argvars, typval_T *rettv) { pos_T pos; linenr_T lnum; @@ -11661,19 +11152,14 @@ typval_T *rettv; /* * "localtime()" function */ -static void f_localtime(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_localtime(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = (varnumber_T)time(NULL); } static void get_maparg __ARGS((typval_T *argvars, typval_T *rettv, int exact)); -static void get_maparg(argvars, rettv, exact) -typval_T *argvars; -typval_T *rettv; -int exact; +static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) { char_u *keys; char_u *which; @@ -11741,9 +11227,7 @@ int exact; /* * "log()" function */ -static void f_log(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_log(typval_T *argvars, typval_T *rettv) { float_T f; @@ -11757,9 +11241,7 @@ typval_T *rettv; /* * "log10()" function */ -static void f_log10(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_log10(typval_T *argvars, typval_T *rettv) { float_T f; @@ -11774,9 +11256,7 @@ typval_T *rettv; /* * "map()" function */ -static void f_map(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_map(typval_T *argvars, typval_T *rettv) { filter_map(argvars, rettv, TRUE); } @@ -11784,9 +11264,7 @@ typval_T *rettv; /* * "maparg()" function */ -static void f_maparg(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_maparg(typval_T *argvars, typval_T *rettv) { get_maparg(argvars, rettv, TRUE); } @@ -11794,9 +11272,7 @@ typval_T *rettv; /* * "mapcheck()" function */ -static void f_mapcheck(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_mapcheck(typval_T *argvars, typval_T *rettv) { get_maparg(argvars, rettv, FALSE); } @@ -11804,10 +11280,7 @@ typval_T *rettv; static void find_some_match __ARGS((typval_T *argvars, typval_T *rettv, int start)); -static void find_some_match(argvars, rettv, type) -typval_T *argvars; -typval_T *rettv; -int type; +static void find_some_match(typval_T *argvars, typval_T *rettv, int type) { char_u *str = NULL; char_u *expr = NULL; @@ -11960,9 +11433,7 @@ theend: /* * "match()" function */ -static void f_match(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_match(typval_T *argvars, typval_T *rettv) { find_some_match(argvars, rettv, 1); } @@ -11970,9 +11441,7 @@ typval_T *rettv; /* * "matchadd()" function */ -static void f_matchadd(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_matchadd(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ @@ -12003,9 +11472,7 @@ typval_T *rettv UNUSED; /* * "matcharg()" function */ -static void f_matcharg(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_matcharg(typval_T *argvars, typval_T *rettv) { if (rettv_list_alloc(rettv) == OK) { int id = get_tv_number(&argvars[0]); @@ -12027,9 +11494,7 @@ typval_T *rettv; /* * "matchdelete()" function */ -static void f_matchdelete(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_matchdelete(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = match_delete(curwin, (int)get_tv_number(&argvars[0]), TRUE); @@ -12038,9 +11503,7 @@ typval_T *rettv UNUSED; /* * "matchend()" function */ -static void f_matchend(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_matchend(typval_T *argvars, typval_T *rettv) { find_some_match(argvars, rettv, 0); } @@ -12048,9 +11511,7 @@ typval_T *rettv; /* * "matchlist()" function */ -static void f_matchlist(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_matchlist(typval_T *argvars, typval_T *rettv) { find_some_match(argvars, rettv, 3); } @@ -12058,19 +11519,14 @@ typval_T *rettv; /* * "matchstr()" function */ -static void f_matchstr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_matchstr(typval_T *argvars, typval_T *rettv) { find_some_match(argvars, rettv, 2); } static void max_min __ARGS((typval_T *argvars, typval_T *rettv, int domax)); -static void max_min(argvars, rettv, domax) -typval_T *argvars; -typval_T *rettv; -int domax; +static void max_min(typval_T *argvars, typval_T *rettv, int domax) { long n = 0; long i; @@ -12124,9 +11580,7 @@ int domax; /* * "max()" function */ -static void f_max(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_max(typval_T *argvars, typval_T *rettv) { max_min(argvars, rettv, TRUE); } @@ -12134,9 +11588,7 @@ typval_T *rettv; /* * "min()" function */ -static void f_min(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_min(typval_T *argvars, typval_T *rettv) { max_min(argvars, rettv, FALSE); } @@ -12147,9 +11599,7 @@ static int mkdir_recurse __ARGS((char_u *dir, int prot)); * Create the directory in which "dir" is located, and higher levels when * needed. */ -static int mkdir_recurse(dir, prot) -char_u *dir; -int prot; +static int mkdir_recurse(char_u *dir, int prot) { char_u *p; char_u *updir; @@ -12177,9 +11627,7 @@ int prot; /* * "mkdir()" function */ -static void f_mkdir(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_mkdir(typval_T *argvars, typval_T *rettv) { char_u *dir; char_u buf[NUMBUFLEN]; @@ -12211,9 +11659,7 @@ typval_T *rettv; /* * "mode()" function */ -static void f_mode(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_mode(typval_T *argvars, typval_T *rettv) { char_u buf[3]; @@ -12268,9 +11714,7 @@ typval_T *rettv; /* * "nextnonblank()" function */ -static void f_nextnonblank(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_nextnonblank(typval_T *argvars, typval_T *rettv) { linenr_T lnum; @@ -12288,9 +11732,7 @@ typval_T *rettv; /* * "nr2char()" function */ -static void f_nr2char(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_nr2char(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; @@ -12314,9 +11756,7 @@ typval_T *rettv; /* * "or(expr, expr)" function */ -static void f_or(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_or(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | get_tv_number_chk(&argvars[1], NULL); @@ -12325,9 +11765,7 @@ typval_T *rettv; /* * "pathshorten()" function */ -static void f_pathshorten(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_pathshorten(typval_T *argvars, typval_T *rettv) { char_u *p; @@ -12346,9 +11784,7 @@ typval_T *rettv; /* * "pow()" function */ -static void f_pow(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_pow(typval_T *argvars, typval_T *rettv) { float_T fx, fy; @@ -12363,9 +11799,7 @@ typval_T *rettv; /* * "prevnonblank()" function */ -static void f_prevnonblank(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_prevnonblank(typval_T *argvars, typval_T *rettv) { linenr_T lnum; @@ -12389,9 +11823,7 @@ static va_list ap; /* * "printf()" function */ -static void f_printf(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_printf(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -12422,9 +11854,7 @@ typval_T *rettv; /* * "pumvisible()" function */ -static void f_pumvisible(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_pumvisible(typval_T *argvars, typval_T *rettv) { if (pum_visible()) rettv->vval.v_number = 1; @@ -12435,9 +11865,7 @@ typval_T *rettv UNUSED; /* * "range()" function */ -static void f_range(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_range(typval_T *argvars, typval_T *rettv) { long start; long end; @@ -12473,9 +11901,7 @@ typval_T *rettv; /* * "readfile()" function */ -static void f_readfile(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_readfile(typval_T *argvars, typval_T *rettv) { int binary = FALSE; int failed = FALSE; @@ -12686,9 +12112,7 @@ proftime_T *tm; /* * "reltime()" function */ -static void f_reltime(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_reltime(typval_T *argvars, typval_T *rettv) { proftime_T res; proftime_T start; @@ -12721,9 +12145,7 @@ typval_T *rettv UNUSED; /* * "reltimestr()" function */ -static void f_reltimestr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_reltimestr(typval_T *argvars, typval_T *rettv) { proftime_T tm; @@ -12738,9 +12160,7 @@ typval_T *rettv; /* * "remote_expr()" function */ -static void f_remote_expr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_remote_expr(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -12749,22 +12169,16 @@ typval_T *rettv; /* * "remote_foreground()" function */ -static void f_remote_foreground(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_remote_foreground(typval_T *argvars, typval_T *rettv) { } -static void f_remote_peek(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_remote_peek(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = -1; } -static void f_remote_read(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_remote_read(typval_T *argvars, typval_T *rettv) { char_u *r = NULL; @@ -12775,9 +12189,7 @@ typval_T *rettv; /* * "remote_send()" function */ -static void f_remote_send(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_remote_send(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; @@ -12786,9 +12198,7 @@ typval_T *rettv; /* * "remove()" function */ -static void f_remove(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_remove(typval_T *argvars, typval_T *rettv) { list_T *l; listitem_T *item, *item2; @@ -12871,9 +12281,7 @@ typval_T *rettv; /* * "rename({from}, {to})" function */ -static void f_rename(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_rename(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; @@ -12887,9 +12295,7 @@ typval_T *rettv; /* * "repeat()" function */ -static void f_repeat(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_repeat(typval_T *argvars, typval_T *rettv) { char_u *p; int n; @@ -12929,9 +12335,7 @@ typval_T *rettv; /* * "resolve()" function */ -static void f_resolve(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_resolve(typval_T *argvars, typval_T *rettv) { char_u *p; #ifdef HAVE_READLINK @@ -13116,9 +12520,7 @@ fail: /* * "reverse({list})" function */ -static void f_reverse(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_reverse(typval_T *argvars, typval_T *rettv) { list_T *l; listitem_T *li, *ni; @@ -13157,9 +12559,7 @@ static int get_search_arg __ARGS((typval_T *varp, int *flagsp)); * Possibly sets "p_ws". * Returns BACKWARD, FORWARD or zero (for an error). */ -static int get_search_arg(varp, flagsp) -typval_T *varp; -int *flagsp; +static int get_search_arg(typval_T *varp, int *flagsp) { int dir = FORWARD; char_u *flags; @@ -13203,10 +12603,7 @@ int *flagsp; /* * Shared by search() and searchpos() functions */ -static int search_cmn(argvars, match_pos, flagsp) -typval_T *argvars; -pos_T *match_pos; -int *flagsp; +static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) { int flags; char_u *pat; @@ -13294,8 +12691,7 @@ theend: /* * round() is not in C90, use ceil() or floor() instead. */ -float_T vim_round(f) -float_T f; +float_T vim_round(float_T f) { return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); } @@ -13303,9 +12699,7 @@ float_T f; /* * "round({float})" function */ -static void f_round(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_round(typval_T *argvars, typval_T *rettv) { float_T f; @@ -13319,9 +12713,7 @@ typval_T *rettv; /* * "screenattr()" function */ -static void f_screenattr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_screenattr(typval_T *argvars, typval_T *rettv) { int row; int col; @@ -13340,9 +12732,7 @@ typval_T *rettv; /* * "screenchar()" function */ -static void f_screenchar(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_screenchar(typval_T *argvars, typval_T *rettv) { int row; int col; @@ -13369,9 +12759,7 @@ typval_T *rettv; * * First column is 1 to be consistent with virtcol(). */ -static void f_screencol(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_screencol(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = screen_screencol() + 1; } @@ -13379,9 +12767,7 @@ typval_T *rettv; /* * "screenrow()" function */ -static void f_screenrow(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_screenrow(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = screen_screenrow() + 1; } @@ -13389,9 +12775,7 @@ typval_T *rettv; /* * "search()" function */ -static void f_search(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_search(typval_T *argvars, typval_T *rettv) { int flags = 0; @@ -13401,9 +12785,7 @@ typval_T *rettv; /* * "searchdecl()" function */ -static void f_searchdecl(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_searchdecl(typval_T *argvars, typval_T *rettv) { int locally = 1; int thisblock = 0; @@ -13426,9 +12808,7 @@ typval_T *rettv; /* * Used by searchpair() and searchpairpos() */ -static int searchpair_cmn(argvars, match_pos) -typval_T *argvars; -pos_T *match_pos; +static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) { char_u *spat, *mpat, *epat; char_u *skip; @@ -13499,9 +12879,7 @@ theend: /* * "searchpair()" function */ -static void f_searchpair(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_searchpair(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = searchpair_cmn(argvars, NULL); } @@ -13509,9 +12887,7 @@ typval_T *rettv; /* * "searchpairpos()" function */ -static void f_searchpairpos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_searchpairpos(typval_T *argvars, typval_T *rettv) { pos_T match_pos; int lnum = 0; @@ -13534,17 +12910,18 @@ typval_T *rettv; * Used by searchpair(), see its documentation for the details. * Returns 0 or -1 for no match, */ -long do_searchpair(spat, mpat, epat, dir, skip, flags, match_pos, - lnum_stop, time_limit) -char_u *spat; /* start pattern */ -char_u *mpat; /* middle pattern */ -char_u *epat; /* end pattern */ -int dir; /* BACKWARD or FORWARD */ -char_u *skip; /* skip expression */ -int flags; /* SP_SETPCMARK and other SP_ values */ -pos_T *match_pos; -linenr_T lnum_stop; /* stop at this line if not zero */ -long time_limit UNUSED; /* stop after this many msec */ +long +do_searchpair ( + char_u *spat, /* start pattern */ + char_u *mpat, /* middle pattern */ + char_u *epat, /* end pattern */ + int dir, /* BACKWARD or FORWARD */ + char_u *skip, /* skip expression */ + int flags, /* SP_SETPCMARK and other SP_ values */ + pos_T *match_pos, + linenr_T lnum_stop, /* stop at this line if not zero */ + long time_limit /* stop after this many msec */ +) { char_u *save_cpo; char_u *pat, *pat2 = NULL, *pat3 = NULL; @@ -13679,9 +13056,7 @@ theend: /* * "searchpos()" function */ -static void f_searchpos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_searchpos(typval_T *argvars, typval_T *rettv) { pos_T match_pos; int lnum = 0; @@ -13705,16 +13080,12 @@ typval_T *rettv; } -static void f_server2client(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_server2client(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = -1; } -static void f_serverlist(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_serverlist(typval_T *argvars, typval_T *rettv) { char_u *r = NULL; @@ -13725,9 +13096,7 @@ typval_T *rettv; /* * "setbufvar()" function */ -static void f_setbufvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv UNUSED; +static void f_setbufvar(typval_T *argvars, typval_T *rettv) { buf_T *buf; aco_save_T aco; @@ -13774,9 +13143,7 @@ typval_T *rettv UNUSED; /* * "setcmdpos()" function */ -static void f_setcmdpos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setcmdpos(typval_T *argvars, typval_T *rettv) { int pos = (int)get_tv_number(&argvars[0]) - 1; @@ -13787,9 +13154,7 @@ typval_T *rettv; /* * "setline()" function */ -static void f_setline(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setline(typval_T *argvars, typval_T *rettv) { linenr_T lnum; char_u *line = NULL; @@ -13857,11 +13222,7 @@ static void set_qf_ll_list __ARGS((win_T *wp, typval_T *list_arg, typval_T * /* * Used by "setqflist()" and "setloclist()" functions */ -static void set_qf_ll_list(wp, list_arg, action_arg, rettv) -win_T *wp UNUSED; -typval_T *list_arg UNUSED; -typval_T *action_arg UNUSED; -typval_T *rettv; +static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv) { char_u *act; int action = ' '; @@ -13890,9 +13251,7 @@ typval_T *rettv; /* * "setloclist()" function */ -static void f_setloclist(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setloclist(typval_T *argvars, typval_T *rettv) { win_T *win; @@ -13906,9 +13265,7 @@ typval_T *rettv; /* * "setmatches()" function */ -static void f_setmatches(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_setmatches(typval_T *argvars, typval_T *rettv) { list_T *l; listitem_T *li; @@ -13957,9 +13314,7 @@ typval_T *rettv UNUSED; /* * "setpos()" function */ -static void f_setpos(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setpos(typval_T *argvars, typval_T *rettv) { pos_T pos; int fnum; @@ -13992,9 +13347,7 @@ typval_T *rettv; /* * "setqflist()" function */ -static void f_setqflist(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setqflist(typval_T *argvars, typval_T *rettv) { set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv); } @@ -14002,9 +13355,7 @@ typval_T *rettv; /* * "setreg()" function */ -static void f_setreg(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setreg(typval_T *argvars, typval_T *rettv) { int regname; char_u *strregname; @@ -14065,9 +13416,7 @@ typval_T *rettv; /* * "settabvar()" function */ -static void f_settabvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_settabvar(typval_T *argvars, typval_T *rettv) { tabpage_T *save_curtab; tabpage_T *tp; @@ -14106,9 +13455,7 @@ typval_T *rettv; /* * "settabwinvar()" function */ -static void f_settabwinvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_settabwinvar(typval_T *argvars, typval_T *rettv) { setwinvar(argvars, rettv, 1); } @@ -14116,9 +13463,7 @@ typval_T *rettv; /* * "setwinvar()" function */ -static void f_setwinvar(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_setwinvar(typval_T *argvars, typval_T *rettv) { setwinvar(argvars, rettv, 0); } @@ -14127,10 +13472,7 @@ typval_T *rettv; * "setwinvar()" and "settabwinvar()" functions */ -static void setwinvar(argvars, rettv, off) -typval_T *argvars; -typval_T *rettv UNUSED; -int off; +static void setwinvar(typval_T *argvars, typval_T *rettv, int off) { win_T *win; win_T *save_curwin; @@ -14182,9 +13524,7 @@ int off; /* * "sha256({string})" function */ -static void f_sha256(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_sha256(typval_T *argvars, typval_T *rettv) { char_u *p; @@ -14197,9 +13537,7 @@ typval_T *rettv; /* * "shellescape({string})" function */ -static void f_shellescape(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_shellescape(typval_T *argvars, typval_T *rettv) { rettv->vval.v_string = vim_strsave_shellescape( get_tv_string(&argvars[0]), non_zero_arg(&argvars[1])); @@ -14209,9 +13547,7 @@ typval_T *rettv; /* * shiftwidth() function */ -static void f_shiftwidth(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_shiftwidth(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = get_sw_value(curbuf); } @@ -14219,9 +13555,7 @@ typval_T *rettv; /* * "simplify()" function */ -static void f_simplify(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_simplify(typval_T *argvars, typval_T *rettv) { char_u *p; @@ -14234,9 +13568,7 @@ typval_T *rettv; /* * "sin()" function */ -static void f_sin(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_sin(typval_T *argvars, typval_T *rettv) { float_T f; @@ -14250,9 +13582,7 @@ typval_T *rettv; /* * "sinh()" function */ -static void f_sinh(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_sinh(typval_T *argvars, typval_T *rettv) { float_T f; @@ -14277,9 +13607,7 @@ static int item_compare_func_err; /* * Compare functions for f_sort() below. */ -static int item_compare(s1, s2) -const void *s1; -const void *s2; +static int item_compare(const void *s1, const void *s2) { char_u *p1, *p2; char_u *tofree1, *tofree2; @@ -14302,9 +13630,7 @@ const void *s2; return res; } -static int item_compare2(s1, s2) -const void *s1; -const void *s2; +static int item_compare2(const void *s1, const void *s2) { int res; typval_T rettv; @@ -14340,9 +13666,7 @@ const void *s2; /* * "sort({list})" function */ -static void f_sort(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_sort(typval_T *argvars, typval_T *rettv) { list_T *l; listitem_T *li; @@ -14429,9 +13753,7 @@ typval_T *rettv; /* * "soundfold({word})" function */ -static void f_soundfold(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_soundfold(typval_T *argvars, typval_T *rettv) { char_u *s; @@ -14443,9 +13765,7 @@ typval_T *rettv; /* * "spellbadword()" function */ -static void f_spellbadword(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_spellbadword(typval_T *argvars, typval_T *rettv) { char_u *word = (char_u *)""; hlf_T attr = HLF_COUNT; @@ -14488,9 +13808,7 @@ typval_T *rettv; /* * "spellsuggest()" function */ -static void f_spellsuggest(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_spellsuggest(typval_T *argvars, typval_T *rettv) { char_u *str; int typeerr = FALSE; @@ -14536,9 +13854,7 @@ typval_T *rettv; } } -static void f_split(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_split(typval_T *argvars, typval_T *rettv) { char_u *str; char_u *end; @@ -14611,9 +13927,7 @@ typval_T *rettv; /* * "sqrt()" function */ -static void f_sqrt(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_sqrt(typval_T *argvars, typval_T *rettv) { float_T f; @@ -14627,9 +13941,7 @@ typval_T *rettv; /* * "str2float()" function */ -static void f_str2float(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_str2float(typval_T *argvars, typval_T *rettv) { char_u *p = skipwhite(get_tv_string(&argvars[0])); @@ -14642,9 +13954,7 @@ typval_T *rettv; /* * "str2nr()" function */ -static void f_str2nr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_str2nr(typval_T *argvars, typval_T *rettv) { int base = 10; char_u *p; @@ -14669,9 +13979,7 @@ typval_T *rettv; /* * "strftime({format}[, {time}])" function */ -static void f_strftime(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strftime(typval_T *argvars, typval_T *rettv) { char_u result_buf[256]; struct tm *curtime; @@ -14722,9 +14030,7 @@ typval_T *rettv; /* * "stridx()" function */ -static void f_stridx(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_stridx(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; char_u *needle; @@ -14757,9 +14063,7 @@ typval_T *rettv; /* * "string()" function */ -static void f_string(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_string(typval_T *argvars, typval_T *rettv) { char_u *tofree; char_u numbuf[NUMBUFLEN]; @@ -14774,9 +14078,7 @@ typval_T *rettv; /* * "strlen()" function */ -static void f_strlen(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strlen(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = (varnumber_T)(STRLEN( get_tv_string(&argvars[0]))); @@ -14785,9 +14087,7 @@ typval_T *rettv; /* * "strchars()" function */ -static void f_strchars(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strchars(typval_T *argvars, typval_T *rettv) { char_u *s = get_tv_string(&argvars[0]); varnumber_T len = 0; @@ -14802,9 +14102,7 @@ typval_T *rettv; /* * "strdisplaywidth()" function */ -static void f_strdisplaywidth(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv) { char_u *s = get_tv_string(&argvars[0]); int col = 0; @@ -14818,9 +14116,7 @@ typval_T *rettv; /* * "strwidth()" function */ -static void f_strwidth(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strwidth(typval_T *argvars, typval_T *rettv) { char_u *s = get_tv_string(&argvars[0]); @@ -14832,9 +14128,7 @@ typval_T *rettv; /* * "strpart()" function */ -static void f_strpart(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strpart(typval_T *argvars, typval_T *rettv) { char_u *p; int n; @@ -14874,9 +14168,7 @@ typval_T *rettv; /* * "strridx()" function */ -static void f_strridx(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strridx(typval_T *argvars, typval_T *rettv) { char_u buf[NUMBUFLEN]; char_u *needle; @@ -14922,9 +14214,7 @@ typval_T *rettv; /* * "strtrans()" function */ -static void f_strtrans(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_strtrans(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = transstr(get_tv_string(&argvars[0])); @@ -14933,9 +14223,7 @@ typval_T *rettv; /* * "submatch()" function */ -static void f_submatch(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_submatch(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = @@ -14945,9 +14233,7 @@ typval_T *rettv; /* * "substitute()" function */ -static void f_substitute(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_substitute(typval_T *argvars, typval_T *rettv) { char_u patbuf[NUMBUFLEN]; char_u subbuf[NUMBUFLEN]; @@ -14968,9 +14254,7 @@ typval_T *rettv; /* * "synID(lnum, col, trans)" function */ -static void f_synID(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_synID(typval_T *argvars, typval_T *rettv) { int id = 0; long lnum; @@ -14992,9 +14276,7 @@ typval_T *rettv; /* * "synIDattr(id, what [, mode])" function */ -static void f_synIDattr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_synIDattr(typval_T *argvars, typval_T *rettv) { char_u *p = NULL; int id; @@ -15071,9 +14353,7 @@ typval_T *rettv; /* * "synIDtrans(id)" function */ -static void f_synIDtrans(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_synIDtrans(typval_T *argvars, typval_T *rettv) { int id; @@ -15090,9 +14370,7 @@ typval_T *rettv; /* * "synconcealed(lnum, col)" function */ -static void f_synconcealed(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_synconcealed(typval_T *argvars, typval_T *rettv) { long lnum; long col; @@ -15141,9 +14419,7 @@ typval_T *rettv; /* * "synstack(lnum, col)" function */ -static void f_synstack(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_synstack(typval_T *argvars, typval_T *rettv) { long lnum; long col; @@ -15173,9 +14449,7 @@ typval_T *rettv; /* * "system()" function */ -static void f_system(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_system(typval_T *argvars, typval_T *rettv) { char_u *res = NULL; char_u *p; @@ -15259,9 +14533,7 @@ done: /* * "tabpagebuflist()" function */ -static void f_tabpagebuflist(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv) { tabpage_T *tp; win_T *wp = NULL; @@ -15285,9 +14557,7 @@ typval_T *rettv UNUSED; /* * "tabpagenr()" function */ -static void f_tabpagenr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_tabpagenr(typval_T *argvars, typval_T *rettv) { int nr = 1; char_u *arg; @@ -15312,9 +14582,7 @@ static int get_winnr __ARGS((tabpage_T *tp, typval_T *argvar)); /* * Common code for tabpagewinnr() and winnr(). */ -static int get_winnr(tp, argvar) -tabpage_T *tp; -typval_T *argvar; +static int get_winnr(tabpage_T *tp, typval_T *argvar) { win_T *twin; int nr = 1; @@ -15354,9 +14622,7 @@ typval_T *argvar; /* * "tabpagewinnr()" function */ -static void f_tabpagewinnr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv) { int nr = 1; tabpage_T *tp; @@ -15373,9 +14639,7 @@ typval_T *rettv; /* * "tagfiles()" function */ -static void f_tagfiles(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_tagfiles(typval_T *argvars, typval_T *rettv) { char_u *fname; tagname_T tn; @@ -15398,9 +14662,7 @@ typval_T *rettv; /* * "taglist()" function */ -static void f_taglist(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_taglist(typval_T *argvars, typval_T *rettv) { char_u *tag_pattern; @@ -15417,9 +14679,7 @@ typval_T *rettv; /* * "tempname()" function */ -static void f_tempname(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_tempname(typval_T *argvars, typval_T *rettv) { static int x = 'A'; @@ -15442,9 +14702,7 @@ typval_T *rettv; /* * "test(list)" function: Just checking the walls... */ -static void f_test(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_test(typval_T *argvars, typval_T *rettv) { /* Used for unit testing. Change the code below to your liking. */ } @@ -15452,9 +14710,7 @@ typval_T *rettv UNUSED; /* * "tan()" function */ -static void f_tan(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_tan(typval_T *argvars, typval_T *rettv) { float_T f; @@ -15468,9 +14724,7 @@ typval_T *rettv; /* * "tanh()" function */ -static void f_tanh(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_tanh(typval_T *argvars, typval_T *rettv) { float_T f; @@ -15484,9 +14738,7 @@ typval_T *rettv; /* * "tolower(string)" function */ -static void f_tolower(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_tolower(typval_T *argvars, typval_T *rettv) { char_u *p; @@ -15520,9 +14772,7 @@ typval_T *rettv; /* * "toupper(string)" function */ -static void f_toupper(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_toupper(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); @@ -15531,9 +14781,7 @@ typval_T *rettv; /* * "tr(string, fromstr, tostr)" function */ -static void f_tr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_tr(typval_T *argvars, typval_T *rettv) { char_u *in_str; char_u *fromstr; @@ -15634,9 +14882,7 @@ error: /* * "trunc({float})" function */ -static void f_trunc(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_trunc(typval_T *argvars, typval_T *rettv) { float_T f; @@ -15651,9 +14897,7 @@ typval_T *rettv; /* * "type(expr)" function */ -static void f_type(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_type(typval_T *argvars, typval_T *rettv) { int n; @@ -15672,9 +14916,7 @@ typval_T *rettv; /* * "undofile(name)" function */ -static void f_undofile(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_undofile(typval_T *argvars, typval_T *rettv) { rettv->v_type = VAR_STRING; { @@ -15696,9 +14938,7 @@ typval_T *rettv; /* * "undotree()" function */ -static void f_undotree(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_undotree(typval_T *argvars, typval_T *rettv) { if (rettv_dict_alloc(rettv) == OK) { dict_T *dict = rettv->vval.v_dict; @@ -15723,9 +14963,7 @@ typval_T *rettv; /* * "values(dict)" function */ -static void f_values(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_values(typval_T *argvars, typval_T *rettv) { dict_list(argvars, rettv, 1); } @@ -15733,9 +14971,7 @@ typval_T *rettv; /* * "virtcol(string)" function */ -static void f_virtcol(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_virtcol(typval_T *argvars, typval_T *rettv) { colnr_T vcol = 0; pos_T *fp; @@ -15754,9 +14990,7 @@ typval_T *rettv; /* * "visualmode()" function */ -static void f_visualmode(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_visualmode(typval_T *argvars, typval_T *rettv) { char_u str[2]; @@ -15773,9 +15007,7 @@ typval_T *rettv UNUSED; /* * "wildmenumode()" function */ -static void f_wildmenumode(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv UNUSED; +static void f_wildmenumode(typval_T *argvars, typval_T *rettv) { if (wild_menu_showing) rettv->vval.v_number = 1; @@ -15784,9 +15016,7 @@ typval_T *rettv UNUSED; /* * "winbufnr(nr)" function */ -static void f_winbufnr(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_winbufnr(typval_T *argvars, typval_T *rettv) { win_T *wp; @@ -15800,9 +15030,7 @@ typval_T *rettv; /* * "wincol()" function */ -static void f_wincol(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_wincol(typval_T *argvars, typval_T *rettv) { validate_cursor(); rettv->vval.v_number = curwin->w_wcol + 1; @@ -15811,9 +15039,7 @@ typval_T *rettv; /* * "winheight(nr)" function */ -static void f_winheight(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_winheight(typval_T *argvars, typval_T *rettv) { win_T *wp; @@ -15827,9 +15053,7 @@ typval_T *rettv; /* * "winline()" function */ -static void f_winline(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_winline(typval_T *argvars, typval_T *rettv) { validate_cursor(); rettv->vval.v_number = curwin->w_wrow + 1; @@ -15838,9 +15062,7 @@ typval_T *rettv; /* * "winnr()" function */ -static void f_winnr(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_winnr(typval_T *argvars, typval_T *rettv) { int nr = 1; @@ -15851,9 +15073,7 @@ typval_T *rettv; /* * "winrestcmd()" function */ -static void f_winrestcmd(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_winrestcmd(typval_T *argvars, typval_T *rettv) { win_T *wp; int winnr = 1; @@ -15877,9 +15097,7 @@ typval_T *rettv; /* * "winrestview()" function */ -static void f_winrestview(argvars, rettv) -typval_T *argvars; -typval_T *rettv UNUSED; +static void f_winrestview(typval_T *argvars, typval_T *rettv) { dict_T *dict; @@ -15914,9 +15132,7 @@ typval_T *rettv UNUSED; /* * "winsaveview()" function */ -static void f_winsaveview(argvars, rettv) -typval_T *argvars UNUSED; -typval_T *rettv; +static void f_winsaveview(typval_T *argvars, typval_T *rettv) { dict_T *dict; @@ -15939,9 +15155,7 @@ typval_T *rettv; /* * "winwidth(nr)" function */ -static void f_winwidth(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_winwidth(typval_T *argvars, typval_T *rettv) { win_T *wp; @@ -15955,9 +15169,7 @@ typval_T *rettv; /* * "writefile()" function */ -static void f_writefile(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_writefile(typval_T *argvars, typval_T *rettv) { int binary = FALSE; char_u *fname; @@ -16019,9 +15231,7 @@ typval_T *rettv; /* * "xor(expr, expr)" function */ -static void f_xor(argvars, rettv) -typval_T *argvars; -typval_T *rettv; +static void f_xor(typval_T *argvars, typval_T *rettv) { rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) ^ get_tv_number_chk(&argvars[1], NULL); @@ -16032,10 +15242,12 @@ typval_T *rettv; * Translate a String variable into a position. * Returns NULL when there is an error. */ -static pos_T * var2fpos(varp, dollar_lnum, fnum) -typval_T *varp; -int dollar_lnum; /* TRUE when $ is last line */ -int *fnum; /* set to fnum for '0, 'A, etc. */ +static pos_T * +var2fpos ( + typval_T *varp, + int dollar_lnum, /* TRUE when $ is last line */ + int *fnum /* set to fnum for '0, 'A, etc. */ +) { char_u *name; static pos_T pos; @@ -16134,10 +15346,7 @@ int *fnum; /* set to fnum for '0, 'A, etc. */ * Return FAIL when conversion is not possible, doesn't check the position for * validity. */ -static int list2fpos(arg, posp, fnump) -typval_T *arg; -pos_T *posp; -int *fnump; +static int list2fpos(typval_T *arg, pos_T *posp, int *fnump) { list_T *l = arg->vval.v_list; long i = 0; @@ -16184,8 +15393,7 @@ int *fnump; * Advance "arg" to the first character after the name. * Return 0 for error. */ -static int get_env_len(arg) -char_u **arg; +static int get_env_len(char_u **arg) { char_u *p; int len; @@ -16205,8 +15413,7 @@ char_u **arg; * "arg" is advanced to the first non-white character after the name. * Return 0 if something is wrong. */ -static int get_id_len(arg) -char_u **arg; +static int get_id_len(char_u **arg) { char_u *p; int len; @@ -16232,11 +15439,7 @@ char_u **arg; * If the name contains 'magic' {}'s, expand them and return the * expanded name in an allocated string via 'alias' - caller must free. */ -static int get_name_len(arg, alias, evaluate, verbose) -char_u **arg; -char_u **alias; -int evaluate; -int verbose; +static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose) { int len; char_u *p; @@ -16298,11 +15501,7 @@ int verbose; * Return a pointer to just after the name. Equal to "arg" if there is no * valid name. */ -static char_u * find_name_end(arg, expr_start, expr_end, flags) -char_u *arg; -char_u **expr_start; -char_u **expr_end; -int flags; +static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags) { int mb_nest = 0; int br_nest = 0; @@ -16374,11 +15573,7 @@ int flags; * Returns a new allocated string, which the caller must free. * Returns NULL for failure. */ -static char_u * make_expanded_name(in_start, expr_start, expr_end, in_end) -char_u *in_start; -char_u *expr_start; -char_u *expr_end; -char_u *in_end; +static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end) { char_u c1; char_u *retval = NULL; @@ -16426,8 +15621,7 @@ char_u *in_end; * Return TRUE if character "c" can be used in a variable or function name. * Does not include '{' or '}' for magic braces. */ -static int eval_isnamec(c) -int c; +static int eval_isnamec(int c) { return ASCII_ISALNUM(c) || c == '_' || c == ':' || c == AUTOLOAD_CHAR; } @@ -16436,8 +15630,7 @@ int c; * Return TRUE if character "c" can be used as the first character in a * variable or function name (excluding '{' and '}'). */ -static int eval_isnamec1(c) -int c; +static int eval_isnamec1(int c) { return ASCII_ISALPHA(c) || c == '_'; } @@ -16445,9 +15638,7 @@ int c; /* * Set number v: variable to "val". */ -void set_vim_var_nr(idx, val) -int idx; -long val; +void set_vim_var_nr(int idx, long val) { vimvars[idx].vv_nr = val; } @@ -16455,8 +15646,7 @@ long val; /* * Get number v: variable value. */ -long get_vim_var_nr(idx) -int idx; +long get_vim_var_nr(int idx) { return vimvars[idx].vv_nr; } @@ -16464,8 +15654,7 @@ int idx; /* * Get string v: variable value. Uses a static buffer, can only be used once. */ -char_u * get_vim_var_str(idx) -int idx; +char_u *get_vim_var_str(int idx) { return get_tv_string(&vimvars[idx].vv_tv); } @@ -16474,8 +15663,7 @@ int idx; * Get List v: variable value. Caller must take care of reference count when * needed. */ -list_T * get_vim_var_list(idx) -int idx; +list_T *get_vim_var_list(int idx) { return vimvars[idx].vv_list; } @@ -16483,8 +15671,7 @@ int idx; /* * Set v:char to character "c". */ -void set_vim_var_char(c) -int c; +void set_vim_var_char(int c) { char_u buf[MB_MAXBYTES + 1]; @@ -16501,10 +15688,7 @@ int c; * Set v:count to "count" and v:count1 to "count1". * When "set_prevcount" is TRUE first set v:prevcount from v:count. */ -void set_vcount(count, count1, set_prevcount) -long count; -long count1; -int set_prevcount; +void set_vcount(long count, long count1, int set_prevcount) { if (set_prevcount) vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr; @@ -16515,10 +15699,12 @@ int set_prevcount; /* * Set string v: variable to a copy of "val". */ -void set_vim_var_string(idx, val, len) -int idx; -char_u *val; -int len; /* length of "val" to use or -1 (whole string) */ +void +set_vim_var_string ( + int idx, + char_u *val, + int len /* length of "val" to use or -1 (whole string) */ +) { /* Need to do this (at least) once, since we can't initialize a union. * Will always be invoked when "v:progname" is set. */ @@ -16536,9 +15722,7 @@ int len; /* length of "val" to use or -1 (whole string) */ /* * Set List v: variable to "val". */ -void set_vim_var_list(idx, val) -int idx; -list_T *val; +void set_vim_var_list(int idx, list_T *val) { list_unref(vimvars[idx].vv_list); vimvars[idx].vv_list = val; @@ -16549,8 +15733,7 @@ list_T *val; /* * Set v:register if needed. */ -void set_reg_var(c) -int c; +void set_reg_var(int c) { char_u regname; @@ -16569,8 +15752,7 @@ int c; * Must always be called in pairs to save and restore v:exception! Does not * take care of memory allocations. */ -char_u * v_exception(oldval) -char_u *oldval; +char_u *v_exception(char_u *oldval) { if (oldval == NULL) return vimvars[VV_EXCEPTION].vv_str; @@ -16585,8 +15767,7 @@ char_u *oldval; * Must always be called in pairs to save and restore v:throwpoint! Does not * take care of memory allocations. */ -char_u * v_throwpoint(oldval) -char_u *oldval; +char_u *v_throwpoint(char_u *oldval) { if (oldval == NULL) return vimvars[VV_THROWPOINT].vv_str; @@ -16601,9 +15782,7 @@ char_u *oldval; * If "oldarg" != NULL, restore the value to "oldarg" and return NULL. * Must always be called in pairs! */ -char_u * set_cmdarg(eap, oldarg) -exarg_T *eap; -char_u *oldarg; +char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) { char_u *oldval; char_u *newval; @@ -16667,12 +15846,14 @@ char_u *oldarg; * Get the value of internal variable "name". * Return OK or FAIL. */ -static int get_var_tv(name, len, rettv, verbose, no_autoload) -char_u *name; -int len; /* length of "name" */ -typval_T *rettv; /* NULL when only checking existence */ -int verbose; /* may give error message */ -int no_autoload; /* do not use script autoloading */ +static int +get_var_tv ( + char_u *name, + int len, /* length of "name" */ + typval_T *rettv, /* NULL when only checking existence */ + int verbose, /* may give error message */ + int no_autoload /* do not use script autoloading */ +) { int ret = OK; typval_T *tv = NULL; @@ -16718,11 +15899,13 @@ int no_autoload; /* do not use script autoloading */ * Also handle function call with Funcref variable: func(expr) * Can all be combined: dict.func(expr)[idx]['func'](expr) */ -static int handle_subscript(arg, rettv, evaluate, verbose) -char_u **arg; -typval_T *rettv; -int evaluate; /* do more than finding the end */ -int verbose; /* give error messages */ +static int +handle_subscript ( + char_u **arg, + typval_T *rettv, + int evaluate, /* do more than finding the end */ + int verbose /* give error messages */ +) { int ret = OK; dict_T *selfdict = NULL; @@ -16786,7 +15969,7 @@ int verbose; /* give error messages */ * Allocate memory for a variable type-value, and make it empty (0 or NULL * value). */ -static typval_T * alloc_tv() { +static typval_T *alloc_tv(void) { return (typval_T *)alloc_clear((unsigned)sizeof(typval_T)); } @@ -16795,8 +15978,7 @@ static typval_T * alloc_tv() { * The string "s" must have been allocated, it is consumed. * Return NULL for out of memory, the variable otherwise. */ -static typval_T * alloc_string_tv(s) -char_u *s; +static typval_T *alloc_string_tv(char_u *s) { typval_T *rettv; @@ -16812,8 +15994,7 @@ char_u *s; /* * Free the memory for a variable type-value. */ -void free_tv(varp) -typval_T *varp; +void free_tv(typval_T *varp) { if (varp != NULL) { switch (varp->v_type) { @@ -16844,8 +16025,7 @@ typval_T *varp; /* * Free the memory for a variable value and set the value to NULL or 0. */ -void clear_tv(varp) -typval_T *varp; +void clear_tv(typval_T *varp) { if (varp != NULL) { switch (varp->v_type) { @@ -16882,8 +16062,7 @@ typval_T *varp; /* * Set the value of a variable to NULL without freeing items. */ -static void init_tv(varp) -typval_T *varp; +static void init_tv(typval_T *varp) { if (varp != NULL) vim_memset(varp, 0, sizeof(typval_T)); @@ -16897,17 +16076,14 @@ typval_T *varp; * caller of incompatible types: it sets *denote to TRUE if "denote" * is not NULL or returns -1 otherwise. */ -static long get_tv_number(varp) -typval_T *varp; +static long get_tv_number(typval_T *varp) { int error = FALSE; return get_tv_number_chk(varp, &error); /* return 0L on error */ } -long get_tv_number_chk(varp, denote) -typval_T *varp; -int *denote; +long get_tv_number_chk(typval_T *varp, int *denote) { long n = 0L; @@ -16947,8 +16123,7 @@ int *denote; * Also accepts ".", "$", etc., but that only works for the current buffer. * Returns -1 on error. */ -static linenr_T get_tv_lnum(argvars) -typval_T *argvars; +static linenr_T get_tv_lnum(typval_T *argvars) { typval_T rettv; linenr_T lnum; @@ -16968,9 +16143,7 @@ typval_T *argvars; * Also accepts "$", then "buf" is used. * Returns 0 on error. */ -static linenr_T get_tv_lnum_buf(argvars, buf) -typval_T *argvars; -buf_T *buf; +static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf) { if (argvars[0].v_type == VAR_STRING && argvars[0].vval.v_string != NULL @@ -16990,34 +16163,28 @@ buf_T *buf; * get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return * NULL on error. */ -static char_u * get_tv_string(varp) -typval_T *varp; +static char_u *get_tv_string(typval_T *varp) { static char_u mybuf[NUMBUFLEN]; return get_tv_string_buf(varp, mybuf); } -static char_u * get_tv_string_buf(varp, buf) -typval_T *varp; -char_u *buf; +static char_u *get_tv_string_buf(typval_T *varp, char_u *buf) { char_u *res = get_tv_string_buf_chk(varp, buf); return res != NULL ? res : (char_u *)""; } -char_u * get_tv_string_chk(varp) -typval_T *varp; +char_u *get_tv_string_chk(typval_T *varp) { static char_u mybuf[NUMBUFLEN]; return get_tv_string_buf_chk(varp, mybuf); } -static char_u * get_tv_string_buf_chk(varp, buf) -typval_T *varp; -char_u *buf; +static char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf) { switch (varp->v_type) { case VAR_NUMBER: @@ -17053,10 +16220,7 @@ char_u *buf; * When "htp" is not NULL we are writing to the variable, set "htp" to the * hashtab_T used. */ -static dictitem_T * find_var(name, htp, no_autoload) -char_u *name; -hashtab_T **htp; -int no_autoload; +static dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload) { char_u *varname; hashtab_T *ht; @@ -17073,11 +16237,7 @@ int no_autoload; * Find variable "varname" in hashtab "ht" with name "htname". * Returns NULL if not found. */ -static dictitem_T * find_var_in_ht(ht, htname, varname, no_autoload) -hashtab_T *ht; -int htname; -char_u *varname; -int no_autoload; +static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload) { hashitem_T *hi; @@ -17121,9 +16281,7 @@ int no_autoload; * Find the hashtab used for a variable name. * Set "varname" to the start of name without ':'. */ -static hashtab_T * find_var_ht(name, varname) -char_u *name; -char_u **varname; +static hashtab_T *find_var_ht(char_u *name, char_u **varname) { hashitem_T *hi; @@ -17173,8 +16331,7 @@ char_u **varname; * Note: see get_tv_string() for how long the pointer remains valid. * Returns NULL when it doesn't exist. */ -char_u * get_var_value(name) -char_u *name; +char_u *get_var_value(char_u *name) { dictitem_T *v; @@ -17188,8 +16345,7 @@ char_u *name; * Allocate a new hashtab for a sourced script. It will be used while * sourcing this script and when executing functions defined in the script. */ -void new_script_vars(id) -scid_T id; +void new_script_vars(scid_T id) { int i; hashtab_T *ht; @@ -17220,10 +16376,7 @@ scid_T id; * Initialize dictionary "dict" as a scope and set variable "dict_var" to * point to it. */ -void init_var_dict(dict, dict_var, scope) -dict_T *dict; -dictitem_T *dict_var; -int scope; +void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope) { hash_init(&dict->dv_hashtab); dict->dv_lock = 0; @@ -17240,8 +16393,7 @@ int scope; /* * Unreference a dictionary initialized by init_var_dict(). */ -void unref_var_dict(dict) -dict_T *dict; +void unref_var_dict(dict_T *dict) { /* Now the dict needs to be freed if no one else is using it, go back to * normal reference counting. */ @@ -17254,8 +16406,7 @@ dict_T *dict; * Frees all allocated variables and the value they contain. * Clears hashtab "ht", does not free it. */ -void vars_clear(ht) -hashtab_T *ht; +void vars_clear(hashtab_T *ht) { vars_clear_ext(ht, TRUE); } @@ -17263,9 +16414,7 @@ hashtab_T *ht; /* * Like vars_clear(), but only free the value if "free_val" is TRUE. */ -static void vars_clear_ext(ht, free_val) -hashtab_T *ht; -int free_val; +static void vars_clear_ext(hashtab_T *ht, int free_val) { int todo; hashitem_T *hi; @@ -17295,9 +16444,7 @@ int free_val; * Delete a variable from hashtab "ht" at item "hi". * Clear the variable value and free the dictitem. */ -static void delete_var(ht, hi) -hashtab_T *ht; -hashitem_T *hi; +static void delete_var(hashtab_T *ht, hashitem_T *hi) { dictitem_T *di = HI2DI(hi); @@ -17309,10 +16456,7 @@ hashitem_T *hi; /* * List the value of one internal variable. */ -static void list_one_var(v, prefix, first) -dictitem_T *v; -char_u *prefix; -int *first; +static void list_one_var(dictitem_T *v, char_u *prefix, int *first) { char_u *tofree; char_u *s; @@ -17325,12 +16469,14 @@ int *first; vim_free(tofree); } -static void list_one_var_a(prefix, name, type, string, first) -char_u *prefix; -char_u *name; -int type; -char_u *string; -int *first; /* when TRUE clear rest of screen and set to FALSE */ +static void +list_one_var_a ( + char_u *prefix, + char_u *name, + int type, + char_u *string, + int *first /* when TRUE clear rest of screen and set to FALSE */ +) { /* don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" */ msg_start(); @@ -17369,10 +16515,12 @@ int *first; /* when TRUE clear rest of screen and set to FALSE */ * If the variable already exists, the value is updated. * Otherwise the variable is created. */ -static void set_var(name, tv, copy) -char_u *name; -typval_T *tv; -int copy; /* make copy of value in "tv" */ +static void +set_var ( + char_u *name, + typval_T *tv, + int copy /* make copy of value in "tv" */ +) { dictitem_T *v; char_u *varname; @@ -17472,9 +16620,7 @@ int copy; /* make copy of value in "tv" */ * Return TRUE if di_flags "flags" indicates variable "name" is read-only. * Also give an error message. */ -static int var_check_ro(flags, name) -int flags; -char_u *name; +static int var_check_ro(int flags, char_u *name) { if (flags & DI_FLAGS_RO) { EMSG2(_(e_readonlyvar), name); @@ -17491,9 +16637,7 @@ char_u *name; * Return TRUE if di_flags "flags" indicates variable "name" is fixed. * Also give an error message. */ -static int var_check_fixed(flags, name) -int flags; -char_u *name; +static int var_check_fixed(int flags, char_u *name) { if (flags & DI_FLAGS_FIX) { EMSG2(_("E795: Cannot delete variable %s"), name); @@ -17506,9 +16650,11 @@ char_u *name; * Check if a funcref is assigned to a valid variable name. * Return TRUE and give an error if not. */ -static int var_check_func_name(name, new_var) -char_u *name; /* points to start of variable name */ -int new_var; /* TRUE when creating the variable */ +static int +var_check_func_name ( + char_u *name, /* points to start of variable name */ + int new_var /* TRUE when creating the variable */ +) { if (!(vim_strchr((char_u *)"wbs", name[0]) != NULL && name[1] == ':') && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') @@ -17532,8 +16678,7 @@ int new_var; /* TRUE when creating the variable */ * Check if a variable name is valid. * Return FALSE and give an error if not. */ -static int valid_varname(varname) -char_u *varname; +static int valid_varname(char_u *varname) { char_u *p; @@ -17550,9 +16695,7 @@ char_u *varname; * Return TRUE if typeval "tv" is set to be locked (immutable). * Also give an error message, using "name". */ -static int tv_check_lock(lock, name) -int lock; -char_u *name; +static int tv_check_lock(int lock, char_u *name) { if (lock & VAR_LOCKED) { EMSG2(_("E741: Value is locked: %s"), @@ -17574,9 +16717,7 @@ char_u *name; * It is OK for "from" and "to" to point to the same item. This is used to * make a copy later. */ -void copy_tv(from, to) -typval_T *from; -typval_T *to; +void copy_tv(typval_T *from, typval_T *to) { to->v_type = from->v_type; to->v_lock = 0; @@ -17626,11 +16767,7 @@ typval_T *to; * reference to an already copied list/dict can be used. * Returns FAIL or OK. */ -static int item_copy(from, to, deep, copyID) -typval_T *from; -typval_T *to; -int deep; -int copyID; +static int item_copy(typval_T *from, typval_T *to, int deep, int copyID) { static int recurse = 0; int ret = OK; @@ -17689,8 +16826,7 @@ int copyID; * newline at the end. * ":echon expr1 ..." print each argument plain. */ -void ex_echo(eap) -exarg_T *eap; +void ex_echo(exarg_T *eap) { char_u *arg = eap->arg; typval_T rettv; @@ -17777,8 +16913,7 @@ exarg_T *eap; /* * ":echohl {name}". */ -void ex_echohl(eap) -exarg_T *eap; +void ex_echohl(exarg_T *eap) { int id; @@ -17796,8 +16931,7 @@ exarg_T *eap; * Each gets spaces around each argument and a newline at the end for * echo commands */ -void ex_execute(eap) -exarg_T *eap; +void ex_execute(exarg_T *eap) { char_u *arg = eap->arg; typval_T rettv; @@ -17872,9 +17006,7 @@ exarg_T *eap; * Returns NULL when no option name found. Otherwise pointer to the char * after the option name. */ -static char_u * find_option_end(arg, opt_flags) -char_u **arg; -int *opt_flags; +static char_u *find_option_end(char_u **arg, int *opt_flags) { char_u *p = *arg; @@ -17903,8 +17035,7 @@ int *opt_flags; /* * ":function" */ -void ex_function(eap) -exarg_T *eap; +void ex_function(exarg_T *eap) { char_u *theline; int i; @@ -18496,11 +17627,13 @@ ret_free: * TFN_NO_AUTOLOAD: do not use script autoloading * Advances "pp" to just after the function name (if no error). */ -static char_u * trans_function_name(pp, skip, flags, fdp) -char_u **pp; -int skip; /* only find the end, don't evaluate */ -int flags; -funcdict_T *fdp; /* return: info about dictionary used */ +static char_u * +trans_function_name ( + char_u **pp, + int skip, /* only find the end, don't evaluate */ + int flags, + funcdict_T *fdp /* return: info about dictionary used */ +) { char_u *name = NULL; char_u *start; @@ -18662,8 +17795,7 @@ theend: * Return 2 if "p" starts with "s:". * Return 0 otherwise. */ -static int eval_fname_script(p) -char_u *p; +static int eval_fname_script(char_u *p) { if (p[0] == '<' && (STRNICMP(p + 1, "SID>", 4) == 0 || STRNICMP(p + 1, "SNR>", 4) == 0)) @@ -18677,8 +17809,7 @@ char_u *p; * Return TRUE if "p" starts with "" or "s:". * Only works if eval_fname_script() returned non-zero for "p"! */ -static int eval_fname_sid(p) -char_u *p; +static int eval_fname_sid(char_u *p) { return *p == 's' || TOUPPER_ASC(p[2]) == 'I'; } @@ -18686,9 +17817,7 @@ char_u *p; /* * List the head of the function: "name(arg1, arg2)". */ -static void list_func_head(fp, indent) -ufunc_T *fp; -int indent; +static void list_func_head(ufunc_T *fp, int indent) { int j; @@ -18728,8 +17857,7 @@ int indent; * Find a function by name, return pointer to it in ufuncs. * Return NULL for unknown function. */ -static ufunc_T * find_func(name) -char_u *name; +static ufunc_T *find_func(char_u *name) { hashitem_T *hi; @@ -18740,7 +17868,7 @@ char_u *name; } #if defined(EXITFREE) || defined(PROTO) -void free_all_functions() { +void free_all_functions(void) { hashitem_T *hi; /* Need to start all over every time, because func_free() may change the @@ -18755,8 +17883,7 @@ void free_all_functions() { #endif -int translated_function_exists(name) -char_u *name; +int translated_function_exists(char_u *name) { if (builtin_function(name)) return find_internal_func(name) >= 0; @@ -18766,8 +17893,7 @@ char_u *name; /* * Return TRUE if a function "name" exists. */ -static int function_exists(name) -char_u *name; +static int function_exists(char_u *name) { char_u *nm = name; char_u *p; @@ -18785,9 +17911,7 @@ char_u *name; return n; } -char_u * get_expanded_name(name, check) -char_u *name; -int check; +char_u *get_expanded_name(char_u *name, int check) { char_u *nm = name; char_u *p; @@ -18806,8 +17930,7 @@ int check; * Return TRUE if "name" looks like a builtin function name: starts with a * lower case letter and doesn't contain a ':' or AUTOLOAD_CHAR. */ -static int builtin_function(name) -char_u *name; +static int builtin_function(char_u *name) { return ASCII_ISLOWER(name[0]) && vim_strchr(name, ':') == NULL && vim_strchr(name, AUTOLOAD_CHAR) == NULL; @@ -18816,8 +17939,7 @@ char_u *name; /* * Start profiling function "fp". */ -static void func_do_profile(fp) -ufunc_T *fp; +static void func_do_profile(ufunc_T *fp) { int len = fp->uf_lines.ga_len; @@ -18845,8 +17967,7 @@ ufunc_T *fp; /* * Dump the profiling results for all functions in file "fd". */ -void func_dump_profile(fd) -FILE *fd; +void func_dump_profile(FILE *fd) { hashitem_T *hi; int todo; @@ -18906,12 +18027,14 @@ FILE *fd; vim_free(sorttab); } -static void prof_sort_list(fd, sorttab, st_len, title, prefer_self) -FILE *fd; -ufunc_T **sorttab; -int st_len; -char *title; -int prefer_self; /* when equal print only self time */ +static void +prof_sort_list ( + FILE *fd, + ufunc_T **sorttab, + int st_len, + char *title, + int prefer_self /* when equal print only self time */ +) { int i; ufunc_T *fp; @@ -18957,9 +18080,7 @@ int prefer_self; /* when equal print only self time */ /* * Compare function for total time sorting. */ -static int prof_total_cmp(s1, s2) -const void *s1; -const void *s2; +static int prof_total_cmp(const void *s1, const void *s2) { ufunc_T *p1, *p2; @@ -18971,9 +18092,7 @@ const void *s2; /* * Compare function for self time sorting. */ -static int prof_self_cmp(s1, s2) -const void *s1; -const void *s2; +static int prof_self_cmp(const void *s1, const void *s2) { ufunc_T *p1, *p2; @@ -18987,9 +18106,11 @@ const void *s2; * If "name" has a package name try autoloading the script for it. * Return TRUE if a package was loaded. */ -static int script_autoload(name, reload) -char_u *name; -int reload; /* load script again when already loaded */ +static int +script_autoload ( + char_u *name, + int reload /* load script again when already loaded */ +) { char_u *p; char_u *scriptname, *tofree; @@ -19030,8 +18151,7 @@ int reload; /* load script again when already loaded */ * Return the autoload script name for a function or variable name. * Returns NULL when out of memory. */ -static char_u * autoload_name(name) -char_u *name; +static char_u *autoload_name(char_u *name) { char_u *p; char_u *scriptname; @@ -19054,9 +18174,7 @@ char_u *name; * Function given to ExpandGeneric() to obtain the list of user defined * function names. */ -char_u * get_user_func_name(xp, idx) -expand_T *xp; -int idx; +char_u *get_user_func_name(expand_T *xp, int idx) { static long_u done; static hashitem_T *hi; @@ -19096,9 +18214,7 @@ int idx; * "buf" must be able to hold the function name plus three bytes. * Takes care of script-local function names. */ -static void cat_func_name(buf, fp) -char_u *buf; -ufunc_T *fp; +static void cat_func_name(char_u *buf, ufunc_T *fp) { if (fp->uf_name[0] == K_SPECIAL) { STRCPY(buf, ""); @@ -19110,8 +18226,7 @@ ufunc_T *fp; /* * ":delfunction {name}" */ -void ex_delfunction(eap) -exarg_T *eap; +void ex_delfunction(exarg_T *eap) { ufunc_T *fp = NULL; char_u *p; @@ -19161,8 +18276,7 @@ exarg_T *eap; /* * Free a function and remove it from the list of functions. */ -static void func_free(fp) -ufunc_T *fp; +static void func_free(ufunc_T *fp) { hashitem_T *hi; @@ -19187,8 +18301,7 @@ ufunc_T *fp; * Unreference a Function: decrement the reference count and free it when it * becomes zero. Only for numbered functions. */ -void func_unref(name) -char_u *name; +void func_unref(char_u *name) { ufunc_T *fp; @@ -19208,8 +18321,7 @@ char_u *name; /* * Count a reference to a Function. */ -void func_ref(name) -char_u *name; +void func_ref(char_u *name) { ufunc_T *fp; @@ -19225,15 +18337,16 @@ char_u *name; /* * Call a user function. */ -static void call_user_func(fp, argcount, argvars, rettv, firstline, lastline, - selfdict) -ufunc_T *fp; /* pointer to function */ -int argcount; /* nr of args */ -typval_T *argvars; /* arguments */ -typval_T *rettv; /* return value */ -linenr_T firstline; /* first line of range */ -linenr_T lastline; /* last line of range */ -dict_T *selfdict; /* Dictionary for "self" */ +static void +call_user_func ( + ufunc_T *fp, /* pointer to function */ + int argcount, /* nr of args */ + typval_T *argvars, /* arguments */ + typval_T *rettv, /* return value */ + linenr_T firstline, /* first line of range */ + linenr_T lastline, /* last line of range */ + dict_T *selfdict /* Dictionary for "self" */ +) { char_u *save_sourcing_name; linenr_T save_sourcing_lnum; @@ -19554,9 +18667,7 @@ dict_T *selfdict; /* Dictionary for "self" */ * Return TRUE if items in "fc" do not have "copyID". That means they are not * referenced from anywhere that is in use. */ -static int can_free_funccal(fc, copyID) -funccall_T *fc; -int copyID; +static int can_free_funccal(funccall_T *fc, int copyID) { return fc->l_varlist.lv_copyID != copyID && fc->l_vars.dv_copyID != copyID @@ -19566,9 +18677,11 @@ int copyID; /* * Free "fc" and what it contains. */ -static void free_funccal(fc, free_val) -funccall_T *fc; -int free_val; /* a: vars were allocated */ +static void +free_funccal ( + funccall_T *fc, + int free_val /* a: vars were allocated */ +) { listitem_T *li; @@ -19590,11 +18703,7 @@ int free_val; /* a: vars were allocated */ /* * Add a number variable "name" to dict "dp" with value "nr". */ -static void add_nr_var(dp, v, name, nr) -dict_T *dp; -dictitem_T *v; -char *name; -varnumber_T nr; +static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr) { STRCPY(v->di_key, name); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; @@ -19607,8 +18716,7 @@ varnumber_T nr; /* * ":return [expr]" */ -void ex_return(eap) -exarg_T *eap; +void ex_return(exarg_T *eap) { char_u *arg = eap->arg; typval_T rettv; @@ -19660,11 +18768,7 @@ exarg_T *eap; * with the return rettv. Returns TRUE when the return can be carried out, * FALSE when the return gets pending. */ -int do_return(eap, reanimate, is_cmd, rettv) -exarg_T *eap; -int reanimate; -int is_cmd; -void *rettv; +int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) { int idx; struct condstack *cstack = eap->cstack; @@ -19732,8 +18836,7 @@ void *rettv; /* * Free the variable with a pending return value. */ -void discard_pending_return(rettv) -void *rettv; +void discard_pending_return(void *rettv) { free_tv((typval_T *)rettv); } @@ -19742,8 +18845,7 @@ void *rettv; * Generate a return command for producing the value of "rettv". The result * is an allocated string. Used by report_pending() for verbose messages. */ -char_u * get_return_cmd(rettv) -void *rettv; +char_u *get_return_cmd(void *rettv) { char_u *s = NULL; char_u *tofree = NULL; @@ -19767,10 +18869,7 @@ void *rettv; * Called by do_cmdline() to get the next line. * Returns allocated string, or NULL for end of function. */ -char_u * get_func_line(c, cookie, indent) -int c UNUSED; -void *cookie; -int indent UNUSED; +char_u *get_func_line(int c, void *cookie, int indent) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; @@ -19823,8 +18922,7 @@ int indent UNUSED; * When skipping lines it may not actually be executed, but we won't find out * until later and we need to store the time now. */ -void func_line_start(cookie) -void *cookie; +void func_line_start(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; @@ -19845,8 +18943,7 @@ void *cookie; /* * Called when actually executing a function line. */ -void func_line_exec(cookie) -void *cookie; +void func_line_exec(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; @@ -19858,8 +18955,7 @@ void *cookie; /* * Called when done with a function line. */ -void func_line_end(cookie) -void *cookie; +void func_line_end(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; @@ -19881,8 +18977,7 @@ void *cookie; * Return TRUE if the currently active function should be ended, because a * return was encountered or an error occurred. Used inside a ":while". */ -int func_has_ended(cookie) -void *cookie; +int func_has_ended(void *cookie) { funccall_T *fcp = (funccall_T *)cookie; @@ -19895,8 +18990,7 @@ void *cookie; /* * return TRUE if cookie indicates a function which "abort"s on errors. */ -int func_has_abort(cookie) -void *cookie; +int func_has_abort(void *cookie) { return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT; } @@ -19909,8 +19003,7 @@ typedef enum { static var_flavour_T var_flavour __ARGS((char_u *varname)); -static var_flavour_T var_flavour(varname) -char_u *varname; +static var_flavour_T var_flavour(char_u *varname) { char_u *p = varname; @@ -19926,9 +19019,7 @@ char_u *varname; /* * Restore global vars that start with a capital from the viminfo file */ -int read_viminfo_varlist(virp, writing) -vir_T *virp; -int writing; +int read_viminfo_varlist(vir_T *virp, int writing) { char_u *tab; int type = VAR_NUMBER; @@ -19985,8 +19076,7 @@ int writing; /* * Write global vars that start with a capital to the viminfo file */ -void write_viminfo_varlist(fp) -FILE *fp; +void write_viminfo_varlist(FILE *fp) { hashitem_T *hi; dictitem_T *this_var; @@ -20025,8 +19115,7 @@ FILE *fp; } } -int store_session_globals(fd) -FILE *fd; +int store_session_globals(FILE *fd) { hashitem_T *hi; dictitem_T *this_var; @@ -20087,8 +19176,7 @@ FILE *fd; * Display script name where an item was last set. * Should only be invoked when 'verbose' is non-zero. */ -void last_set_msg(scriptID) -scid_T scriptID; +void last_set_msg(scid_T scriptID) { char_u *p; @@ -20107,8 +19195,7 @@ scid_T scriptID; /* * List v:oldfiles in a nice way. */ -void ex_oldfiles(eap) -exarg_T *eap UNUSED; +void ex_oldfiles(exarg_T *eap) { list_T *l = vimvars[VV_OLDFILES].vv_list; listitem_T *li; @@ -20144,12 +19231,14 @@ exarg_T *eap UNUSED; * Returns VALID_ flags or -1 for failure. * When there is an error, *fnamep is set to NULL. */ -int modify_fname(src, usedlen, fnamep, bufp, fnamelen) -char_u *src; /* string with modifiers */ -int *usedlen; /* characters after src that are used */ -char_u **fnamep; /* file name so far */ -char_u **bufp; /* buffer for allocated file name or NULL */ -int *fnamelen; /* length of fnamep */ +int +modify_fname ( + char_u *src, /* string with modifiers */ + int *usedlen, /* characters after src that are used */ + char_u **fnamep, /* file name so far */ + char_u **bufp, /* buffer for allocated file name or NULL */ + int *fnamelen /* length of fnamep */ +) { int valid = 0; char_u *tail; @@ -20395,11 +19484,7 @@ repeat: * "flags" can be "g" to do a global substitute. * Returns an allocated string, NULL for error. */ -char_u * do_string_sub(str, pat, sub, flags) -char_u *str; -char_u *pat; -char_u *sub; -char_u *flags; +char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags) { int sublen; regmatch_T regmatch; diff --git a/src/ex_cmds.c b/src/ex_cmds.c index d791d777dc..2570335f66 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -32,8 +32,7 @@ help_compare __ARGS((const void *s1, const void *s2)); /* * ":ascii" and "ga". */ -void do_ascii(eap) -exarg_T *eap UNUSED; +void do_ascii(exarg_T *eap) { int c; int cval; @@ -113,8 +112,7 @@ exarg_T *eap UNUSED; /* * ":left", ":center" and ":right": align text. */ -void ex_align(eap) -exarg_T *eap; +void ex_align(exarg_T *eap) { pos_T save_curpos; int len; @@ -204,8 +202,7 @@ exarg_T *eap; /* * Get the length of the current line, excluding trailing white space. */ -static int linelen(has_tab) -int *has_tab; +static int linelen(int *has_tab) { char_u *line; char_u *first; @@ -252,9 +249,7 @@ typedef struct { static int sort_compare __ARGS((const void *s1, const void *s2)); -static int sort_compare(s1, s2) -const void *s1; -const void *s2; +static int sort_compare(const void *s1, const void *s2) { sorti_T l1 = *(sorti_T *)s1; sorti_T l2 = *(sorti_T *)s2; @@ -298,8 +293,7 @@ const void *s2; /* * ":sort". */ -void ex_sort(eap) -exarg_T *eap; +void ex_sort(exarg_T *eap) { regmatch_T regmatch; int len; @@ -509,8 +503,7 @@ sortend: /* * ":retab". */ -void ex_retab(eap) -exarg_T *eap; +void ex_retab(exarg_T *eap) { linenr_T lnum; int got_tab = FALSE; @@ -642,10 +635,7 @@ exarg_T *eap; * * return FAIL for failure, OK otherwise */ -int do_move(line1, line2, dest) -linenr_T line1; -linenr_T line2; -linenr_T dest; +int do_move(linenr_T line1, linenr_T line2, linenr_T dest) { char_u *str; linenr_T l; @@ -747,10 +737,7 @@ linenr_T dest; /* * ":copy" */ -void ex_copy(line1, line2, n) -linenr_T line1; -linenr_T line2; -linenr_T n; +void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) { linenr_T count; char_u *p; @@ -802,7 +789,7 @@ linenr_T n; static char_u *prevcmd = NULL; /* the previous command */ #if defined(EXITFREE) || defined(PROTO) -void free_prev_shellcmd() { +void free_prev_shellcmd(void) { vim_free(prevcmd); } @@ -813,11 +800,7 @@ void free_prev_shellcmd() { * Bangs in the argument are replaced with the previously entered command. * Remember the argument. */ -void do_bang(addr_count, eap, forceit, do_in, do_out) -int addr_count; -exarg_T *eap; -int forceit; -int do_in, do_out; +void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) { char_u *arg = eap->arg; /* command */ linenr_T line1 = eap->line1; /* start of range */ @@ -952,11 +935,15 @@ int do_in, do_out; * We use input redirection if do_in is TRUE. * We use output redirection if do_out is TRUE. */ -static void do_filter(line1, line2, eap, cmd, do_in, do_out) -linenr_T line1, line2; -exarg_T *eap; /* for forced 'ff' and 'fenc' */ -char_u *cmd; -int do_in, do_out; +static void +do_filter ( + linenr_T line1, + linenr_T line2, + exarg_T *eap, /* for forced 'ff' and 'fenc' */ + char_u *cmd, + int do_in, + int do_out +) { char_u *itmp = NULL; char_u *otmp = NULL; @@ -1164,9 +1151,11 @@ filterend: * Call a shell to execute a command. * When "cmd" is NULL start an interactive shell. */ -void do_shell(cmd, flags) -char_u *cmd; -int flags; /* may be SHELL_DOOUT when output is redirected */ +void +do_shell ( + char_u *cmd, + int flags /* may be SHELL_DOOUT when output is redirected */ +) { buf_T *buf; int save_nwr; @@ -1269,10 +1258,12 @@ int flags; /* may be SHELL_DOOUT when output is redirected */ * output redirection file. * Returns an allocated string with the shell command, or NULL for failure. */ -char_u * make_filter_cmd(cmd, itmp, otmp) -char_u *cmd; /* command */ -char_u *itmp; /* NULL or name of input file */ -char_u *otmp; /* NULL or name of output file */ +char_u * +make_filter_cmd ( + char_u *cmd, /* command */ + char_u *itmp, /* NULL or name of input file */ + char_u *otmp /* NULL or name of output file */ +) { char_u *buf; long_u len; @@ -1342,11 +1333,7 @@ char_u *otmp; /* NULL or name of output file */ * The caller should make sure that there is enough room: * STRLEN(opt) + STRLEN(fname) + 3 */ -void append_redir(buf, buflen, opt, fname) -char_u *buf; -int buflen; -char_u *opt; -char_u *fname; +void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname) { char_u *p; char_u *end; @@ -1373,7 +1360,7 @@ char_u *fname; static int no_viminfo __ARGS((void)); static int viminfo_errcnt; -static int no_viminfo() { +static int no_viminfo(void) { /* "vim -i NONE" does not read or write a viminfo file */ return use_viminfo != NULL && STRCMP(use_viminfo, "NONE") == 0; } @@ -1382,10 +1369,7 @@ static int no_viminfo() { * Report an error for reading a viminfo file. * Count the number of errors. When there are more than 10, return TRUE. */ -int viminfo_error(errnum, message, line) -char *errnum; -char *message; -char_u *line; +int viminfo_error(char *errnum, char *message, char_u *line) { vim_snprintf((char *)IObuff, IOSIZE, _("%sviminfo: %s in line: "), errnum, message); @@ -1404,9 +1388,11 @@ char_u *line; * read_viminfo() -- Read the viminfo file. Registers etc. which are already * set are not over-written unless "flags" includes VIF_FORCEIT. -- webb */ -int read_viminfo(file, flags) -char_u *file; /* file name or NULL to use default name */ -int flags; /* VIF_WANT_INFO et al. */ +int +read_viminfo ( + char_u *file, /* file name or NULL to use default name */ + int flags /* VIF_WANT_INFO et al. */ +) { FILE *fp; char_u *fname; @@ -1448,9 +1434,7 @@ int flags; /* VIF_WANT_INFO et al. */ * If "forceit" is TRUE, then the old file is not read in, and only internal * info is written to the file. */ -void write_viminfo(file, forceit) -char_u *file; -int forceit; +void write_viminfo(char_u *file, int forceit) { char_u *fname; FILE *fp_in = NULL; /* input viminfo file, if any */ @@ -1678,8 +1662,7 @@ end: * expand environment variables. * Returns an allocated string. NULL when out of memory. */ -static char_u * viminfo_filename(file) -char_u *file; +static char_u *viminfo_filename(char_u *file) { if (file == NULL || *file == NUL) { if (use_viminfo != NULL) @@ -1707,10 +1690,7 @@ char_u *file; /* * do_viminfo() -- Should only be called from read_viminfo() & write_viminfo(). */ -static void do_viminfo(fp_in, fp_out, flags) -FILE *fp_in; -FILE *fp_out; -int flags; +static void do_viminfo(FILE *fp_in, FILE *fp_out, int flags) { int count = 0; int eof = FALSE; @@ -1763,10 +1743,7 @@ int flags; * first part of the viminfo file which contains everything but the marks that * are local to a file. Returns TRUE when end-of-file is reached. -- webb */ -static int read_viminfo_up_to_marks(virp, forceit, writing) -vir_T *virp; -int forceit; -int writing; +static int read_viminfo_up_to_marks(vir_T *virp, int forceit, int writing) { int eof; buf_T *buf; @@ -1843,8 +1820,7 @@ int writing; * 'encoding'. If different and the 'c' flag is in 'viminfo', setup for * conversion of text with iconv() in viminfo_readstring(). */ -static int viminfo_encoding(virp) -vir_T *virp; +static int viminfo_encoding(vir_T *virp) { char_u *p; int i; @@ -1868,8 +1844,7 @@ vir_T *virp; * Read a line from the viminfo file. * Returns TRUE for end-of-file; */ -int viminfo_readline(virp) -vir_T *virp; +int viminfo_readline(vir_T *virp) { return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd); } @@ -1884,10 +1859,12 @@ vir_T *virp; * * Return the string in allocated memory (NULL when out of memory). */ -char_u * viminfo_readstring(virp, off, convert) -vir_T *virp; -int off; /* offset for virp->vir_line */ -int convert UNUSED; /* convert the string */ +char_u * +viminfo_readstring ( + vir_T *virp, + int off, /* offset for virp->vir_line */ + int convert /* convert the string */ +) { char_u *retval; char_u *s, *d; @@ -1945,9 +1922,7 @@ int convert UNUSED; /* convert the string */ * - write " CTRL-V \n " in first line * - write " < \n " in second line */ -void viminfo_writestring(fd, p) -FILE *fd; -char_u *p; +void viminfo_writestring(FILE *fd, char_u *p) { int c; char_u *s; @@ -1983,8 +1958,7 @@ char_u *p; * ^? ^H * not ^? ^? */ -void do_fixdel(eap) -exarg_T *eap UNUSED; +void do_fixdel(exarg_T *eap) { char_u *p; @@ -1993,10 +1967,7 @@ exarg_T *eap UNUSED; && *p == DEL ? (char_u *)CTRL_H_STR : DEL_STR, FALSE); } -void print_line_no_prefix(lnum, use_number, list) -linenr_T lnum; -int use_number; -int list; +void print_line_no_prefix(linenr_T lnum, int use_number, int list) { char_u numbuf[30]; @@ -2011,10 +1982,7 @@ int list; /* * Print a text line. Also in silent mode ("ex -s"). */ -void print_line(lnum, use_number, list) -linenr_T lnum; -int use_number; -int list; +void print_line(linenr_T lnum, int use_number, int list) { int save_silent = silent_mode; @@ -2031,8 +1999,7 @@ int list; info_message = FALSE; } -int rename_buffer(new_fname) -char_u *new_fname; +int rename_buffer(char_u *new_fname) { char_u *fname, *sfname, *xfname; buf_T *buf; @@ -2078,8 +2045,7 @@ char_u *new_fname; /* * ":file[!] [fname]". */ -void ex_file(eap) -exarg_T *eap; +void ex_file(exarg_T *eap) { /* ":0file" removes the file name. Check for illegal uses ":3file", * "0file name", etc. */ @@ -2102,8 +2068,7 @@ exarg_T *eap; /* * ":update". */ -void ex_update(eap) -exarg_T *eap; +void ex_update(exarg_T *eap) { if (curbufIsChanged()) (void)do_write(eap); @@ -2112,8 +2077,7 @@ exarg_T *eap; /* * ":write" and ":saveas". */ -void ex_write(eap) -exarg_T *eap; +void ex_write(exarg_T *eap) { if (eap->usefilter) /* input lines to shell command */ do_bang(1, eap, FALSE, TRUE, FALSE); @@ -2129,8 +2093,7 @@ exarg_T *eap; * * return FAIL for failure, OK otherwise */ -int do_write(eap) -exarg_T *eap; +int do_write(exarg_T *eap) { int other; char_u *fname = NULL; /* init to shut up gcc */ @@ -2287,13 +2250,15 @@ theend: * May set eap->forceit if a dialog says it's OK to overwrite. * Return OK if it's OK, FAIL if it is not. */ -int check_overwrite(eap, buf, fname, ffname, other) -exarg_T *eap; -buf_T *buf; -char_u *fname; /* file name to be used (can differ from +int +check_overwrite ( + exarg_T *eap, + buf_T *buf, + char_u *fname, /* file name to be used (can differ from buf->ffname) */ -char_u *ffname; /* full path version of fname */ -int other; /* writing under other name */ + char_u *ffname, /* full path version of fname */ + int other /* writing under other name */ +) { /* * write to other file or b_flags set or not writing the whole file: @@ -2384,8 +2349,7 @@ int other; /* writing under other name */ /* * Handle ":wnext", ":wNext" and ":wprevious" commands. */ -void ex_wnext(eap) -exarg_T *eap; +void ex_wnext(exarg_T *eap) { int i; @@ -2402,8 +2366,7 @@ exarg_T *eap; /* * ":wall", ":wqall" and ":xall": Write all changed files (and exit). */ -void do_wqall(eap) -exarg_T *eap; +void do_wqall(exarg_T *eap) { buf_T *buf; int error = 0; @@ -2453,7 +2416,7 @@ exarg_T *eap; * Check the 'write' option. * Return TRUE and give a message when it's not st. */ -int not_writing() { +int not_writing(void) { if (p_write) return FALSE; EMSG(_("E142: File not written: Writing is disabled by 'write' option")); @@ -2465,9 +2428,7 @@ int not_writing() { * read-only). Ask for overruling in a dialog. Return TRUE and give an error * message when the buffer is readonly. */ -static int check_readonly(forceit, buf) -int *forceit; -buf_T *buf; +static int check_readonly(int *forceit, buf_T *buf) { struct stat st; @@ -2517,13 +2478,7 @@ buf_T *buf; * -1 for successfully opening another file. * 'lnum' is the line number for the cursor in the new file (if non-zero). */ -int getfile(fnum, ffname, sfname, setpm, lnum, forceit) -int fnum; -char_u *ffname; -char_u *sfname; -int setpm; -linenr_T lnum; -int forceit; +int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm, linenr_T lnum, int forceit) { int other; int retval; @@ -2607,14 +2562,16 @@ theend: * * return FAIL for failure, OK otherwise */ -int do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin) -int fnum; -char_u *ffname; -char_u *sfname; -exarg_T *eap; /* can be NULL! */ -linenr_T newlnum; -int flags; -win_T *oldwin; +int +do_ecmd ( + int fnum, + char_u *ffname, + char_u *sfname, + exarg_T *eap, /* can be NULL! */ + linenr_T newlnum, + int flags, + win_T *oldwin +) { int other_file; /* TRUE if editing another file */ int oldbuf; /* TRUE if using existing buffer */ @@ -3173,8 +3130,7 @@ theend: return retval; } -static void delbuf_msg(name) -char_u *name; +static void delbuf_msg(char_u *name) { EMSG2(_("E143: Autocommands unexpectedly deleted new buffer %s"), name == NULL ? (char_u *)"" : name); @@ -3187,8 +3143,7 @@ static int append_indent = 0; /* autoindent for first line */ /* * ":insert" and ":append", also used by ":change" */ -void ex_append(eap) -exarg_T *eap; +void ex_append(exarg_T *eap) { char_u *theline; int did_undo = FALSE; @@ -3312,8 +3267,7 @@ exarg_T *eap; /* * ":change" */ -void ex_change(eap) -exarg_T *eap; +void ex_change(exarg_T *eap) { linenr_T lnum; @@ -3340,8 +3294,7 @@ exarg_T *eap; ex_append(eap); } -void ex_z(eap) -exarg_T *eap; +void ex_z(exarg_T *eap) { char_u *x; int bigness; @@ -3460,7 +3413,7 @@ exarg_T *eap; * If so, give an error message and return TRUE. * Otherwise, return FALSE. */ -int check_restricted() { +int check_restricted(void) { if (restricted) { EMSG(_("E145: Shell commands not allowed in rvim")); return TRUE; @@ -3473,7 +3426,7 @@ int check_restricted() { * If so, give an error message and return TRUE. * Otherwise, return FALSE. */ -int check_secure() { +int check_secure(void) { if (secure) { secure = 2; EMSG(_(e_curdir)); @@ -3504,8 +3457,7 @@ static int global_need_beginline; /* call beginline() after ":g" */ * * The usual escapes are supported as described in the regexp docs. */ -void do_sub(eap) -exarg_T *eap; +void do_sub(exarg_T *eap) { linenr_T lnum; long i = 0; @@ -4416,8 +4368,10 @@ outofmem: * Can also be used after a ":global" command. * Return TRUE if a message was given. */ -int do_sub_msg(count_only) -int count_only; /* used 'n' flag for ":s" */ +int +do_sub_msg ( + int count_only /* used 'n' flag for ":s" */ +) { /* * Only report substitutions when: @@ -4473,8 +4427,7 @@ int count_only; /* used 'n' flag for ":s" */ * for each line that has a mark. This is required because after deleting * lines we do not know where to search for the next match. */ -void ex_global(eap) -exarg_T *eap; +void ex_global(exarg_T *eap) { linenr_T lnum; /* line number according to old situation */ int ndone = 0; @@ -4571,8 +4524,7 @@ exarg_T *eap; /* * Execute "cmd" on lines marked with ml_setmarked(). */ -void global_exe(cmd) -char_u *cmd; +void global_exe(char_u *cmd) { linenr_T old_lcount; /* b_ml.ml_line_count before the command */ buf_T *old_buf = curbuf; /* remember what buffer we started in */ @@ -4626,9 +4578,7 @@ char_u *cmd; msgmore(curbuf->b_ml.ml_line_count - old_lcount); } -int read_viminfo_sub_string(virp, force) -vir_T *virp; -int force; +int read_viminfo_sub_string(vir_T *virp, int force) { if (force) vim_free(old_sub); @@ -4637,8 +4587,7 @@ int force; return viminfo_readline(virp); } -void write_viminfo_sub_string(fp) -FILE *fp; +void write_viminfo_sub_string(FILE *fp) { if (get_viminfo_parameter('/') != 0 && old_sub != NULL) { fputs(_("\n# Last Substitute String:\n$"), fp); @@ -4647,7 +4596,7 @@ FILE *fp; } #if defined(EXITFREE) || defined(PROTO) -void free_old_sub() { +void free_old_sub(void) { vim_free(old_sub); } @@ -4657,8 +4606,10 @@ void free_old_sub() { * Set up for a tagpreview. * Return TRUE when it was created. */ -int prepare_tagpreview(undo_sync) -int undo_sync; /* sync undo when leaving the window */ +int +prepare_tagpreview ( + int undo_sync /* sync undo when leaving the window */ +) { win_T *wp; @@ -4696,8 +4647,7 @@ int undo_sync; /* sync undo when leaving the window */ /* * ":help": open a read-only window on a help file */ -void ex_help(eap) -exarg_T *eap; +void ex_help(exarg_T *eap) { char_u *arg; char_u *tag; @@ -4870,8 +4820,7 @@ erret: * Changes the "@" to NUL if found, and returns a pointer to "xx". * Returns NULL if not found. */ -char_u * check_help_lang(arg) -char_u *arg; +char_u *check_help_lang(char_u *arg) { int len = (int)STRLEN(arg); @@ -4894,10 +4843,12 @@ char_u *arg; * Assumption is made that the matched_string passed has already been found to * match some string for which help is requested. webb. */ -int help_heuristic(matched_string, offset, wrong_case) -char_u *matched_string; -int offset; /* offset for match */ -int wrong_case; /* no matching case */ +int +help_heuristic ( + char_u *matched_string, + int offset, /* offset for match */ + int wrong_case /* no matching case */ +) { int num_letters; char_u *p; @@ -4934,9 +4885,7 @@ int wrong_case; /* no matching case */ * Compare functions for qsort() below, that checks the help heuristics number * that has been put after the tagname by find_tags(). */ -static int help_compare(s1, s2) -const void *s1; -const void *s2; +static int help_compare(const void *s1, const void *s2) { char *p1; char *p2; @@ -4952,11 +4901,7 @@ const void *s2; * The matches will be sorted with a "best" match algorithm. * When "keep_lang" is TRUE try keeping the language of the current buffer. */ -int find_help_tags(arg, num_matches, matches, keep_lang) -char_u *arg; -int *num_matches; -char_u ***matches; -int keep_lang; +int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_lang) { char_u *s, *d; int i; @@ -5135,7 +5080,7 @@ int keep_lang; * After reading a help file: May cleanup a help buffer when syntax * highlighting is not used. */ -void fix_help_buffer() { +void fix_help_buffer(void) { linenr_T lnum; char_u *line; int in_example = FALSE; @@ -5331,8 +5276,7 @@ void fix_help_buffer() { /* * ":exusage" */ -void ex_exusage(eap) -exarg_T *eap UNUSED; +void ex_exusage(exarg_T *eap) { do_cmdline_cmd((char_u *)"help ex-cmd-index"); } @@ -5340,8 +5284,7 @@ exarg_T *eap UNUSED; /* * ":viusage" */ -void ex_viusage(eap) -exarg_T *eap UNUSED; +void ex_viusage(exarg_T *eap) { do_cmdline_cmd((char_u *)"help normal-index"); } @@ -5352,8 +5295,7 @@ static void helptags_one __ARGS((char_u *dir, char_u *ext, char_u *lang, /* * ":helptags" */ -void ex_helptags(eap) -exarg_T *eap; +void ex_helptags(exarg_T *eap) { garray_T ga; int i, j; @@ -5454,11 +5396,13 @@ exarg_T *eap; vim_free(dirname); } -static void helptags_one(dir, ext, tagfname, add_help_tags) -char_u *dir; /* doc directory */ -char_u *ext; /* suffix, ".txt", ".itx", ".frx", etc. */ -char_u *tagfname; /* "tags" for English, "tags-fr" for French. */ -int add_help_tags; /* add "help-tags" tag */ +static void +helptags_one ( + char_u *dir, /* doc directory */ + char_u *ext, /* suffix, ".txt", ".itx", ".frx", etc. */ + char_u *tagfname, /* "tags" for English, "tags-fr" for French. */ + int add_help_tags /* add "help-tags" tag */ +) { FILE *fd_tags; FILE *fd; diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 209fcddd67..4f5cd60da9 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -64,8 +64,7 @@ static int debug_greedy = FALSE; /* batch mode debugging: don't save * do_debug(): Debug mode. * Repeatedly get Ex commands, until told to continue normal execution. */ -void do_debug(cmd) -char_u *cmd; +void do_debug(char_u *cmd) { int save_msg_scroll = msg_scroll; int save_State = State; @@ -247,8 +246,7 @@ char_u *cmd; /* * ":debug". */ -void ex_debug(eap) -exarg_T *eap; +void ex_debug(exarg_T *eap) { int debug_break_level_save = debug_break_level; @@ -277,8 +275,7 @@ static char_u *debug_skipped_name; * decide to execute something themselves. * Called from do_one_cmd() before executing a command. */ -void dbg_check_breakpoint(eap) -exarg_T *eap; +void dbg_check_breakpoint(exarg_T *eap) { char_u *p; @@ -317,8 +314,7 @@ exarg_T *eap; * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was * set. Return TRUE when the debug mode is entered this time. */ -int dbg_check_skipped(eap) -exarg_T *eap; +int dbg_check_skipped(exarg_T *eap) { int prev_got_int; @@ -374,9 +370,11 @@ static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, * is allocated. * Returns FAIL for failure. */ -static int dbg_parsearg(arg, gap) -char_u *arg; -garray_T *gap; /* either &dbg_breakp or &prof_ga */ +static int +dbg_parsearg ( + char_u *arg, + garray_T *gap /* either &dbg_breakp or &prof_ga */ +) { char_u *p = arg; char_u *q; @@ -456,8 +454,7 @@ garray_T *gap; /* either &dbg_breakp or &prof_ga */ /* * ":breakadd". */ -void ex_breakadd(eap) -exarg_T *eap; +void ex_breakadd(exarg_T *eap) { struct debuggy *bp; char_u *pat; @@ -493,8 +490,7 @@ exarg_T *eap; /* * ":debuggreedy". */ -void ex_debuggreedy(eap) -exarg_T *eap; +void ex_debuggreedy(exarg_T *eap) { if (eap->addr_count == 0 || eap->line2 != 0) debug_greedy = TRUE; @@ -505,8 +501,7 @@ exarg_T *eap; /* * ":breakdel" and ":profdel". */ -void ex_breakdel(eap) -exarg_T *eap; +void ex_breakdel(exarg_T *eap) { struct debuggy *bp, *bpi; int nr; @@ -577,8 +572,7 @@ exarg_T *eap; /* * ":breaklist". */ -void ex_breaklist(eap) -exarg_T *eap UNUSED; +void ex_breaklist(exarg_T *eap) { struct debuggy *bp; int i; @@ -602,10 +596,12 @@ exarg_T *eap UNUSED; * Find a breakpoint for a function or sourced file. * Returns line number at which to break; zero when no matching breakpoint. */ -linenr_T dbg_find_breakpoint(file, fname, after) -int file; /* TRUE for a file, FALSE for a function */ -char_u *fname; /* file or function name */ -linenr_T after; /* after this line number */ +linenr_T +dbg_find_breakpoint ( + int file, /* TRUE for a file, FALSE for a function */ + char_u *fname, /* file or function name */ + linenr_T after /* after this line number */ +) { return debuggy_find(file, fname, after, &dbg_breakp, NULL); } @@ -613,10 +609,12 @@ linenr_T after; /* after this line number */ /* * Return TRUE if profiling is on for a function or sourced file. */ -int has_profiling(file, fname, fp) -int file; /* TRUE for a file, FALSE for a function */ -char_u *fname; /* file or function name */ -int *fp; /* return: forceit */ +int +has_profiling ( + int file, /* TRUE for a file, FALSE for a function */ + char_u *fname, /* file or function name */ + int *fp /* return: forceit */ +) { return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) != (linenr_T)0; @@ -625,12 +623,14 @@ int *fp; /* return: forceit */ /* * Common code for dbg_find_breakpoint() and has_profiling(). */ -static linenr_T debuggy_find(file, fname, after, gap, fp) -int file; /* TRUE for a file, FALSE for a function */ -char_u *fname; /* file or function name */ -linenr_T after; /* after this line number */ -garray_T *gap; /* either &dbg_breakp or &prof_ga */ -int *fp; /* if not NULL: return forceit */ +static linenr_T +debuggy_find ( + int file, /* TRUE for a file, FALSE for a function */ + char_u *fname, /* file or function name */ + linenr_T after, /* after this line number */ + garray_T *gap, /* either &dbg_breakp or &prof_ga */ + int *fp /* if not NULL: return forceit */ +) { struct debuggy *bp; int i; @@ -687,9 +687,7 @@ int *fp; /* if not NULL: return forceit */ /* * Called when a breakpoint was encountered. */ -void dbg_breakpoint(name, lnum) -char_u *name; -linenr_T lnum; +void dbg_breakpoint(char_u *name, linenr_T lnum) { /* We need to check if this line is actually executed in do_one_cmd() */ debug_breakpoint_name = name; @@ -901,8 +899,7 @@ static proftime_T pause_time; /* * ":profile cmd args" */ -void ex_profile(eap) -exarg_T *eap; +void ex_profile(exarg_T *eap) { char_u *e; int len; @@ -960,9 +957,7 @@ static char *pexpand_cmds[] = { * Function given to ExpandGeneric() to obtain the profile command * specific expansion. */ -char_u * get_profile_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_profile_name(expand_T *xp, int idx) { switch (pexpand_what) { case PEXP_SUBCMD: @@ -976,9 +971,7 @@ int idx; /* * Handle command line completion for :profile command. */ -void set_context_in_profile_cmd(xp, arg) -expand_T *xp; -char_u *arg; +void set_context_in_profile_cmd(expand_T *xp, char_u *arg) { char_u *end_subcmd; @@ -1004,7 +997,7 @@ char_u *arg; /* * Dump the profiling info. */ -void profile_dump() { +void profile_dump(void) { FILE *fd; if (profile_fname != NULL) { @@ -1022,8 +1015,7 @@ void profile_dump() { /* * Start profiling script "fp". */ -static void script_do_profile(si) -scriptitem_T *si; +static void script_do_profile(scriptitem_T *si) { si->sn_pr_count = 0; profile_zero(&si->sn_pr_total); @@ -1075,14 +1067,14 @@ static proftime_T inchar_time; /* * Called when starting to wait for the user to type a character. */ -void prof_inchar_enter() { +void prof_inchar_enter(void) { profile_start(&inchar_time); } /* * Called when finished waiting for the user to type a character. */ -void prof_inchar_exit() { +void prof_inchar_exit(void) { profile_end(&inchar_time); profile_add(&prof_wait_time, &inchar_time); } @@ -1090,8 +1082,7 @@ void prof_inchar_exit() { /* * Dump the profiling results for all scripts in file "fd". */ -static void script_dump_profile(fd) -FILE *fd; +static void script_dump_profile(FILE *fd) { int id; scriptitem_T *si; @@ -1142,7 +1133,7 @@ FILE *fd; * Return TRUE when a function defined in the current script should be * profiled. */ -int prof_def_func() { +int prof_def_func(void) { if (current_SID > 0) return SCRIPT_ITEM(current_SID).sn_pr_force; return FALSE; @@ -1154,9 +1145,7 @@ int prof_def_func() { * * return FAIL for failure, OK otherwise */ -int autowrite(buf, forceit) -buf_T *buf; -int forceit; +int autowrite(buf_T *buf, int forceit) { int r; @@ -1177,7 +1166,7 @@ int forceit; /* * flush all buffers, except the ones that are readonly */ -void autowrite_all() { +void autowrite_all(void) { buf_T *buf; if (!(p_aw || p_awa) || !p_write) @@ -1195,9 +1184,7 @@ void autowrite_all() { * Return TRUE if buffer was changed and cannot be abandoned. * For flags use the CCGD_ values. */ -int check_changed(buf, flags) -buf_T *buf; -int flags; +int check_changed(buf_T *buf, int flags) { int forceit = (flags & CCGD_FORCEIT); @@ -1239,9 +1226,11 @@ int flags; * Ask the user what to do when abandoning a changed buffer. * Must check 'write' option first! */ -void dialog_changed(buf, checkall) -buf_T *buf; -int checkall; /* may abandon all changed buffers */ +void +dialog_changed ( + buf_T *buf, + int checkall /* may abandon all changed buffers */ +) { char_u buff[DIALOG_MSG_SIZE]; int ret; @@ -1300,9 +1289,7 @@ int checkall; /* may abandon all changed buffers */ * Return TRUE if the buffer "buf" can be abandoned, either by making it * hidden, autowriting it or unloading it. */ -int can_abandon(buf, forceit) -buf_T *buf; -int forceit; +int can_abandon(buf_T *buf, int forceit) { return P_HID(buf) || !bufIsChanged(buf) @@ -1316,10 +1303,7 @@ static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr)); /* * Add a buffer number to "bufnrs", unless it's already there. */ -static void add_bufnum(bufnrs, bufnump, nr) -int *bufnrs; -int *bufnump; -int nr; +static void add_bufnum(int *bufnrs, int *bufnump, int nr) { int i; @@ -1334,8 +1318,10 @@ int nr; * Return TRUE if any buffer was changed and cannot be abandoned. * That changed buffer becomes the current buffer. */ -int check_changed_any(hidden) -int hidden; /* Only check hidden buffers */ +int +check_changed_any ( + int hidden /* Only check hidden buffers */ +) { int ret = FALSE; buf_T *buf; @@ -1440,7 +1426,7 @@ theend: * return FAIL if there is no file name, OK if there is one * give error message for FAIL */ -int check_fname() { +int check_fname(void) { if (curbuf->b_ffname == NULL) { EMSG(_(e_noname)); return FAIL; @@ -1453,9 +1439,7 @@ int check_fname() { * * return FAIL for failure, OK otherwise */ -int buf_write_all(buf, forceit) -buf_T *buf; -int forceit; +int buf_write_all(buf_T *buf, int forceit) { int retval; buf_T *old_curbuf = curbuf; @@ -1488,8 +1472,7 @@ static int alist_add_list __ARGS((int count, char_u **files, int after)); * Changes the argument in-place, puts a NUL after it. Backticks remain. * Return a pointer to the start of the next argument. */ -static char_u * do_one_arg(str) -char_u *str; +static char_u *do_one_arg(char_u *str) { char_u *p; int inbacktick; @@ -1520,9 +1503,7 @@ char_u *str; * Separate the arguments in "str" and return a list of pointers in the * growarray "gap". */ -int get_arglist(gap, str) -garray_T *gap; -char_u *str; +int get_arglist(garray_T *gap, char_u *str) { ga_init2(gap, (int)sizeof(char_u *), 20); while (*str != NUL) { @@ -1543,11 +1524,7 @@ char_u *str; * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'. * Return FAIL or OK. */ -int get_arglist_exp(str, fcountp, fnamesp, wig) -char_u *str; -int *fcountp; -char_u ***fnamesp; -int wig; +int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, int wig) { garray_T ga; int i; @@ -1573,10 +1550,12 @@ int wig; * * Return FAIL for failure, OK otherwise. */ -static int do_arglist(str, what, after) -char_u *str; -int what UNUSED; -int after UNUSED; /* 0 means before first one */ +static int +do_arglist ( + char_u *str, + int what, + int after /* 0 means before first one */ +) { garray_T new_ga; int exp_count; @@ -1657,7 +1636,7 @@ int after UNUSED; /* 0 means before first one */ /* * Check the validity of the arg_idx for each other window. */ -static void alist_check_arg_idx() { +static void alist_check_arg_idx(void) { win_T *win; tabpage_T *tp; @@ -1670,8 +1649,7 @@ static void alist_check_arg_idx() { * Return TRUE if window "win" is editing the file at the current argument * index. */ -static int editing_arg_idx(win) -win_T *win; +static int editing_arg_idx(win_T *win) { return !(win->w_arg_idx >= WARGCOUNT(win) || (win->w_buffer->b_fnum @@ -1685,8 +1663,7 @@ win_T *win; /* * Check if window "win" is editing the w_arg_idx file in its argument list. */ -void check_arg_idx(win) -win_T *win; +void check_arg_idx(win_T *win) { if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) { /* We are not editing the current entry in the argument list. @@ -1716,8 +1693,7 @@ win_T *win; /* * ":args", ":argslocal" and ":argsglobal". */ -void ex_args(eap) -exarg_T *eap; +void ex_args(exarg_T *eap) { int i; @@ -1773,8 +1749,7 @@ exarg_T *eap; /* * ":previous", ":sprevious", ":Next" and ":sNext". */ -void ex_previous(eap) -exarg_T *eap; +void ex_previous(exarg_T *eap) { /* If past the last one already, go to the last one. */ if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) @@ -1786,8 +1761,7 @@ exarg_T *eap; /* * ":rewind", ":first", ":sfirst" and ":srewind". */ -void ex_rewind(eap) -exarg_T *eap; +void ex_rewind(exarg_T *eap) { do_argfile(eap, 0); } @@ -1795,8 +1769,7 @@ exarg_T *eap; /* * ":last" and ":slast". */ -void ex_last(eap) -exarg_T *eap; +void ex_last(exarg_T *eap) { do_argfile(eap, ARGCOUNT - 1); } @@ -1804,8 +1777,7 @@ exarg_T *eap; /* * ":argument" and ":sargument". */ -void ex_argument(eap) -exarg_T *eap; +void ex_argument(exarg_T *eap) { int i; @@ -1819,9 +1791,7 @@ exarg_T *eap; /* * Edit file "argn" of the argument lists. */ -void do_argfile(eap, argn) -exarg_T *eap; -int argn; +void do_argfile(exarg_T *eap, int argn) { int other; char_u *p; @@ -1884,8 +1854,7 @@ int argn; /* * ":next", and commands that behave like it. */ -void ex_next(eap) -exarg_T *eap; +void ex_next(exarg_T *eap) { int i; @@ -1911,8 +1880,7 @@ exarg_T *eap; /* * ":argedit" */ -void ex_argedit(eap) -exarg_T *eap; +void ex_argedit(exarg_T *eap) { int fnum; int i; @@ -1946,8 +1914,7 @@ exarg_T *eap; /* * ":argadd" */ -void ex_argadd(eap) -exarg_T *eap; +void ex_argadd(exarg_T *eap) { do_arglist(eap->arg, AL_ADD, eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); @@ -1957,8 +1924,7 @@ exarg_T *eap; /* * ":argdelete" */ -void ex_argdelete(eap) -exarg_T *eap; +void ex_argdelete(exarg_T *eap) { int i; int n; @@ -1991,8 +1957,7 @@ exarg_T *eap; /* * ":argdo", ":windo", ":bufdo", ":tabdo" */ -void ex_listdo(eap) -exarg_T *eap; +void ex_listdo(exarg_T *eap) { int i; win_T *wp; @@ -2120,10 +2085,12 @@ exarg_T *eap; * Files[] itself is not taken over. * Returns index of first added argument. Returns -1 when failed (out of mem). */ -static int alist_add_list(count, files, after) -int count; -char_u **files; -int after; /* where to add: 0 = before first one */ +static int +alist_add_list ( + int count, + char_u **files, + int after /* where to add: 0 = before first one */ +) { int i; @@ -2154,8 +2121,7 @@ int after; /* where to add: 0 = before first one */ /* * ":compiler[!] {name}" */ -void ex_compiler(eap) -exarg_T *eap; +void ex_compiler(exarg_T *eap) { char_u *buf; char_u *old_cur_comp = NULL; @@ -2216,17 +2182,14 @@ exarg_T *eap; /* * ":runtime {name}" */ -void ex_runtime(eap) -exarg_T *eap; +void ex_runtime(exarg_T *eap) { source_runtime(eap->arg, eap->forceit); } static void source_callback __ARGS((char_u *fname, void *cookie)); -static void source_callback(fname, cookie) -char_u *fname; -void *cookie UNUSED; +static void source_callback(char_u *fname, void *cookie) { (void)do_source(fname, FALSE, DOSO_NONE); } @@ -2237,9 +2200,7 @@ void *cookie UNUSED; * When "all" is TRUE, source all files, otherwise only the first one. * return FAIL when no file could be sourced, OK otherwise. */ -int source_runtime(name, all) -char_u *name; -int all; +int source_runtime(char_u *name, int all) { return do_in_runtimepath(name, all, source_callback, NULL); } @@ -2339,8 +2300,7 @@ void *cookie; /* * ":options" */ -void ex_options(eap) -exarg_T *eap UNUSED; +void ex_options(exarg_T *eap) { cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); } @@ -2348,15 +2308,12 @@ exarg_T *eap UNUSED; /* * ":source {fname}" */ -void ex_source(eap) -exarg_T *eap; +void ex_source(exarg_T *eap) { cmd_source(eap->arg, eap); } -static void cmd_source(fname, eap) -char_u *fname; -exarg_T *eap; +static void cmd_source(char_u *fname, exarg_T *eap) { if (*fname == NUL) EMSG(_(e_argreq)); @@ -2406,8 +2363,7 @@ struct source_cookie { /* * Return the address holding the next breakpoint line for a source cookie. */ -linenr_T * source_breakpoint(cookie) -void *cookie; +linenr_T *source_breakpoint(void *cookie) { return &((struct source_cookie *)cookie)->breakpoint; } @@ -2415,8 +2371,7 @@ void *cookie; /* * Return the address holding the debug tick for a source cookie. */ -int * source_dbg_tick(cookie) -void *cookie; +int *source_dbg_tick(void *cookie) { return &((struct source_cookie *)cookie)->dbg_tick; } @@ -2424,8 +2379,7 @@ void *cookie; /* * Return the nesting level for a source cookie. */ -int source_level(cookie) -void *cookie; +int source_level(void *cookie) { return ((struct source_cookie *)cookie)->level; } @@ -2440,8 +2394,7 @@ static FILE *fopen_noinh_readbin __ARGS((char *filename)); * Special function to open a file without handle inheritance. * When possible the handle is closed on exec(). */ -static FILE * fopen_noinh_readbin(filename) -char *filename; +static FILE *fopen_noinh_readbin(char *filename) { int fd_tmp = mch_open(filename, O_RDONLY, 0); @@ -2468,10 +2421,12 @@ char *filename; * * return FAIL if file could not be opened, OK otherwise */ -int do_source(fname, check_other, is_vimrc) -char_u *fname; -int check_other; /* check for .vimrc and _vimrc */ -int is_vimrc; /* DOSO_ value */ +int +do_source ( + char_u *fname, + int check_other, /* check for .vimrc and _vimrc */ + int is_vimrc /* DOSO_ value */ +) { struct source_cookie cookie; char_u *save_sourcing_name; @@ -2773,8 +2728,7 @@ theend: /* * ":scriptnames" */ -void ex_scriptnames(eap) -exarg_T *eap UNUSED; +void ex_scriptnames(exarg_T *eap) { int i; @@ -2790,7 +2744,7 @@ exarg_T *eap UNUSED; /* * Fix slashes in the list of script names for 'shellslash'. */ -void scriptnames_slash_adjust() { +void scriptnames_slash_adjust(void) { int i; for (i = 1; i <= script_items.ga_len; ++i) @@ -2803,8 +2757,7 @@ void scriptnames_slash_adjust() { /* * Get a pointer to a script name. Used for ":verbose set". */ -char_u * get_scriptname(id) -scid_T id; +char_u *get_scriptname(scid_T id) { if (id == SID_MODELINE) return (char_u *)_("modeline"); @@ -2820,7 +2773,7 @@ scid_T id; } # if defined(EXITFREE) || defined(PROTO) -void free_scriptnames() { +void free_scriptnames(void) { int i; for (i = script_items.ga_len; i > 0; --i) @@ -2840,10 +2793,7 @@ void free_scriptnames() { * Test with earlier versions, MSL 2.2 is the library supplied with * Codewarrior Pro 2. */ -char * fgets_cr(s, n, stream) -char *s; -int n; -FILE *stream; +char *fgets_cr(char *s, int n, FILE *stream) { return fgets(s, n, stream); } @@ -2854,10 +2804,7 @@ FILE *stream; * For older versions of the Metrowerks library. * At least CodeWarrior 9 needed this code. */ -char * fgets_cr(s, n, stream) -char *s; -int n; -FILE *stream; +char *fgets_cr(char *s, int n, FILE *stream) { int c = 0; int char_read = 0; @@ -2893,10 +2840,7 @@ FILE *stream; * Return a pointer to the line in allocated memory. * Return NULL for end-of-file or some error. */ -char_u * getsourceline(c, cookie, indent) -int c UNUSED; -void *cookie; -int indent UNUSED; +char_u *getsourceline(int c, void *cookie, int indent) { struct source_cookie *sp = (struct source_cookie *)cookie; char_u *line; @@ -2987,8 +2931,7 @@ int indent UNUSED; return line; } -static char_u * get_one_sourceline(sp) -struct source_cookie *sp; +static char_u *get_one_sourceline(struct source_cookie *sp) { garray_T ga; int len; @@ -3126,7 +3069,7 @@ struct source_cookie *sp; * When skipping lines it may not actually be executed, but we won't find out * until later and we need to store the time now. */ -void script_line_start() { +void script_line_start(void) { scriptitem_T *si; sn_prl_T *pp; @@ -3157,7 +3100,7 @@ void script_line_start() { /* * Called when actually executing a function line. */ -void script_line_exec() { +void script_line_exec(void) { scriptitem_T *si; if (current_SID <= 0 || current_SID > script_items.ga_len) @@ -3170,7 +3113,7 @@ void script_line_exec() { /* * Called when done with a function line. */ -void script_line_end() { +void script_line_end(void) { scriptitem_T *si; sn_prl_T *pp; @@ -3196,8 +3139,7 @@ void script_line_end() { * ":scriptencoding": Set encoding conversion for a sourced script. * Without the multi-byte feature it's simply ignored. */ -void ex_scriptencoding(eap) -exarg_T *eap UNUSED; +void ex_scriptencoding(exarg_T *eap) { struct source_cookie *sp; char_u *name; @@ -3225,8 +3167,7 @@ exarg_T *eap UNUSED; /* * ":finish": Mark a sourced file as finished. */ -void ex_finish(eap) -exarg_T *eap; +void ex_finish(exarg_T *eap) { if (getline_equal(eap->getline, eap->cookie, getsourceline)) do_finish(eap, FALSE); @@ -3239,9 +3180,7 @@ exarg_T *eap; * Also called for a pending finish at the ":endtry" or after returning from * an extra do_cmdline(). "reanimate" is used in the latter case. */ -void do_finish(eap, reanimate) -exarg_T *eap; -int reanimate; +void do_finish(exarg_T *eap, int reanimate) { int idx; @@ -3282,8 +3221,7 @@ void *cookie; /* * ":checktime [buffer]" */ -void ex_checktime(eap) -exarg_T *eap; +void ex_checktime(exarg_T *eap) { buf_T *buf; int save_no_check_timestamps = no_check_timestamps; @@ -3304,8 +3242,7 @@ exarg_T *eap; # define HAVE_GET_LOCALE_VAL static char *get_locale_val __ARGS((int what)); -static char * get_locale_val(what) -int what; +static char *get_locale_val(int what) { char *loc; @@ -3324,7 +3261,7 @@ int what; * Obtain the current messages language. Used to set the default for * 'helplang'. May return NULL or an empty string. */ -char_u * get_mess_lang() { +char_u *get_mess_lang(void) { char_u *p; # ifdef HAVE_GET_LOCALE_VAL @@ -3355,7 +3292,7 @@ static char_u *get_mess_env __ARGS((void)); /* * Get the language used for messages from the environment. */ -static char_u * get_mess_env() { +static char_u *get_mess_env(void) { char_u *p; p = mch_getenv((char_u *)"LC_ALL"); @@ -3381,7 +3318,7 @@ static char_u * get_mess_env() { * Set the "v:lang" variable according to the current locale setting. * Also do "v:lc_time"and "v:ctype". */ -void set_lang_var() { +void set_lang_var(void) { char_u *loc; # ifdef HAVE_GET_LOCALE_VAL @@ -3411,8 +3348,7 @@ void set_lang_var() { /* * ":language": Set the language (locale). */ -void ex_language(eap) -exarg_T *eap; +void ex_language(exarg_T *eap) { char *loc; char_u *p; @@ -3519,7 +3455,7 @@ static char_u **find_locales __ARGS((void)); /* * Lazy initialization of all available locales. */ -static void init_locales() { +static void init_locales(void) { if (!did_init_locales) { did_init_locales = TRUE; locales = find_locales(); @@ -3528,7 +3464,7 @@ static void init_locales() { /* Return an array of strings for all available locales + NULL for the * last element. Return NULL in case of error. */ -static char_u ** find_locales() { +static char_u **find_locales(void) { garray_T locales_ga; char_u *loc; @@ -3564,7 +3500,7 @@ static char_u ** find_locales() { } # if defined(EXITFREE) || defined(PROTO) -void free_locales() { +void free_locales(void) { int i; if (locales != NULL) { for (i = 0; locales[i] != NULL; i++) @@ -3580,9 +3516,7 @@ void free_locales() { * Function given to ExpandGeneric() to obtain the possible arguments of the * ":language" command. */ -char_u * get_lang_arg(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_lang_arg(expand_T *xp, int idx) { if (idx == 0) return (char_u *)"messages"; @@ -3600,9 +3534,7 @@ int idx; /* * Function given to ExpandGeneric() to obtain the available locales. */ -char_u * get_locales(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_locales(expand_T *xp, int idx) { init_locales(); if (locales == NULL) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 88fe8e1c5d..942a0f28c5 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -303,8 +303,7 @@ struct dbg_stuff { static void save_dbg_stuff __ARGS((struct dbg_stuff *dsp)); static void restore_dbg_stuff __ARGS((struct dbg_stuff *dsp)); -static void save_dbg_stuff(dsp) -struct dbg_stuff *dsp; +static void save_dbg_stuff(struct dbg_stuff *dsp) { dsp->trylevel = trylevel; trylevel = 0; dsp->force_abort = force_abort; force_abort = FALSE; @@ -321,8 +320,7 @@ struct dbg_stuff *dsp; dsp->current_exception = current_exception; current_exception = NULL; } -static void restore_dbg_stuff(dsp) -struct dbg_stuff *dsp; +static void restore_dbg_stuff(struct dbg_stuff *dsp) { suppress_errthrow = FALSE; trylevel = dsp->trylevel; @@ -343,8 +341,10 @@ struct dbg_stuff *dsp; * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi" * command is given. */ -void do_exmode(improved) -int improved; /* TRUE for "improved Ex" mode */ +void +do_exmode ( + int improved /* TRUE for "improved Ex" mode */ +) { int save_msg_scroll; int prev_msg_row; @@ -421,8 +421,7 @@ int improved; /* TRUE for "improved Ex" mode */ /* * Execute a simple command line. Used for translated commands like "*". */ -int do_cmdline_cmd(cmd) -char_u *cmd; +int do_cmdline_cmd(char_u *cmd) { return do_cmdline(cmd, NULL, NULL, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); @@ -1125,10 +1124,7 @@ int flags; /* * Obtain a line when inside a ":while" or ":for" loop. */ -static char_u * get_loop_line(c, cookie, indent) -int c; -void *cookie; -int indent; +static char_u *get_loop_line(int c, void *cookie, int indent) { struct loop_cookie *cp = (struct loop_cookie *)cookie; wcmd_T *wp; @@ -1159,9 +1155,7 @@ int indent; /* * Store a line in "gap" so that a ":while" loop can execute it again. */ -static int store_loop_line(gap, line) -garray_T *gap; -char_u *line; +static int store_loop_line(garray_T *gap, char_u *line) { if (ga_grow(gap, 1) == FAIL) return FAIL; @@ -1174,8 +1168,7 @@ char_u *line; /* * Free the lines stored for a ":while" or ":for" loop. */ -static void free_cmdlines(gap) -garray_T *gap; +static void free_cmdlines(garray_T *gap) { while (gap->ga_len > 0) { vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line); @@ -1189,7 +1182,7 @@ garray_T *gap; */ int getline_equal(fgetline, cookie, func) char_u *(*fgetline)__ARGS((int, void *, int)); -void *cookie UNUSED; /* argument for fgetline() */ +void *cookie; /* argument for fgetline() */ char_u *(*func)__ARGS((int, void *, int)); { char_u *(*gp)__ARGS((int, void *, int)); @@ -1212,7 +1205,7 @@ char_u *(*func)__ARGS((int, void *, int)); * getline function. Otherwise return "cookie". */ void * getline_cookie(fgetline, cookie) -char_u *(*fgetline)__ARGS((int, void *, int)) UNUSED; +char_u *(*fgetline)__ARGS((int, void *, int)); void *cookie; /* argument for fgetline() */ { char_u *(*gp)__ARGS((int, void *, int)); @@ -2150,10 +2143,12 @@ doend: * Check for an Ex command with optional tail. * If there is a match advance "pp" to the argument and return TRUE. */ -int checkforcmd(pp, cmd, len) -char_u **pp; /* start of command */ -char *cmd; /* name of command */ -int len; /* required length */ +int +checkforcmd ( + char_u **pp, /* start of command */ + char *cmd, /* name of command */ + int len /* required length */ +) { int i; @@ -2172,8 +2167,7 @@ int len; /* required length */ * Takes care of limiting the length and handling 0xa0, which would be * invisible otherwise. */ -static void append_command(cmd) -char_u *cmd; +static void append_command(char_u *cmd) { char_u *s = cmd; char_u *d; @@ -2202,9 +2196,7 @@ char_u *cmd; * "full" is set to TRUE if the whole command name matched. * Returns NULL for an ambiguous user command. */ -static char_u * find_command(eap, full) -exarg_T *eap; -int *full UNUSED; +static char_u *find_command(exarg_T *eap, int *full) { int len; char_u *p; @@ -2296,12 +2288,14 @@ int *full UNUSED; * Return a pointer to just after the command. * Return NULL if there is no matching command. */ -static char_u * find_ucmd(eap, p, full, xp, compl) -exarg_T *eap; -char_u *p; /* end of the command (possibly including count) */ -int *full; /* set to TRUE for a full match */ -expand_T *xp; /* used for completion, NULL otherwise */ -int *compl; /* completion flags or NULL */ +static char_u * +find_ucmd ( + exarg_T *eap, + char_u *p, /* end of the command (possibly including count) */ + int *full, /* set to TRUE for a full match */ + expand_T *xp, /* used for completion, NULL otherwise */ + int *compl /* completion flags or NULL */ +) { int len = (int)(p - eap->cmd); int j, k, matchlen = 0; @@ -2423,8 +2417,7 @@ static struct cmdmod { * Return length of a command modifier (including optional count). * Return zero when it's not a modifier. */ -int modifier_len(cmd) -char_u *cmd; +int modifier_len(char_u *cmd) { int i, j; char_u *p = cmd; @@ -2447,8 +2440,7 @@ char_u *cmd; * Return 2 if there is an exact match. * Return 3 if there is an ambiguous match. */ -int cmd_exists(name) -char_u *name; +int cmd_exists(char_u *name) { exarg_T ea; int full = FALSE; @@ -2486,9 +2478,11 @@ char_u *name; * perfectly compatible with each other, but then the command line syntax * probably won't change that much -- webb. */ -char_u * set_one_cmd_context(xp, buff) -expand_T *xp; -char_u *buff; /* buffer for command string */ +char_u * +set_one_cmd_context ( + expand_T *xp, + char_u *buff /* buffer for command string */ +) { char_u *p; char_u *cmd, *arg; @@ -3210,9 +3204,11 @@ char_u *buff; /* buffer for command string */ * Also skip white space and ":" characters. * Returns the "cmd" pointer advanced to beyond the range. */ -char_u * skip_range(cmd, ctx) -char_u *cmd; -int *ctx; /* pointer to xp_context or NULL */ +char_u * +skip_range ( + char_u *cmd, + int *ctx /* pointer to xp_context or NULL */ +) { unsigned delim; @@ -3247,10 +3243,12 @@ int *ctx; /* pointer to xp_context or NULL */ * * Return MAXLNUM when no Ex address was found. */ -static linenr_T get_address(ptr, skip, to_other_file) -char_u **ptr; -int skip; /* only skip the address, don't use it */ -int to_other_file; /* flag: may jump to other file */ +static linenr_T +get_address ( + char_u **ptr, + int skip, /* only skip the address, don't use it */ + int to_other_file /* flag: may jump to other file */ +) { int c; int i; @@ -3417,8 +3415,7 @@ error: /* * Get flags from an Ex command argument. */ -static void get_flags(eap) -exarg_T *eap; +static void get_flags(exarg_T *eap) { while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL) { if (*eap->arg == 'l') @@ -3434,8 +3431,7 @@ exarg_T *eap; /* * Function called for command which is Not Implemented. NI! */ -void ex_ni(eap) -exarg_T *eap; +void ex_ni(exarg_T *eap) { if (!eap->skip) eap->errmsg = (char_u *)N_( @@ -3447,8 +3443,7 @@ exarg_T *eap; * Function called for script command which is Not Implemented. NI! * Skips over ":perl <skip) ex_ni(eap); @@ -3461,8 +3456,7 @@ exarg_T *eap; * Check range in Ex command for validity. * Return NULL when valid, error message when invalid. */ -static char_u * invalid_range(eap) -exarg_T *eap; +static char_u *invalid_range(exarg_T *eap) { if ( eap->line1 < 0 || eap->line2 < 0 @@ -3479,8 +3473,7 @@ exarg_T *eap; /* * Correct the range for zero line number, if required. */ -static void correct_range(eap) -exarg_T *eap; +static void correct_range(exarg_T *eap) { if (!(eap->argt & ZEROR)) { /* zero in range not allowed */ if (eap->line1 == 0) @@ -3496,8 +3489,7 @@ static char_u *skip_grep_pat __ARGS((exarg_T *eap)); * For a ":vimgrep" or ":vimgrepadd" command return a pointer past the * pattern. Otherwise return eap->arg. */ -static char_u * skip_grep_pat(eap) -exarg_T *eap; +static char_u *skip_grep_pat(exarg_T *eap) { char_u *p = eap->arg; @@ -3516,10 +3508,7 @@ exarg_T *eap; * For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option * in the command line, so that things like % get expanded. */ -static char_u * replace_makeprg(eap, p, cmdlinep) -exarg_T *eap; -char_u *p; -char_u **cmdlinep; +static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep) { char_u *new_cmdline; char_u *program; @@ -3591,10 +3580,7 @@ char_u **cmdlinep; * Expand file name in Ex command argument. * Return FAIL for failure, OK otherwise. */ -int expand_filename(eap, cmdlinep, errormsgp) -exarg_T *eap; -char_u **cmdlinep; -char_u **errormsgp; +int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp) { int has_wildcards; /* need to expand wildcards */ char_u *repl; @@ -3812,12 +3798,7 @@ char_u **errormsgp; * Returns a pointer to the character after the replaced string. * Returns NULL for failure. */ -static char_u * repl_cmdline(eap, src, srclen, repl, cmdlinep) -exarg_T *eap; -char_u *src; -int srclen; -char_u *repl; -char_u **cmdlinep; +static char_u *repl_cmdline(exarg_T *eap, char_u *src, int srclen, char_u *repl, char_u **cmdlinep) { int len; int i; @@ -3867,8 +3848,7 @@ char_u **cmdlinep; /* * Check for '|' to separate commands and '"' to start comments. */ -void separate_nextcmd(eap) -exarg_T *eap; +void separate_nextcmd(exarg_T *eap) { char_u *p; @@ -3921,8 +3901,7 @@ exarg_T *eap; /* * get + command from ex argument */ -static char_u * getargcmd(argp) -char_u **argp; +static char_u *getargcmd(char_u **argp) { char_u *arg = *argp; char_u *command = NULL; @@ -3947,9 +3926,11 @@ char_u **argp; /* * Find end of "+command" argument. Skip over "\ " and "\\". */ -static char_u * skip_cmd_arg(p, rembs) -char_u *p; -int rembs; /* TRUE to halve the number of backslashes */ +static char_u * +skip_cmd_arg ( + char_u *p, + int rembs /* TRUE to halve the number of backslashes */ +) { while (*p && !vim_isspace(*p)) { if (*p == '\\' && p[1] != NUL) { @@ -3967,8 +3948,7 @@ int rembs; /* TRUE to halve the number of backslashes */ * Get "++opt=arg" argument. * Return FAIL or OK. */ -static int getargopt(eap) -exarg_T *eap; +static int getargopt(exarg_T *eap) { char_u *arg = eap->arg + 2; int *pp = NULL; @@ -4048,8 +4028,7 @@ exarg_T *eap; /* * ":abbreviate" and friends. */ -static void ex_abbreviate(eap) -exarg_T *eap; +static void ex_abbreviate(exarg_T *eap) { do_exmap(eap, TRUE); /* almost the same as mapping */ } @@ -4057,8 +4036,7 @@ exarg_T *eap; /* * ":map" and friends. */ -static void ex_map(eap) -exarg_T *eap; +static void ex_map(exarg_T *eap) { /* * If we are sourcing .exrc or .vimrc in current directory we @@ -4075,8 +4053,7 @@ exarg_T *eap; /* * ":unmap" and friends. */ -static void ex_unmap(eap) -exarg_T *eap; +static void ex_unmap(exarg_T *eap) { do_exmap(eap, FALSE); } @@ -4084,8 +4061,7 @@ exarg_T *eap; /* * ":mapclear" and friends. */ -static void ex_mapclear(eap) -exarg_T *eap; +static void ex_mapclear(exarg_T *eap) { map_clear(eap->cmd, eap->arg, eap->forceit, FALSE); } @@ -4093,14 +4069,12 @@ exarg_T *eap; /* * ":abclear" and friends. */ -static void ex_abclear(eap) -exarg_T *eap; +static void ex_abclear(exarg_T *eap) { map_clear(eap->cmd, eap->arg, TRUE, TRUE); } -static void ex_autocmd(eap) -exarg_T *eap; +static void ex_autocmd(exarg_T *eap) { /* * Disallow auto commands from .exrc and .vimrc in current @@ -4118,8 +4092,7 @@ exarg_T *eap; /* * ":doautocmd": Apply the automatic commands to the current buffer. */ -static void ex_doautocmd(eap) -exarg_T *eap; +static void ex_doautocmd(exarg_T *eap) { char_u *arg = eap->arg; int call_do_modelines = check_nomodeline(&arg); @@ -4134,8 +4107,7 @@ exarg_T *eap; * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list * :[N]bwipeout[!] [N] [bufname] delete buffer really */ -static void ex_bunload(eap) -exarg_T *eap; +static void ex_bunload(exarg_T *eap) { eap->errmsg = do_bufdel( eap->cmdidx == CMD_bdelete ? DOBUF_DEL @@ -4148,8 +4120,7 @@ exarg_T *eap; * :[N]buffer [N] to buffer N * :[N]sbuffer [N] to buffer N */ -static void ex_buffer(eap) -exarg_T *eap; +static void ex_buffer(exarg_T *eap) { if (*eap->arg) eap->errmsg = e_trailing; @@ -4165,8 +4136,7 @@ exarg_T *eap; * :[N]bmodified [N] to next mod. buffer * :[N]sbmodified [N] to next mod. buffer */ -static void ex_bmodified(eap) -exarg_T *eap; +static void ex_bmodified(exarg_T *eap) { goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2); } @@ -4175,8 +4145,7 @@ exarg_T *eap; * :[N]bnext [N] to next buffer * :[N]sbnext [N] split and to next buffer */ -static void ex_bnext(eap) -exarg_T *eap; +static void ex_bnext(exarg_T *eap) { goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2); } @@ -4187,8 +4156,7 @@ exarg_T *eap; * :[N]sbNext [N] split and to previous buffer * :[N]sbprevious [N] split and to previous buffer */ -static void ex_bprevious(eap) -exarg_T *eap; +static void ex_bprevious(exarg_T *eap) { goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2); } @@ -4199,8 +4167,7 @@ exarg_T *eap; * :sbrewind split and to first buffer * :sbfirst split and to first buffer */ -static void ex_brewind(eap) -exarg_T *eap; +static void ex_brewind(exarg_T *eap) { goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); } @@ -4209,14 +4176,12 @@ exarg_T *eap; * :blast to last buffer * :sblast split and to last buffer */ -static void ex_blast(eap) -exarg_T *eap; +static void ex_blast(exarg_T *eap) { goto_buffer(eap, DOBUF_LAST, BACKWARD, 0); } -int ends_excmd(c) -int c; +int ends_excmd(int c) { return c == NUL || c == '|' || c == '"' || c == '\n'; } @@ -4227,8 +4192,7 @@ int c; * Return the next command, after the first '|' or '\n'. * Return NULL if not found. */ -char_u * find_nextcmd(p) -char_u *p; +char_u *find_nextcmd(char_u *p) { while (*p != '|' && *p != '\n') { if (*p == NUL) @@ -4243,8 +4207,7 @@ char_u *p; * Check if *p is a separator between Ex commands. * Return NULL if it isn't, (p + 1) if it is. */ -char_u * check_nextcmd(p) -char_u *p; +char_u *check_nextcmd(char_u *p) { p = skipwhite(p); if (*p == '|' || *p == '\n') @@ -4261,9 +4224,11 @@ char_u *p; * return FAIL and give error message if 'message' TRUE * return OK otherwise */ -static int check_more(message, forceit) -int message; /* when FALSE check only, no messages */ -int forceit; +static int +check_more ( + int message, /* when FALSE check only, no messages */ + int forceit +) { int n = ARGCOUNT - curwin->w_arg_idx - 1; @@ -4298,9 +4263,7 @@ int forceit; /* * Function given to ExpandGeneric() to obtain the list of command names. */ -char_u * get_command_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_command_name(expand_T *xp, int idx) { if (idx >= (int)CMD_SIZE) return get_user_command_name(idx); @@ -4321,18 +4284,7 @@ static size_t uc_check_code __ARGS((char_u *code, size_t len, char_u *buf, *split_buf, size_t *split_len)); -static int uc_add_command(name, name_len, rep, argt, def, flags, compl, - compl_arg, - force) -char_u *name; -size_t name_len; -char_u *rep; -long argt; -long def; -int flags; -int compl; -char_u *compl_arg; -int force; +static int uc_add_command(char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, char_u *compl_arg, int force) { ucmd_T *cmd = NULL; char_u *p; @@ -4466,9 +4418,7 @@ static struct { {0, NULL} }; -static void uc_list(name, name_len) -char_u *name; -size_t name_len; +static void uc_list(char_u *name, size_t name_len) { int i, j; int found = FALSE; @@ -4576,7 +4526,7 @@ size_t name_len; MSG(_("No user-defined commands found")); } -static char_u * uc_fun_cmd() { +static char_u *uc_fun_cmd(void) { static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4, 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60, 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2, @@ -4589,14 +4539,7 @@ static char_u * uc_fun_cmd() { return IObuff; } -static int uc_scan_attr(attr, len, argt, def, flags, compl, compl_arg) -char_u *attr; -size_t len; -long *argt; -long *def; -int *flags; -int *compl; -char_u **compl_arg; +static int uc_scan_attr(char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl, char_u **compl_arg) { char_u *p; @@ -4710,8 +4653,7 @@ invalid_count: /* * ":command ..." */ -static void ex_command(eap) -exarg_T *eap; +static void ex_command(exarg_T *eap) { char_u *name; char_u *end; @@ -4771,8 +4713,7 @@ exarg_T *eap; * ":comclear" * Clear all user commands, global and for current buffer. */ -void ex_comclear(eap) -exarg_T *eap UNUSED; +void ex_comclear(exarg_T *eap) { uc_clear(&ucmds); uc_clear(&curbuf->b_ucmds); @@ -4781,8 +4722,7 @@ exarg_T *eap UNUSED; /* * Clear all user commands for "gap". */ -void uc_clear(gap) -garray_T *gap; +void uc_clear(garray_T *gap) { int i; ucmd_T *cmd; @@ -4796,8 +4736,7 @@ garray_T *gap; ga_clear(gap); } -static void ex_delcommand(eap) -exarg_T *eap; +static void ex_delcommand(exarg_T *eap) { int i = 0; ucmd_T *cmd = NULL; @@ -4835,9 +4774,7 @@ exarg_T *eap; /* * split and quote args for */ -static char_u * uc_split_args(arg, lenp) -char_u *arg; -size_t *lenp; +static char_u *uc_split_args(char_u *arg, size_t *lenp) { char_u *buf; char_u *p; @@ -4917,14 +4854,16 @@ size_t *lenp; * Returns the length of the replacement, which has been added to "buf". * Returns -1 if there was no match, and only the "<" has been copied. */ -static size_t uc_check_code(code, len, buf, cmd, eap, split_buf, split_len) -char_u *code; -size_t len; -char_u *buf; -ucmd_T *cmd; /* the user command we're expanding */ -exarg_T *eap; /* ex arguments */ -char_u **split_buf; -size_t *split_len; +static size_t +uc_check_code ( + char_u *code, + size_t len, + char_u *buf, + ucmd_T *cmd, /* the user command we're expanding */ + exarg_T *eap, /* ex arguments */ + char_u **split_buf, + size_t *split_len +) { size_t result = 0; char_u *p = code + 1; @@ -5094,8 +5033,7 @@ size_t *split_len; return result; } -static void do_ucmd(eap) -exarg_T *eap; +static void do_ucmd(exarg_T *eap) { char_u *buf; char_u *p; @@ -5203,8 +5141,7 @@ exarg_T *eap; vim_free(split_buf); } -static char_u * get_user_command_name(idx) -int idx; +static char_u *get_user_command_name(int idx) { return get_user_commands(NULL, idx - (int)CMD_SIZE); } @@ -5212,9 +5149,7 @@ int idx; /* * Function given to ExpandGeneric() to obtain the list of user command names. */ -char_u * get_user_commands(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_user_commands(expand_T *xp, int idx) { if (idx < curbuf->b_ucmds.ga_len) return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name; @@ -5228,9 +5163,7 @@ int idx; * Function given to ExpandGeneric() to obtain the list of user command * attributes. */ -char_u * get_user_cmd_flags(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_user_cmd_flags(expand_T *xp, int idx) { static char *user_cmd_flags[] = {"bang", "bar", "buffer", "complete", "count", @@ -5244,9 +5177,7 @@ int idx; /* * Function given to ExpandGeneric() to obtain the list of values for -nargs. */ -char_u * get_user_cmd_nargs(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_user_cmd_nargs(expand_T *xp, int idx) { static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; @@ -5258,9 +5189,7 @@ int idx; /* * Function given to ExpandGeneric() to obtain the list of values for -complete. */ -char_u * get_user_cmd_complete(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_user_cmd_complete(expand_T *xp, int idx) { return (char_u *)command_complete[idx].name; } @@ -5273,12 +5202,7 @@ int idx; * copied to allocated memory and stored in "*compl_arg". * Returns FAIL if something is wrong. */ -int parse_compl_arg(value, vallen, complp, argt, compl_arg) -char_u *value; -int vallen; -int *complp; -long *argt; -char_u **compl_arg UNUSED; +int parse_compl_arg(char_u *value, int vallen, int *complp, long *argt, char_u **compl_arg) { char_u *arg = NULL; size_t arglen = 0; @@ -5330,8 +5254,7 @@ char_u **compl_arg UNUSED; return OK; } -static void ex_colorscheme(eap) -exarg_T *eap; +static void ex_colorscheme(exarg_T *eap) { if (*eap->arg == NUL) { char_u *expr = vim_strsave((char_u *)"g:colors_name"); @@ -5352,8 +5275,7 @@ exarg_T *eap; EMSG2(_("E185: Cannot find color scheme '%s'"), eap->arg); } -static void ex_highlight(eap) -exarg_T *eap; +static void ex_highlight(exarg_T *eap) { if (*eap->arg == NUL && eap->cmd[2] == '!') MSG(_("Greetings, Vim user!")); @@ -5365,7 +5287,7 @@ exarg_T *eap; * Call this function if we thought we were going to exit, but we won't * (because of an error). May need to restore the terminal mode. */ -void not_exiting() { +void not_exiting(void) { exiting = FALSE; settmode(TMODE_RAW); } @@ -5373,8 +5295,7 @@ void not_exiting() { /* * ":quit": quit current window, quit Vim if closed the last window. */ -static void ex_quit(eap) -exarg_T *eap; +static void ex_quit(exarg_T *eap) { if (cmdwin_type != 0) { cmdwin_result = Ctrl_C; @@ -5415,8 +5336,7 @@ exarg_T *eap; /* * ":cquit". */ -static void ex_cquit(eap) -exarg_T *eap UNUSED; +static void ex_cquit(exarg_T *eap) { getout(1); /* this does not always pass on the exit code to the Manx compiler. why? */ @@ -5425,8 +5345,7 @@ exarg_T *eap UNUSED; /* * ":qall": try to quit all windows */ -static void ex_quit_all(eap) -exarg_T *eap; +static void ex_quit_all(exarg_T *eap) { if (cmdwin_type != 0) { if (eap->forceit) @@ -5456,8 +5375,7 @@ exarg_T *eap; /* * ":close": close current window, unless it is the last one */ -static void ex_close(eap) -exarg_T *eap; +static void ex_close(exarg_T *eap) { if (cmdwin_type != 0) cmdwin_result = Ctrl_C; @@ -5470,8 +5388,7 @@ exarg_T *eap; /* * ":pclose": Close any preview window. */ -static void ex_pclose(eap) -exarg_T *eap; +static void ex_pclose(exarg_T *eap) { win_T *win; @@ -5486,10 +5403,12 @@ exarg_T *eap; * Close window "win" and take care of handling closing the last window for a * modified buffer. */ -static void ex_win_close(forceit, win, tp) -int forceit; -win_T *win; -tabpage_T *tp; /* NULL or the tab page "win" is in */ +static void +ex_win_close ( + int forceit, + win_T *win, + tabpage_T *tp /* NULL or the tab page "win" is in */ +) { int need_hide; buf_T *buf = win->w_buffer; @@ -5519,8 +5438,7 @@ tabpage_T *tp; /* NULL or the tab page "win" is in */ * ":tabclose": close current tab page, unless it is the last one. * ":tabclose N": close tab page N. */ -static void ex_tabclose(eap) -exarg_T *eap; +static void ex_tabclose(exarg_T *eap) { tabpage_T *tp; @@ -5550,8 +5468,7 @@ exarg_T *eap; /* * ":tabonly": close all tab pages except the current one */ -static void ex_tabonly(eap) -exarg_T *eap; +static void ex_tabonly(exarg_T *eap) { tabpage_T *tp; int done; @@ -5582,8 +5499,7 @@ exarg_T *eap; /* * Close the current tab page. */ -void tabpage_close(forceit) -int forceit; +void tabpage_close(int forceit) { /* First close all the windows but the current one. If that worked then * close the last window in this tab, that will close it. */ @@ -5599,9 +5515,7 @@ int forceit; * Also takes care of the tab pages line disappearing when closing the * last-but-one tab page. */ -void tabpage_close_other(tp, forceit) -tabpage_T *tp; -int forceit; +void tabpage_close_other(tabpage_T *tp, int forceit) { int done = 0; win_T *wp; @@ -5627,8 +5541,7 @@ int forceit; /* * ":only". */ -static void ex_only(eap) -exarg_T *eap; +static void ex_only(exarg_T *eap) { close_others(TRUE, eap->forceit); } @@ -5637,16 +5550,14 @@ exarg_T *eap; * ":all" and ":sall". * Also used for ":tab drop file ..." after setting the argument list. */ -void ex_all(eap) -exarg_T *eap; +void ex_all(exarg_T *eap) { if (eap->addr_count == 0) eap->line2 = 9999; do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop); } -static void ex_hide(eap) -exarg_T *eap; +static void ex_hide(exarg_T *eap) { if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) eap->errmsg = e_invarg; @@ -5662,8 +5573,7 @@ exarg_T *eap; /* * ":stop" and ":suspend": Suspend Vim. */ -static void ex_stop(eap) -exarg_T *eap; +static void ex_stop(exarg_T *eap) { /* * Disallow suspending for "rvim". @@ -5691,8 +5601,7 @@ exarg_T *eap; /* * ":exit", ":xit" and ":wq": Write file and exit Vim. */ -static void ex_exit(eap) -exarg_T *eap; +static void ex_exit(exarg_T *eap) { if (cmdwin_type != 0) { cmdwin_result = Ctrl_C; @@ -5731,8 +5640,7 @@ exarg_T *eap; /* * ":print", ":list", ":number". */ -static void ex_print(eap) -exarg_T *eap; +static void ex_print(exarg_T *eap) { if (curbuf->b_ml.ml_flags & ML_EMPTY) EMSG(_(e_emptybuf)); @@ -5755,8 +5663,7 @@ exarg_T *eap; ex_no_reprint = TRUE; } -static void ex_goto(eap) -exarg_T *eap; +static void ex_goto(exarg_T *eap) { goto_byte(eap->line2); } @@ -5764,8 +5671,7 @@ exarg_T *eap; /* * ":shell". */ -static void ex_shell(eap) -exarg_T *eap UNUSED; +static void ex_shell(exarg_T *eap) { do_shell(NULL, 0); } @@ -5793,10 +5699,12 @@ exarg_T *eap UNUSED; * file functionality is (currently) not in EMX this is not presently a * problem. */ -void handle_drop(filec, filev, split) -int filec; /* the number of files dropped */ -char_u **filev; /* the list of files dropped */ -int split; /* force splitting the window */ +void +handle_drop ( + int filec, /* the number of files dropped */ + char_u **filev, /* the list of files dropped */ + int split /* force splitting the window */ +) { exarg_T ea; int save_msg_scroll = msg_scroll; @@ -5859,8 +5767,7 @@ int split; /* force splitting the window */ /* * Clear an argument list: free all file names and reset it to zero entries. */ -void alist_clear(al) -alist_T *al; +void alist_clear(alist_T *al) { while (--al->al_ga.ga_len >= 0) vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); @@ -5870,8 +5777,7 @@ alist_T *al; /* * Init an argument list. */ -void alist_init(al) -alist_T *al; +void alist_init(alist_T *al) { ga_init2(&al->al_ga, (int)sizeof(aentry_T), 5); } @@ -5882,8 +5788,7 @@ alist_T *al; * Ignored when the argument list is the global one. * If the argument list is no longer used by any window, free it. */ -void alist_unlink(al) -alist_T *al; +void alist_unlink(alist_T *al) { if (al != &global_alist && --al->al_refcount <= 0) { alist_clear(al); @@ -5894,7 +5799,7 @@ alist_T *al; /* * Create a new argument list and use it for the current window. */ -void alist_new() { +void alist_new(void) { curwin->w_alist = (alist_T *)alloc((unsigned)sizeof(alist_T)); if (curwin->w_alist == NULL) { curwin->w_alist = &global_alist; @@ -5911,9 +5816,7 @@ void alist_new() { * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer * numbers to be re-used. */ -void alist_expand(fnum_list, fnum_len) -int *fnum_list; -int fnum_len; +void alist_expand(int *fnum_list, int fnum_len) { char_u **old_arg_files; int old_arg_count; @@ -5948,13 +5851,7 @@ int fnum_len; * Set the argument list for the current window. * Takes over the allocated files[] and the allocated fnames in it. */ -void alist_set(al, count, files, use_curbuf, fnum_list, fnum_len) -alist_T *al; -int count; -char_u **files; -int use_curbuf; -int *fnum_list; -int fnum_len; +void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum_list, int fnum_len) { int i; @@ -5988,10 +5885,12 @@ int fnum_len; * Add file "fname" to argument list "al". * "fname" must have been allocated and "al" must have been checked for room. */ -void alist_add(al, fname, set_fnum) -alist_T *al; -char_u *fname; -int set_fnum; /* 1: set buffer number; 2: re-use curbuf */ +void +alist_add ( + alist_T *al, + char_u *fname, + int set_fnum /* 1: set buffer number; 2: re-use curbuf */ +) { if (fname == NULL) /* don't add NULL file names */ return; @@ -6009,7 +5908,7 @@ int set_fnum; /* 1: set buffer number; 2: re-use curbuf */ /* * Adjust slashes in file names. Called after 'shellslash' was set. */ -void alist_slash_adjust() { +void alist_slash_adjust(void) { int i; win_T *wp; tabpage_T *tp; @@ -6029,8 +5928,7 @@ void alist_slash_adjust() { /* * ":preserve". */ -static void ex_preserve(eap) -exarg_T *eap UNUSED; +static void ex_preserve(exarg_T *eap) { curbuf->b_flags |= BF_PRESERVED; ml_preserve(curbuf, TRUE); @@ -6039,8 +5937,7 @@ exarg_T *eap UNUSED; /* * ":recover". */ -static void ex_recover(eap) -exarg_T *eap; +static void ex_recover(exarg_T *eap) { /* Set recoverymode right away to avoid the ATTENTION prompt. */ recoverymode = TRUE; @@ -6058,8 +5955,7 @@ exarg_T *eap; /* * Command modifier used in a wrong way. */ -static void ex_wrongmodifier(eap) -exarg_T *eap; +static void ex_wrongmodifier(exarg_T *eap) { eap->errmsg = e_invcmd; } @@ -6077,8 +5973,7 @@ exarg_T *eap; * :tabnew [[+command] file] just like :tabedit * :tabfind [+command] file open new Tab page and find "file" */ -void ex_splitview(eap) -exarg_T *eap; +void ex_splitview(exarg_T *eap) { win_T *old_curwin = curwin; char_u *fname = NULL; @@ -6140,7 +6035,7 @@ theend: /* * Open a new tab page. */ -void tabpage_new() { +void tabpage_new(void) { exarg_T ea; vim_memset(&ea, 0, sizeof(ea)); @@ -6153,8 +6048,7 @@ void tabpage_new() { /* * :tabnext command */ -static void ex_tabnext(eap) -exarg_T *eap; +static void ex_tabnext(exarg_T *eap) { switch (eap->cmdidx) { case CMD_tabfirst: @@ -6177,8 +6071,7 @@ exarg_T *eap; /* * :tabmove command */ -static void ex_tabmove(eap) -exarg_T *eap; +static void ex_tabmove(exarg_T *eap) { int tab_number = 9999; @@ -6214,8 +6107,7 @@ exarg_T *eap; /* * :tabs command: List tabs and their contents. */ -static void ex_tabs(eap) -exarg_T *eap UNUSED; +static void ex_tabs(exarg_T *eap) { tabpage_T *tp; win_T *wp; @@ -6257,8 +6149,7 @@ exarg_T *eap UNUSED; * ":mode": Set screen mode. * If no argument given, just get the screen size and redraw. */ -static void ex_mode(eap) -exarg_T *eap; +static void ex_mode(exarg_T *eap) { if (*eap->arg == NUL) shell_resized(); @@ -6270,8 +6161,7 @@ exarg_T *eap; * ":resize". * set, increment or decrement current window height */ -static void ex_resize(eap) -exarg_T *eap; +static void ex_resize(exarg_T *eap) { int n; win_T *wp = curwin; @@ -6301,8 +6191,7 @@ exarg_T *eap; /* * ":find [+command] " command. */ -static void ex_find(eap) -exarg_T *eap; +static void ex_find(exarg_T *eap) { char_u *fname; int count; @@ -6330,8 +6219,7 @@ exarg_T *eap; /* * ":open" simulation: for now just work like ":visual". */ -static void ex_open(eap) -exarg_T *eap; +static void ex_open(exarg_T *eap) { regmatch_T regmatch; char_u *p; @@ -6365,8 +6253,7 @@ exarg_T *eap; /* * ":edit", ":badd", ":visual". */ -static void ex_edit(eap) -exarg_T *eap; +static void ex_edit(exarg_T *eap) { do_exedit(eap, NULL); } @@ -6374,9 +6261,11 @@ exarg_T *eap; /* * ":edit " command and alikes. */ -void do_exedit(eap, old_curwin) -exarg_T *eap; -win_T *old_curwin; /* curwin before doing a split or NULL */ +void +do_exedit ( + exarg_T *eap, + win_T *old_curwin /* curwin before doing a split or NULL */ +) { int n; int need_hide; @@ -6506,16 +6395,14 @@ win_T *old_curwin; /* curwin before doing a split or NULL */ /* * ":gui" and ":gvim" when there is no GUI. */ -static void ex_nogui(eap) -exarg_T *eap; +static void ex_nogui(exarg_T *eap) { eap->errmsg = e_nogvim; } -static void ex_swapname(eap) -exarg_T *eap UNUSED; +static void ex_swapname(exarg_T *eap) { if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) MSG(_("No swap file")); @@ -6528,8 +6415,7 @@ exarg_T *eap UNUSED; * offset. * (1998-11-02 16:21:01 R. Edward Ralston ) */ -static void ex_syncbind(eap) -exarg_T *eap UNUSED; +static void ex_syncbind(exarg_T *eap) { win_T *wp; win_T *save_curwin = curwin; @@ -6592,8 +6478,7 @@ exarg_T *eap UNUSED; } -static void ex_read(eap) -exarg_T *eap; +static void ex_read(exarg_T *eap) { int i; int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); @@ -6644,7 +6529,7 @@ exarg_T *eap; static char_u *prev_dir = NULL; #if defined(EXITFREE) || defined(PROTO) -void free_cd_dir() { +void free_cd_dir(void) { vim_free(prev_dir); prev_dir = NULL; @@ -6658,8 +6543,7 @@ void free_cd_dir() { * Deal with the side effects of changing the current directory. * When "local" is TRUE then this was after an ":lcd" command. */ -void post_chdir(local) -int local; +void post_chdir(int local) { vim_free(curwin->w_localdir); curwin->w_localdir = NULL; @@ -6685,8 +6569,7 @@ int local; /* * ":cd", ":lcd", ":chdir" and ":lchdir". */ -void ex_cd(eap) -exarg_T *eap; +void ex_cd(exarg_T *eap) { char_u *new_dir; char_u *tofree; @@ -6748,8 +6631,7 @@ exarg_T *eap; /* * ":pwd". */ -static void ex_pwd(eap) -exarg_T *eap UNUSED; +static void ex_pwd(exarg_T *eap) { if (mch_dirname(NameBuff, MAXPATHL) == OK) { #ifdef BACKSLASH_IN_FILENAME @@ -6763,15 +6645,13 @@ exarg_T *eap UNUSED; /* * ":=". */ -static void ex_equal(eap) -exarg_T *eap; +static void ex_equal(exarg_T *eap) { smsg((char_u *)"%ld", (long)eap->line2); ex_may_print(eap); } -static void ex_sleep(eap) -exarg_T *eap; +static void ex_sleep(exarg_T *eap) { int n; long len; @@ -6794,8 +6674,7 @@ exarg_T *eap; /* * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second. */ -void do_sleep(msec) -long msec; +void do_sleep(long msec) { long done; @@ -6807,9 +6686,7 @@ long msec; } } -static void do_exmap(eap, isabbrev) -exarg_T *eap; -int isabbrev; +static void do_exmap(exarg_T *eap, int isabbrev) { int mode; char_u *cmdp; @@ -6829,8 +6706,7 @@ int isabbrev; /* * ":winsize" command (obsolete). */ -static void ex_winsize(eap) -exarg_T *eap; +static void ex_winsize(exarg_T *eap) { int w, h; char_u *arg = eap->arg; @@ -6846,8 +6722,7 @@ exarg_T *eap; EMSG(_("E465: :winsize requires two number arguments")); } -static void ex_wincmd(eap) -exarg_T *eap; +static void ex_wincmd(exarg_T *eap) { int xchar = NUL; char_u *p; @@ -6910,8 +6785,7 @@ exarg_T *eap; /* * Handle command that work like operators: ":delete", ":yank", ":>" and ":<". */ -static void ex_operators(eap) -exarg_T *eap; +static void ex_operators(exarg_T *eap) { oparg_T oa; @@ -6959,8 +6833,7 @@ exarg_T *eap; /* * ":put". */ -static void ex_put(eap) -exarg_T *eap; +static void ex_put(exarg_T *eap) { /* ":0put" works like ":1put!". */ if (eap->line2 == 0) { @@ -6975,8 +6848,7 @@ exarg_T *eap; /* * Handle ":copy" and ":move". */ -static void ex_copymove(eap) -exarg_T *eap; +static void ex_copymove(exarg_T *eap) { long n; @@ -7008,8 +6880,7 @@ exarg_T *eap; /* * Print the current line if flags were given to the Ex command. */ -static void ex_may_print(eap) -exarg_T *eap; +static void ex_may_print(exarg_T *eap) { if (eap->flags != 0) { print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR), @@ -7021,8 +6892,7 @@ exarg_T *eap; /* * ":smagic" and ":snomagic". */ -static void ex_submagic(eap) -exarg_T *eap; +static void ex_submagic(exarg_T *eap) { int magic_save = p_magic; @@ -7034,8 +6904,7 @@ exarg_T *eap; /* * ":join". */ -static void ex_join(eap) -exarg_T *eap; +static void ex_join(exarg_T *eap) { curwin->w_cursor.lnum = eap->line1; if (eap->line1 == eap->line2) { @@ -7055,8 +6924,7 @@ exarg_T *eap; /* * ":[addr]@r" or ":[addr]*r": execute register */ -static void ex_at(eap) -exarg_T *eap; +static void ex_at(exarg_T *eap) { int c; int prev_len = typebuf.tb_len; @@ -7095,8 +6963,7 @@ exarg_T *eap; /* * ":!". */ -static void ex_bang(eap) -exarg_T *eap; +static void ex_bang(exarg_T *eap) { do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE); } @@ -7104,8 +6971,7 @@ exarg_T *eap; /* * ":undo". */ -static void ex_undo(eap) -exarg_T *eap UNUSED; +static void ex_undo(exarg_T *eap) { if (eap->addr_count == 1) /* :undo 123 */ undo_time(eap->line2, FALSE, FALSE, TRUE); @@ -7113,8 +6979,7 @@ exarg_T *eap UNUSED; u_undo(1); } -static void ex_wundo(eap) -exarg_T *eap; +static void ex_wundo(exarg_T *eap) { char_u hash[UNDO_HASH_SIZE]; @@ -7122,8 +6987,7 @@ exarg_T *eap; u_write_undo(eap->arg, eap->forceit, curbuf, hash); } -static void ex_rundo(eap) -exarg_T *eap; +static void ex_rundo(exarg_T *eap) { char_u hash[UNDO_HASH_SIZE]; @@ -7134,8 +6998,7 @@ exarg_T *eap; /* * ":redo". */ -static void ex_redo(eap) -exarg_T *eap UNUSED; +static void ex_redo(exarg_T *eap) { u_redo(1); } @@ -7143,8 +7006,7 @@ exarg_T *eap UNUSED; /* * ":earlier" and ":later". */ -static void ex_later(eap) -exarg_T *eap; +static void ex_later(exarg_T *eap) { long count = 0; int sec = FALSE; @@ -7174,8 +7036,7 @@ exarg_T *eap; /* * ":redir": start/stop redirection. */ -static void ex_redir(eap) -exarg_T *eap; +static void ex_redir(exarg_T *eap) { char *mode; char_u *fname; @@ -7257,8 +7118,7 @@ exarg_T *eap; /* * ":redraw": force redraw */ -static void ex_redraw(eap) -exarg_T *eap; +static void ex_redraw(exarg_T *eap) { int r = RedrawingDisabled; int p = p_lz; @@ -7287,8 +7147,7 @@ exarg_T *eap; /* * ":redrawstatus": force redraw of status line(s) */ -static void ex_redrawstatus(eap) -exarg_T *eap UNUSED; +static void ex_redrawstatus(exarg_T *eap) { int r = RedrawingDisabled; int p = p_lz; @@ -7307,7 +7166,7 @@ exarg_T *eap UNUSED; out_flush(); } -static void close_redir() { +static void close_redir(void) { if (redir_fd != NULL) { fclose(redir_fd); redir_fd = NULL; @@ -7327,8 +7186,7 @@ static int mksession_nl = FALSE; /* use NL only in put_eol() */ /* * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession". */ -static void ex_mkrc(eap) -exarg_T *eap; +static void ex_mkrc(exarg_T *eap) { FILE *fd; int failed = FALSE; @@ -7490,9 +7348,7 @@ exarg_T *eap; #if ((defined(FEAT_SESSION) || defined(FEAT_EVAL)) && defined(vim_mkdir)) \ || defined(PROTO) -int vim_mkdir_emsg(name, prot) -char_u *name; -int prot UNUSED; +int vim_mkdir_emsg(char_u *name, int prot) { if (vim_mkdir(name, prot) != 0) { EMSG2(_("E739: Cannot create directory: %s"), name); @@ -7506,10 +7362,12 @@ int prot UNUSED; * Open a file for writing for an Ex command, with some checks. * Return file descriptor, or NULL on failure. */ -FILE * open_exfile(fname, forceit, mode) -char_u *fname; -int forceit; -char *mode; /* "w" for create new file or "a" for append */ +FILE * +open_exfile ( + char_u *fname, + int forceit, + char *mode /* "w" for create new file or "a" for append */ +) { FILE *fd; @@ -7534,8 +7392,7 @@ char *mode; /* "w" for create new file or "a" for append */ /* * ":mark" and ":k". */ -static void ex_mark(eap) -exarg_T *eap; +static void ex_mark(exarg_T *eap) { pos_T pos; @@ -7556,7 +7413,7 @@ exarg_T *eap; /* * Update w_topline, w_leftcol and the cursor position. */ -void update_topline_cursor() { +void update_topline_cursor(void) { check_cursor(); /* put cursor on valid line */ update_topline(); if (!curwin->w_p_wrap) @@ -7567,8 +7424,7 @@ void update_topline_cursor() { /* * ":normal[!] {commands}": Execute normal mode commands. */ -static void ex_normal(eap) -exarg_T *eap; +static void ex_normal(exarg_T *eap) { int save_msg_scroll = msg_scroll; int save_restart_edit = restart_edit; @@ -7677,8 +7533,7 @@ exarg_T *eap; /* * ":startinsert", ":startreplace" and ":startgreplace" */ -static void ex_startinsert(eap) -exarg_T *eap; +static void ex_startinsert(exarg_T *eap) { if (eap->forceit) { coladvance((colnr_T)MAXCOL); @@ -7708,8 +7563,7 @@ exarg_T *eap; /* * ":stopinsert" */ -static void ex_stopinsert(eap) -exarg_T *eap UNUSED; +static void ex_stopinsert(exarg_T *eap) { restart_edit = 0; stop_insert_mode = TRUE; @@ -7719,10 +7573,7 @@ exarg_T *eap UNUSED; * Execute normal mode command "cmd". * "remap" can be REMAP_NONE or REMAP_YES. */ -void exec_normal_cmd(cmd, remap, silent) -char_u *cmd; -int remap; -int silent; +void exec_normal_cmd(char_u *cmd, int remap, int silent) { oparg_T oa; @@ -7740,8 +7591,7 @@ int silent; } } -static void ex_checkpath(eap) -exarg_T *eap; +static void ex_checkpath(exarg_T *eap) { find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L, eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, @@ -7751,16 +7601,14 @@ exarg_T *eap; /* * ":psearch" */ -static void ex_psearch(eap) -exarg_T *eap; +static void ex_psearch(exarg_T *eap) { g_do_tagpreview = p_pvh; ex_findpat(eap); g_do_tagpreview = 0; } -static void ex_findpat(eap) -exarg_T *eap; +static void ex_findpat(exarg_T *eap) { int whole = TRUE; long n; @@ -7816,8 +7664,7 @@ exarg_T *eap; /* * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc. */ -static void ex_ptag(eap) -exarg_T *eap; +static void ex_ptag(exarg_T *eap) { g_do_tagpreview = p_pvh; /* will be reset to 0 in ex_tag_cmd() */ ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); @@ -7826,8 +7673,7 @@ exarg_T *eap; /* * ":pedit" */ -static void ex_pedit(eap) -exarg_T *eap; +static void ex_pedit(exarg_T *eap) { win_T *curwin_save = curwin; @@ -7848,8 +7694,7 @@ exarg_T *eap; /* * ":stag", ":stselect" and ":stjump". */ -static void ex_stag(eap) -exarg_T *eap; +static void ex_stag(exarg_T *eap) { postponed_split = -1; postponed_split_flags = cmdmod.split; @@ -7862,15 +7707,12 @@ exarg_T *eap; /* * ":tag", ":tselect", ":tjump", ":tnext", etc. */ -static void ex_tag(eap) -exarg_T *eap; +static void ex_tag(exarg_T *eap) { ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name); } -static void ex_tag_cmd(eap, name) -exarg_T *eap; -char_u *name; +static void ex_tag_cmd(exarg_T *eap, char_u *name) { int cmd; @@ -7914,9 +7756,7 @@ char_u *name; * If found return one of the SPEC_ values and set "*usedlen" to the length of * the variable. Otherwise return -1 and "*usedlen" is unchanged. */ -int find_cmdline_var(src, usedlen) -char_u *src; -int *usedlen; +int find_cmdline_var(char_u *src, int *usedlen) { int len; int i; @@ -7973,14 +7813,16 @@ int *usedlen; * Returns NULL if no match was found. "usedlen" then still contains the * number of characters to skip. */ -char_u * eval_vars(src, srcstart, usedlen, lnump, errormsg, escaped) -char_u *src; /* pointer into commandline */ -char_u *srcstart; /* beginning of valid memory for src */ -int *usedlen; /* characters after src that are used */ -linenr_T *lnump; /* line number for :e command, or NULL */ -char_u **errormsg; /* pointer to error message */ -int *escaped; /* return value has escaped white space (can +char_u * +eval_vars ( + char_u *src, /* pointer into commandline */ + char_u *srcstart, /* beginning of valid memory for src */ + int *usedlen, /* characters after src that are used */ + linenr_T *lnump, /* line number for :e command, or NULL */ + char_u **errormsg, /* pointer to error message */ + int *escaped /* return value has escaped white space (can * be NULL) */ +) { int i; char_u *s; @@ -8188,7 +8030,7 @@ int *escaped; /* return value has escaped white space (can * Spaces and backslashes in the file names are escaped with a backslash. * Returns NULL when out of memory. */ -static char_u * arg_all() { +static char_u *arg_all(void) { int len; int idx; char_u *retval = NULL; @@ -8244,8 +8086,7 @@ static char_u * arg_all() { * * Returns an allocated string, or NULL for any error. */ -char_u * expand_sfile(arg) -char_u *arg; +char_u *expand_sfile(char_u *arg) { char_u *errormsg; int len; @@ -8311,9 +8152,11 @@ static int ses_fname __ARGS((FILE *fd, buf_T *buf, unsigned *flagp)); * Write openfile commands for the current buffers to an .exrc file. * Return FAIL on error, OK otherwise. */ -static int makeopens(fd, dirnow) -FILE *fd; -char_u *dirnow; /* Current directory name */ +static int +makeopens ( + FILE *fd, + char_u *dirnow /* Current directory name */ +) { buf_T *buf; int only_save_windows = TRUE; @@ -8581,10 +8424,7 @@ char_u *dirnow; /* Current directory name */ return OK; } -static int ses_winsizes(fd, restore_size, tab_firstwin) -FILE *fd; -int restore_size; -win_T *tab_firstwin; +static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin) { int n = 0; win_T *wp; @@ -8625,9 +8465,7 @@ win_T *tab_firstwin; * After the commands the last window in the frame is the current window. * Returns FAIL when writing the commands to "fd" fails. */ -static int ses_win_rec(fd, fr) -FILE *fd; -frame_T *fr; +static int ses_win_rec(FILE *fd, frame_T *fr) { frame_T *frc; int count = 0; @@ -8671,8 +8509,7 @@ frame_T *fr; * Skip frames that don't contain windows we want to save in the Session. * Returns NULL when there none. */ -static frame_T * ses_skipframe(fr) -frame_T *fr; +static frame_T *ses_skipframe(frame_T *fr) { frame_T *frc; @@ -8686,8 +8523,7 @@ frame_T *fr; * Return TRUE if frame "fr" has a window somewhere that we want to save in * the Session. */ -static int ses_do_frame(fr) -frame_T *fr; +static int ses_do_frame(frame_T *fr) { frame_T *frc; @@ -8702,8 +8538,7 @@ frame_T *fr; /* * Return non-zero if window "wp" is to be stored in the Session. */ -static int ses_do_win(wp) -win_T *wp; +static int ses_do_win(win_T *wp) { if (wp->w_buffer->b_fname == NULL /* When 'buftype' is "nofile" can't restore the window contents. */ @@ -8719,13 +8554,15 @@ win_T *wp; * Write commands to "fd" to restore the view of a window. * Caller must make sure 'scrolloff' is zero. */ -static int put_view(fd, wp, add_edit, flagp, current_arg_idx) -FILE *fd; -win_T *wp; -int add_edit; /* add ":edit" command to view */ -unsigned *flagp; /* vop_flags or ssop_flags */ -int current_arg_idx; /* current argument index of the window, use +static int +put_view ( + FILE *fd, + win_T *wp, + int add_edit, /* add ":edit" command to view */ + unsigned *flagp, /* vop_flags or ssop_flags */ + int current_arg_idx /* current argument index of the window, use * -1 if unknown */ +) { win_T *save_curwin; int f; @@ -8895,12 +8732,14 @@ int current_arg_idx; /* current argument index of the window, use * Write an argument list to the session file. * Returns FAIL if writing fails. */ -static int ses_arglist(fd, cmd, gap, fullname, flagp) -FILE *fd; -char *cmd; -garray_T *gap; -int fullname; /* TRUE: use full path name */ -unsigned *flagp; +static int +ses_arglist ( + FILE *fd, + char *cmd, + garray_T *gap, + int fullname, /* TRUE: use full path name */ + unsigned *flagp +) { int i; char_u *buf = NULL; @@ -8936,10 +8775,7 @@ unsigned *flagp; * Also ends the line. * Returns FAIL if writing fails. */ -static int ses_fname(fd, buf, flagp) -FILE *fd; -buf_T *buf; -unsigned *flagp; +static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp) { char_u *name; @@ -8967,10 +8803,7 @@ unsigned *flagp; * characters. * Returns FAIL if writing fails or out of memory. */ -static int ses_put_fname(fd, name, flagp) -FILE *fd; -char_u *name; -unsigned *flagp; +static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp) { char_u *sname; char_u *p; @@ -9004,8 +8837,7 @@ unsigned *flagp; /* * ":loadview [nr]" */ -static void ex_loadview(eap) -exarg_T *eap; +static void ex_loadview(exarg_T *eap) { char_u *fname; @@ -9019,8 +8851,7 @@ exarg_T *eap; /* * Get the name of the view file for the current buffer. */ -static char_u * get_view_file(c) -int c; +static char_u *get_view_file(int c) { int len = 0; char_u *p, *s; @@ -9079,8 +8910,7 @@ int c; * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession". * Return FAIL for a write error. */ -int put_eol(fd) -FILE *fd; +int put_eol(FILE *fd) { if ( #ifdef USE_CRNL @@ -9099,9 +8929,7 @@ FILE *fd; * Write a line to "fd". * Return FAIL for a write error. */ -int put_line(fd, s) -FILE *fd; -char *s; +int put_line(FILE *fd, char *s) { if (fputs(s, fd) < 0 || put_eol(fd) == FAIL) return FAIL; @@ -9111,8 +8939,7 @@ char *s; /* * ":rviminfo" and ":wviminfo". */ -static void ex_viminfo(eap) -exarg_T *eap; +static void ex_viminfo(exarg_T *eap) { char_u *save_viminfo; @@ -9132,10 +8959,7 @@ exarg_T *eap; * Make a dialog message in "buff[DIALOG_MSG_SIZE]". * "format" must contain "%s". */ -void dialog_msg(buff, format, fname) -char_u *buff; -char *format; -char_u *fname; +void dialog_msg(char_u *buff, char *format, char_u *fname) { if (fname == NULL) fname = (char_u *)_("Untitled"); @@ -9145,8 +8969,7 @@ char_u *fname; /* * ":behave {mswin,xterm}" */ -static void ex_behave(eap) -exarg_T *eap; +static void ex_behave(exarg_T *eap) { if (STRCMP(eap->arg, "mswin") == 0) { set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0); @@ -9167,9 +8990,7 @@ exarg_T *eap; * Function given to ExpandGeneric() to obtain the possible arguments of the * ":behave {mswin,xterm}" command. */ -char_u * get_behave_arg(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_behave_arg(expand_T *xp, int idx) { if (idx == 0) return (char_u *)"mswin"; @@ -9191,8 +9012,7 @@ static int filetype_indent = FALSE; * indent on: load filetype.vim and indent.vim * indent off: load indoff.vim */ -static void ex_filetype(eap) -exarg_T *eap; +static void ex_filetype(exarg_T *eap) { char_u *arg = eap->arg; int plugin = FALSE; @@ -9259,15 +9079,13 @@ exarg_T *eap; /* * ":setfiletype {name}" */ -static void ex_setfiletype(eap) -exarg_T *eap; +static void ex_setfiletype(exarg_T *eap) { if (!did_filetype) set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL); } -static void ex_digraphs(eap) -exarg_T *eap UNUSED; +static void ex_digraphs(exarg_T *eap) { if (*eap->arg != NUL) putdigraph(eap->arg); @@ -9275,8 +9093,7 @@ exarg_T *eap UNUSED; listdigraphs(); } -static void ex_set(eap) -exarg_T *eap; +static void ex_set(exarg_T *eap) { int flags = 0; @@ -9290,8 +9107,7 @@ exarg_T *eap; /* * ":nohlsearch" */ -static void ex_nohlsearch(eap) -exarg_T *eap UNUSED; +static void ex_nohlsearch(exarg_T *eap) { SET_NO_HLSEARCH(TRUE); redraw_all_later(SOME_VALID); @@ -9302,8 +9118,7 @@ exarg_T *eap UNUSED; * Sets nextcmd to the start of the next command, if any. Also called when * skipping commands to find the next command. */ -static void ex_match(eap) -exarg_T *eap; +static void ex_match(exarg_T *eap) { char_u *p; char_u *g = NULL; @@ -9361,29 +9176,25 @@ exarg_T *eap; /* * ":X": Get crypt key */ -static void ex_X(eap) -exarg_T *eap UNUSED; +static void ex_X(exarg_T *eap) { if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK) (void)get_crypt_key(TRUE, TRUE); } -static void ex_fold(eap) -exarg_T *eap; +static void ex_fold(exarg_T *eap) { if (foldManualAllowed(TRUE)) foldCreate(eap->line1, eap->line2); } -static void ex_foldopen(eap) -exarg_T *eap; +static void ex_foldopen(exarg_T *eap) { opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen, eap->forceit, FALSE); } -static void ex_folddo(eap) -exarg_T *eap; +static void ex_folddo(exarg_T *eap) { linenr_T lnum; diff --git a/src/ex_eval.c b/src/ex_eval.c index 5f845c3f33..3ccac9e84f 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -84,7 +84,7 @@ static int cause_abort = FALSE; * cancellation of an expression evaluation after an aborting function call or * due to a parsing error, aborting() always returns the same value. */ -int aborting() { +int aborting(void) { return (did_emsg && force_abort) || got_int || did_throw; } @@ -94,7 +94,7 @@ int aborting() { * be necessary to restore "force_abort" even before the throw point for the * error message has been reached. update_force_abort() should be called then. */ -void update_force_abort() { +void update_force_abort(void) { if (cause_abort) force_abort = TRUE; } @@ -105,8 +105,7 @@ void update_force_abort() { * execution of a failing subcommand as long as the error message has not been * displayed and actually caused the abortion. */ -int should_abort(retcode) -int retcode; +int should_abort(int retcode) { return (retcode == FAIL && trylevel != 0 && !emsg_silent) || aborting(); } @@ -117,7 +116,7 @@ int retcode; * to find finally clauses to be executed, and that some errors in skipped * commands are still reported. */ -int aborted_in_try() { +int aborted_in_try(void) { /* This function is only called after an error. In this case, "force_abort" * determines whether searching for finally clauses is necessary. */ return force_abort; @@ -132,10 +131,7 @@ int aborted_in_try() { * most specific one and used as the exception value. The "severe" flag can be * set to TRUE, if a later but severer message should be used instead. */ -int cause_errthrow(mesg, severe, ignore) -char_u *mesg; -int severe; -int *ignore; +int cause_errthrow(char_u *mesg, int severe, int *ignore) { struct msglist *elem; struct msglist **plist; @@ -275,8 +271,7 @@ int *ignore; /* * Free a "msg_list" and the messages it contains. */ -static void free_msglist(l) -struct msglist *l; +static void free_msglist(struct msglist *l) { struct msglist *messages, *next; @@ -293,7 +288,7 @@ struct msglist *l; * Free global "*msg_list" and the messages it contains, then set "*msg_list" * to NULL. */ -void free_global_msglist() { +void free_global_msglist(void) { free_msglist(*msg_list); *msg_list = NULL; } @@ -303,9 +298,7 @@ void free_global_msglist() { * error exception. If cstack is NULL, postpone the throw until do_cmdline() * has returned (see do_one_cmd()). */ -void do_errthrow(cstack, cmdname) -struct condstack *cstack; -char_u *cmdname; +void do_errthrow(struct condstack *cstack, char_u *cmdname) { /* * Ensure that all commands in nested function calls and sourced files @@ -337,8 +330,7 @@ char_u *cmdname; * exception if appropriate. Return TRUE if the current exception is discarded, * FALSE otherwise. */ -int do_intthrow(cstack) -struct condstack *cstack; +int do_intthrow(struct condstack *cstack) { /* * If no interrupt occurred or no try conditional is active and no exception @@ -384,11 +376,7 @@ struct condstack *cstack; /* * Get an exception message that is to be stored in current_exception->value. */ -char_u * get_exception_string(value, type, cmdname, should_free) -void *value; -int type; -char_u *cmdname; -int *should_free; +char_u *get_exception_string(void *value, int type, char_u *cmdname, int *should_free) { char_u *ret, *mesg; int cmdlen; @@ -457,10 +445,7 @@ int *should_free; * user or interrupt exception, or points to a message list in case of an * error exception. */ -static int throw_exception(value, type, cmdname) -void *value; -int type; -char_u *cmdname; +static int throw_exception(void *value, int type, char_u *cmdname) { except_T *excp; int should_free; @@ -541,9 +526,7 @@ fail: * Discard an exception. "was_finished" is set when the exception has been * caught and the catch clause has been ended normally. */ -static void discard_exception(excp, was_finished) -except_T *excp; -int was_finished; +static void discard_exception(except_T *excp, int was_finished) { char_u *saved_IObuff; @@ -589,7 +572,7 @@ int was_finished; /* * Discard the exception currently being thrown. */ -void discard_current_exception() { +void discard_current_exception(void) { discard_exception(current_exception, FALSE); current_exception = NULL; did_throw = FALSE; @@ -599,8 +582,7 @@ void discard_current_exception() { /* * Put an exception on the caught stack. */ -static void catch_exception(excp) -except_T *excp; +static void catch_exception(except_T *excp) { excp->caught = caught_stack; caught_stack = excp; @@ -643,8 +625,7 @@ except_T *excp; /* * Remove an exception from the caught stack. */ -static void finish_exception(excp) -except_T *excp; +static void finish_exception(except_T *excp) { if (excp != caught_stack) EMSG(_(e_internal)); @@ -687,10 +668,7 @@ except_T *excp; * what is pending. "value" specifies the return value for a pending ":return" * or the exception value for a pending exception. */ -static void report_pending(action, pending, value) -int action; -int pending; -void *value; +static void report_pending(int action, int pending, void *value) { char_u *mesg; char *s; @@ -765,9 +743,7 @@ void *value; * If something is made pending in a finally clause, report it if required by * the 'verbose' option or when debugging. */ -void report_make_pending(pending, value) -int pending; -void *value; +void report_make_pending(int pending, void *value) { if (p_verbose >= 14 || debug_break_level > 0) { if (debug_break_level <= 0) @@ -782,9 +758,7 @@ void *value; * If something pending in a finally clause is resumed at the ":endtry", report * it if required by the 'verbose' option or when debugging. */ -void report_resume_pending(pending, value) -int pending; -void *value; +void report_resume_pending(int pending, void *value) { if (p_verbose >= 14 || debug_break_level > 0) { if (debug_break_level <= 0) @@ -799,9 +773,7 @@ void *value; * If something pending in a finally clause is discarded, report it if required * by the 'verbose' option or when debugging. */ -void report_discard_pending(pending, value) -int pending; -void *value; +void report_discard_pending(int pending, void *value) { if (p_verbose >= 14 || debug_break_level > 0) { if (debug_break_level <= 0) @@ -816,8 +788,7 @@ void *value; /* * ":if". */ -void ex_if(eap) -exarg_T *eap; +void ex_if(exarg_T *eap) { int error; int skip; @@ -854,8 +825,7 @@ exarg_T *eap; /* * ":endif". */ -void ex_endif(eap) -exarg_T *eap; +void ex_endif(exarg_T *eap) { did_endif = TRUE; if (eap->cstack->cs_idx < 0 @@ -883,8 +853,7 @@ exarg_T *eap; /* * ":else" and ":elseif". */ -void ex_else(eap) -exarg_T *eap; +void ex_else(exarg_T *eap) { int error; int skip; @@ -965,8 +934,7 @@ exarg_T *eap; /* * Handle ":while" and ":for". */ -void ex_while(eap) -exarg_T *eap; +void ex_while(exarg_T *eap) { int error; int skip; @@ -1055,8 +1023,7 @@ exarg_T *eap; /* * ":continue" */ -void ex_continue(eap) -exarg_T *eap; +void ex_continue(exarg_T *eap) { int idx; struct condstack *cstack = eap->cstack; @@ -1089,8 +1056,7 @@ exarg_T *eap; /* * ":break" */ -void ex_break(eap) -exarg_T *eap; +void ex_break(exarg_T *eap) { int idx; struct condstack *cstack = eap->cstack; @@ -1113,8 +1079,7 @@ exarg_T *eap; /* * ":endwhile" and ":endfor" */ -void ex_endwhile(eap) -exarg_T *eap; +void ex_endwhile(exarg_T *eap) { struct condstack *cstack = eap->cstack; int idx; @@ -1190,8 +1155,7 @@ exarg_T *eap; /* * ":throw expr" */ -void ex_throw(eap) -exarg_T *eap; +void ex_throw(exarg_T *eap) { char_u *arg = eap->arg; char_u *value; @@ -1218,8 +1182,7 @@ exarg_T *eap; * for ":throw" (user exception) and error and interrupt exceptions. Also * used for rethrowing an uncaught exception. */ -void do_throw(cstack) -struct condstack *cstack; +void do_throw(struct condstack *cstack) { int idx; int inactivate_try = FALSE; @@ -1279,8 +1242,7 @@ struct condstack *cstack; /* * ":try" */ -void ex_try(eap) -exarg_T *eap; +void ex_try(exarg_T *eap) { int skip; struct condstack *cstack = eap->cstack; @@ -1347,8 +1309,7 @@ exarg_T *eap; /* * ":catch /{pattern}/" and ":catch" */ -void ex_catch(eap) -exarg_T *eap; +void ex_catch(exarg_T *eap) { int idx = 0; int give_up = FALSE; @@ -1489,8 +1450,7 @@ exarg_T *eap; /* * ":finally" */ -void ex_finally(eap) -exarg_T *eap; +void ex_finally(exarg_T *eap) { int idx; int skip = FALSE; @@ -1608,8 +1568,7 @@ exarg_T *eap; /* * ":endtry" */ -void ex_endtry(eap) -exarg_T *eap; +void ex_endtry(exarg_T *eap) { int idx; int skip; @@ -1797,8 +1756,7 @@ exarg_T *eap; * do_cmdline() that is going to be made for the cleanup autocommand * execution. */ -void enter_cleanup(csp) -cleanup_T *csp; +void enter_cleanup(cleanup_T *csp) { int pending = CSTP_NONE; @@ -1854,8 +1812,7 @@ cleanup_T *csp; * cleanup autocommands. In the latter case, the saved error/interrupt/ * exception state is discarded. */ -void leave_cleanup(csp) -cleanup_T *csp; +void leave_cleanup(cleanup_T *csp) { int pending = csp->pending; @@ -1935,10 +1892,7 @@ cleanup_T *csp; * entered, is restored (used by ex_endtry()). This is normally done only * when such a try conditional is left. */ -int cleanup_conditionals(cstack, searched_cond, inclusive) -struct condstack *cstack; -int searched_cond; -int inclusive; +int cleanup_conditionals(struct condstack *cstack, int searched_cond, int inclusive) { int idx; int stop = FALSE; @@ -2046,8 +2000,7 @@ int inclusive; /* * Return an appropriate error message for a missing endwhile/endfor/endif. */ -static char_u * get_end_emsg(cstack) -struct condstack *cstack; +static char_u *get_end_emsg(struct condstack *cstack) { if (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE) return e_endwhile; @@ -2064,11 +2017,7 @@ struct condstack *cstack; * type. * Also free "for info" structures where needed. */ -void rewind_conditionals(cstack, idx, cond_type, cond_level) -struct condstack *cstack; -int idx; -int cond_type; -int *cond_level; +void rewind_conditionals(struct condstack *cstack, int idx, int cond_type, int *cond_level) { while (cstack->cs_idx > idx) { if (cstack->cs_flags[cstack->cs_idx] & cond_type) @@ -2082,8 +2031,7 @@ int *cond_level; /* * ":endfunction" when not after a ":function" */ -void ex_endfunction(eap) -exarg_T *eap UNUSED; +void ex_endfunction(exarg_T *eap) { EMSG(_("E193: :endfunction not inside a function")); } @@ -2091,8 +2039,7 @@ exarg_T *eap UNUSED; /* * Return TRUE if the string "p" looks like a ":while" or ":for" command. */ -int has_loop_cmd(p) -char_u *p; +int has_loop_cmd(char_u *p) { int len; diff --git a/src/ex_getln.c b/src/ex_getln.c index dbef0a9449..9637b64f2d 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -125,10 +125,12 @@ sort_func_compare __ARGS((const void *s1, const void *s2)); * Return pointer to allocated string if there is a commandline, NULL * otherwise. */ -char_u * getcmdline(firstc, count, indent) -int firstc; -long count UNUSED; /* only used for incremental search */ -int indent; /* indent for inside conditionals */ +char_u * +getcmdline ( + int firstc, + long count, /* only used for incremental search */ + int indent /* indent for inside conditionals */ +) { int c; int i; @@ -1545,12 +1547,14 @@ returncmd: * f_input() when evaluating an expression from CTRL-R =). * Returns the command line in allocated memory, or NULL. */ -char_u * getcmdline_prompt(firstc, prompt, attr, xp_context, xp_arg) -int firstc; -char_u *prompt; /* command line prompt */ -int attr; /* attributes for prompt */ -int xp_context; /* type of expansion */ -char_u *xp_arg; /* user-defined expansion argument */ +char_u * +getcmdline_prompt ( + int firstc, + char_u *prompt, /* command line prompt */ + int attr, /* attributes for prompt */ + int xp_context, /* type of expansion */ + char_u *xp_arg /* user-defined expansion argument */ +) { char_u *s; struct cmdline_info save_ccline; @@ -1579,7 +1583,7 @@ char_u *xp_arg; /* user-defined expansion argument */ * another window or buffer. Used when editing the command line, evaluating * 'balloonexpr', etc. */ -int text_locked() { +int text_locked(void) { if (cmdwin_type != 0) return TRUE; return textlock != 0; @@ -1589,7 +1593,7 @@ int text_locked() { * Give an error message for a command that isn't allowed while the cmdline * window is open or editing the cmdline in another way. */ -void text_locked_msg() { +void text_locked_msg(void) { if (cmdwin_type != 0) EMSG(_(e_cmdwin)); else @@ -1600,7 +1604,7 @@ void text_locked_msg() { * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is * and give an error message. */ -int curbuf_locked() { +int curbuf_locked(void) { if (curbuf_lock > 0) { EMSG(_("E788: Not allowed to edit another buffer now")); return TRUE; @@ -1612,7 +1616,7 @@ int curbuf_locked() { * Check if "allbuf_lock" is set and return TRUE when it is and give an error * message. */ -int allbuf_locked() { +int allbuf_locked(void) { if (allbuf_lock > 0) { EMSG(_("E811: Not allowed to change buffer information now")); return TRUE; @@ -1620,8 +1624,7 @@ int allbuf_locked() { return FALSE; } -static int cmdline_charsize(idx) -int idx; +static int cmdline_charsize(int idx) { if (cmdline_star > 0) /* showing '*', always 1 position */ return 1; @@ -1632,7 +1635,7 @@ int idx; * Compute the offset of the cursor on the command line for the prompt and * indent. */ -static void set_cmdspos() { +static void set_cmdspos(void) { if (ccline.cmdfirstc != NUL) ccline.cmdspos = 1 + ccline.cmdindent; else @@ -1642,7 +1645,7 @@ static void set_cmdspos() { /* * Compute the screen position for the cursor on the command line. */ -static void set_cmdspos_cursor() { +static void set_cmdspos_cursor(void) { int i, m, c; set_cmdspos(); @@ -1672,9 +1675,7 @@ static void set_cmdspos_cursor() { * Check if the character at "idx", which is "cells" wide, is a multi-byte * character that doesn't fit, so that a ">" must be displayed. */ -static void correct_cmdspos(idx, cells) -int idx; -int cells; +static void correct_cmdspos(int idx, int cells) { if ((*mb_ptr2len)(ccline.cmdbuff + idx) > 1 && (*mb_ptr2cells)(ccline.cmdbuff + idx) > 1 @@ -1685,10 +1686,12 @@ int cells; /* * Get an Ex command line for the ":" command. */ -char_u * getexline(c, cookie, indent) -int c; /* normally ':', NUL for ":append" */ -void *cookie UNUSED; -int indent; /* indent for inside conditionals */ +char_u * +getexline ( + int c, /* normally ':', NUL for ":append" */ + void *cookie, + int indent /* indent for inside conditionals */ +) { /* When executing a register, remove ':' that's in front of each line. */ if (exec_from_reg && vpeekc() == ':') @@ -1702,11 +1705,13 @@ int indent; /* indent for inside conditionals */ * mappings or abbreviations. * Returns a string in allocated memory or NULL. */ -char_u * getexmodeline(promptc, cookie, indent) -int promptc; /* normally ':', NUL for ":append" and '?' for +char_u * +getexmodeline ( + int promptc, /* normally ':', NUL for ":append" and '?' for :s prompt */ -void *cookie UNUSED; -int indent; /* indent for inside conditionals */ + void *cookie, + int indent /* indent for inside conditionals */ +) { garray_T line_ga; char_u *pend; @@ -1932,14 +1937,14 @@ redraw: /* * Return TRUE if ccline.overstrike is on. */ -int cmdline_overstrike() { +int cmdline_overstrike(void) { return ccline.overstrike; } /* * Return TRUE if the cursor is at the end of the cmdline. */ -int cmdline_at_end() { +int cmdline_at_end(void) { return ccline.cmdpos >= ccline.cmdlen; } @@ -1952,8 +1957,7 @@ int cmdline_at_end() { * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen. */ -static void alloc_cmdbuff(len) -int len; +static void alloc_cmdbuff(int len) { /* * give some extra space to avoid having to allocate all the time @@ -1971,8 +1975,7 @@ int len; * Re-allocate the command line to length len + something extra. * return FAIL for failure, OK otherwise */ -static int realloc_cmdbuff(len) -int len; +static int realloc_cmdbuff(int len) { char_u *p; @@ -2009,7 +2012,7 @@ int len; static char_u *arshape_buf = NULL; # if defined(EXITFREE) || defined(PROTO) -void free_cmdline_buf() { +void free_cmdline_buf(void) { vim_free(arshape_buf); } @@ -2019,9 +2022,7 @@ void free_cmdline_buf() { * Draw part of the cmdline at the current cursor position. But draw stars * when cmdline_star is TRUE. */ -static void draw_cmdline(start, len) -int start; -int len; +static void draw_cmdline(int start, int len) { int i; @@ -2120,9 +2121,7 @@ int len; * right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc. * "c" must be printable (fit in one display cell)! */ -void putcmdline(c, shift) -int c; -int shift; +void putcmdline(int c, int shift) { if (cmd_silent) return; @@ -2137,7 +2136,7 @@ int shift; /* * Undo a putcmdline(c, FALSE). */ -void unputcmdline() { +void unputcmdline(void) { if (cmd_silent) return; msg_no_more = TRUE; @@ -2160,10 +2159,7 @@ void unputcmdline() { * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be * called afterwards. */ -int put_on_cmdline(str, len, redraw) -char_u *str; -int len; -int redraw; +int put_on_cmdline(char_u *str, int len, int redraw) { int retval; int i; @@ -2298,8 +2294,7 @@ static int prev_ccline_used = FALSE; * and overwrite it. But get_cmdline_str() may need it, thus make it * available globally in prev_ccline. */ -static void save_cmdline(ccp) -struct cmdline_info *ccp; +static void save_cmdline(struct cmdline_info *ccp) { if (!prev_ccline_used) { vim_memset(&prev_ccline, 0, sizeof(struct cmdline_info)); @@ -2315,8 +2310,7 @@ struct cmdline_info *ccp; /* * Restore ccline after it has been saved with save_cmdline(). */ -static void restore_cmdline(ccp) -struct cmdline_info *ccp; +static void restore_cmdline(struct cmdline_info *ccp) { ccline = prev_ccline; prev_ccline = *ccp; @@ -2327,7 +2321,7 @@ struct cmdline_info *ccp; * passed to restore_cmdline_alloc() later. * Returns NULL when failed. */ -char_u * save_cmdline_alloc() { +char_u *save_cmdline_alloc(void) { struct cmdline_info *p; p = (struct cmdline_info *)alloc((unsigned)sizeof(struct cmdline_info)); @@ -2339,8 +2333,7 @@ char_u * save_cmdline_alloc() { /* * Restore the command line from the return value of save_cmdline_alloc(). */ -void restore_cmdline_alloc(p) -char_u *p; +void restore_cmdline_alloc(char_u *p) { if (p != NULL) { restore_cmdline((struct cmdline_info *)p); @@ -2356,10 +2349,12 @@ char_u *p; * * return FAIL for failure, OK otherwise */ -static int cmdline_paste(regname, literally, remcr) -int regname; -int literally; /* Insert text literally instead of "as typed" */ -int remcr; /* remove trailing CR */ +static int +cmdline_paste ( + int regname, + int literally, /* Insert text literally instead of "as typed" */ + int remcr /* remove trailing CR */ +) { long i; char_u *arg; @@ -2433,9 +2428,7 @@ int remcr; /* remove trailing CR */ * When "literally" is FALSE, insert as typed, but don't leave the command * line. */ -void cmdline_paste_str(s, literally) -char_u *s; -int literally; +void cmdline_paste_str(char_u *s, int literally) { int c, cv; @@ -2465,8 +2458,7 @@ int literally; * Delete characters on the command line, from "from" to the current * position. */ -static void cmdline_del(from) -int from; +static void cmdline_del(int from) { mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos, (size_t)(ccline.cmdlen - ccline.cmdpos + 1)); @@ -2478,7 +2470,7 @@ int from; * this function is called when the screen size changes and with incremental * search */ -void redrawcmdline() { +void redrawcmdline(void) { if (cmd_silent) return; need_wait_return = FALSE; @@ -2487,7 +2479,7 @@ void redrawcmdline() { cursorcmd(); } -static void redrawcmdprompt() { +static void redrawcmdprompt(void) { int i; if (cmd_silent) @@ -2508,7 +2500,7 @@ static void redrawcmdprompt() { /* * Redraw what is currently on the command line. */ -void redrawcmd() { +void redrawcmd(void) { if (cmd_silent) return; @@ -2541,7 +2533,7 @@ void redrawcmd() { skip_redraw = FALSE; } -void compute_cmdrow() { +void compute_cmdrow(void) { if (exmode_active || msg_scrolled != 0) cmdline_row = Rows - 1; else @@ -2549,7 +2541,7 @@ void compute_cmdrow() { + W_STATUS_HEIGHT(lastwin); } -static void cursorcmd() { +static void cursorcmd(void) { if (cmd_silent) return; @@ -2568,8 +2560,7 @@ static void cursorcmd() { windgoto(msg_row, msg_col); } -void gotocmdline(clr) -int clr; +void gotocmdline(int clr) { msg_start(); if (cmdmsg_rl) @@ -2587,8 +2578,7 @@ int clr; * When an abbreviation is recognized it is removed from the text with * backspaces and the replacement string is inserted, followed by "c". */ -static int ccheck_abbr(c) -int c; +static int ccheck_abbr(int c) { if (p_paste || no_abbr) /* no abbreviations or in paste mode */ return FALSE; @@ -2596,9 +2586,7 @@ int c; return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0); } -static int sort_func_compare(s1, s2) -const void *s1; -const void *s2; +static int sort_func_compare(const void *s1, const void *s2) { char_u *p1 = *(char_u **)s1; char_u *p2 = *(char_u **)s2; @@ -2614,11 +2602,13 @@ const void *s2; * For the caller, this means that the character is just passed through like a * normal character (instead of being expanded). This allows :s/^I^D etc. */ -static int nextwild(xp, type, options, escape) -expand_T *xp; -int type; -int options; /* extra options for ExpandOne() */ -int escape; /* if TRUE, escape the returned matches */ +static int +nextwild ( + expand_T *xp, + int type, + int options, /* extra options for ExpandOne() */ + int escape /* if TRUE, escape the returned matches */ +) { int i, j; char_u *p1; @@ -2753,12 +2743,14 @@ int escape; /* if TRUE, escape the returned matches */ * * The variables xp->xp_context and xp->xp_backslash must have been set! */ -char_u * ExpandOne(xp, str, orig, options, mode) -expand_T *xp; -char_u *str; -char_u *orig; /* allocated copy of original of expanded string */ -int options; -int mode; +char_u * +ExpandOne ( + expand_T *xp, + char_u *str, + char_u *orig, /* allocated copy of original of expanded string */ + int options, + int mode +) { char_u *ss = NULL; static int findex; @@ -2937,8 +2929,7 @@ int mode; /* * Prepare an expand structure for use. */ -void ExpandInit(xp) -expand_T *xp; +void ExpandInit(expand_T *xp) { xp->xp_pattern = NULL; xp->xp_pattern_len = 0; @@ -2955,8 +2946,7 @@ expand_T *xp; /* * Cleanup an expand structure after use. */ -void ExpandCleanup(xp) -expand_T *xp; +void ExpandCleanup(expand_T *xp) { if (xp->xp_numfiles >= 0) { FreeWild(xp->xp_numfiles, xp->xp_files); @@ -2964,12 +2954,7 @@ expand_T *xp; } } -void ExpandEscape(xp, str, numfiles, files, options) -expand_T *xp; -char_u *str; -int numfiles; -char_u **files; -int options; +void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int options) { int i; char_u *p; @@ -3048,9 +3033,7 @@ int options; * after a Vim command, or, when "shell" is non-zero, a shell command. * Returns the result in allocated memory. */ -char_u * vim_strsave_fnameescape(fname, shell) -char_u *fname; -int shell; +char_u *vim_strsave_fnameescape(char_u *fname, int shell) { char_u *p; #ifdef BACKSLASH_IN_FILENAME @@ -3087,8 +3070,7 @@ int shell; /* * Put a backslash before the file name in "pp", which is in allocated memory. */ -static void escape_fname(pp) -char_u **pp; +static void escape_fname(char_u **pp) { char_u *p; @@ -3105,10 +3087,7 @@ char_u **pp; * For each file name in files[num_files]: * If 'orig_pat' starts with "~/", replace the home directory with "~". */ -void tilde_replace(orig_pat, num_files, files) -char_u *orig_pat; -int num_files; -char_u **files; +void tilde_replace(char_u *orig_pat, int num_files, char_u **files) { int i; char_u *p; @@ -3129,9 +3108,7 @@ char_u **files; * Returns EXPAND_NOTHING when the character that triggered expansion should * be inserted like a normal character. */ -static int showmatches(xp, wildmenu) -expand_T *xp; -int wildmenu UNUSED; +static int showmatches(expand_T *xp, int wildmenu) { #define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m]) int num_files; @@ -3285,8 +3262,7 @@ int wildmenu UNUSED; * Private gettail for showmatches() (and win_redr_status_matches()): * Find tail of file name path, but ignore trailing "/". */ -char_u * sm_gettail(s) -char_u *s; +char_u *sm_gettail(char_u *s) { char_u *p; char_u *t = s; @@ -3313,8 +3289,7 @@ char_u *s; * When not completing file names or there is a wildcard in the path FALSE is * returned. */ -static int expand_showtail(xp) -expand_T *xp; +static int expand_showtail(expand_T *xp) { char_u *s; char_u *end; @@ -3347,10 +3322,12 @@ expand_T *xp; * When expanding other names: The string will be used with regcomp(). Copy * the name into allocated memory and prepend "^". */ -char_u * addstar(fname, len, context) -char_u *fname; -int len; -int context; /* EXPAND_FILES etc. */ +char_u * +addstar ( + char_u *fname, + int len, + int context /* EXPAND_FILES etc. */ +) { char_u *retval; int i, j; @@ -3505,8 +3482,7 @@ int context; /* EXPAND_FILES etc. */ * EXPAND_ENV_VARS Complete environment variable names * EXPAND_USER Complete user names */ -static void set_expand_context(xp) -expand_T *xp; +static void set_expand_context(expand_T *xp) { /* only expansion for ':', '>' and '=' command-lines */ if (ccline.cmdfirstc != ':' @@ -3519,11 +3495,13 @@ expand_T *xp; set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos); } -void set_cmd_context(xp, str, len, col) -expand_T *xp; -char_u *str; /* start of command line */ -int len; /* length of command line (excl. NUL) */ -int col; /* position of cursor */ +void +set_cmd_context ( + expand_T *xp, + char_u *str, /* start of command line */ + int len, /* length of command line (excl. NUL) */ + int col /* position of cursor */ +) { int old_char = NUL; char_u *nextcomm; @@ -3567,12 +3545,14 @@ int col; /* position of cursor */ * key that triggered expansion literally. * Returns EXPAND_OK otherwise. */ -int expand_cmdline(xp, str, col, matchcount, matches) -expand_T *xp; -char_u *str; /* start of command line */ -int col; /* position of cursor */ -int *matchcount; /* return: nr of matches */ -char_u ***matches; /* return: array of pointers to matches */ +int +expand_cmdline ( + expand_T *xp, + char_u *str, /* start of command line */ + int col, /* position of cursor */ + int *matchcount, /* return: nr of matches */ + char_u ***matches /* return: array of pointers to matches */ +) { char_u *file_str = NULL; int options = WILD_ADD_SLASH|WILD_SILENT; @@ -3610,9 +3590,7 @@ char_u ***matches; /* return: array of pointers to matches */ */ static void cleanup_help_tags __ARGS((int num_file, char_u **file)); -static void cleanup_help_tags(num_file, file) -int num_file; -char_u **file; +static void cleanup_help_tags(int num_file, char_u **file) { int i, j; int len; @@ -3636,12 +3614,14 @@ char_u **file; /* * Do the expansion based on xp->xp_context and "pat". */ -static int ExpandFromContext(xp, pat, num_file, file, options) -expand_T *xp; -char_u *pat; -int *num_file; -char_u ***file; -int options; /* EW_ flags */ +static int +ExpandFromContext ( + expand_T *xp, + char_u *pat, + int *num_file, + char_u ***file, + int options /* EW_ flags */ +) { regmatch_T regmatch; int ret; @@ -3900,11 +3880,13 @@ int escaped; * Complete a shell command. * Returns FAIL or OK; */ -static int expand_shellcmd(filepat, num_file, file, flagsarg) -char_u *filepat; /* pattern to match with command names */ -int *num_file; /* return: number of matches */ -char_u ***file; /* return: array with matches */ -int flagsarg; /* EW_ flags */ +static int +expand_shellcmd ( + char_u *filepat, /* pattern to match with command names */ + int *num_file, /* return: number of matches */ + char_u ***file, /* return: array with matches */ + int flagsarg /* EW_ flags */ +) { char_u *pat; int i; @@ -4051,11 +4033,7 @@ char_u ***file; /* * Expand names with a function defined by the user. */ -static int ExpandUserDefined(xp, regmatch, num_file, file) -expand_T *xp; -regmatch_T *regmatch; -int *num_file; -char_u ***file; +static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file) { char_u *retstr; char_u *s; @@ -4101,10 +4079,7 @@ char_u ***file; /* * Expand names with a list returned by a function defined by the user. */ -static int ExpandUserList(xp, num_file, file) -expand_T *xp; -int *num_file; -char_u ***file; +static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file) { list_T *retlist; listitem_T *li; @@ -4139,11 +4114,7 @@ char_u ***file; * 'runtimepath'/{dirnames}/{pat}.vim * "dirnames" is an array with one or more directory names. */ -static int ExpandRTDir(pat, num_file, file, dirnames) -char_u *pat; -int *num_file; -char_u ***file; -char *dirnames[]; +static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirnames[]) { char_u *matches; char_u *s; @@ -4207,10 +4178,7 @@ char *dirnames[]; * Returns an allocated string with all matches concatenated, separated by * newlines. Returns NULL for an error or no matches. */ -char_u * globpath(path, file, expand_options) -char_u *path; -char_u *file; -int expand_options; +char_u *globpath(char_u *path, char_u *file, int expand_options) { expand_T xpc; char_u *buf; @@ -4273,8 +4241,7 @@ int expand_options; /* * Translate a history character to the associated type number. */ -static int hist_char2type(c) -int c; +static int hist_char2type(int c) { if (c == ':') return HIST_CMD; @@ -4307,9 +4274,7 @@ static char *(history_names[]) = * Function given to ExpandGeneric() to obtain the possible first * arguments of the ":history command. */ -static char_u * get_history_arg(xp, idx) -expand_T *xp UNUSED; -int idx; +static char_u *get_history_arg(expand_T *xp, int idx) { static char_u compl[2] = { NUL, NUL }; char *short_names = ":=@>?/"; @@ -4331,7 +4296,7 @@ int idx; * init_history() - Initialize the command line history. * Also used to re-allocate the history when the size changes. */ -void init_history() { +void init_history(void) { int newlen; /* new length of history table */ histentry_T *temp; int i; @@ -4394,8 +4359,7 @@ void init_history() { } } -static void clear_hist_entry(hisptr) -histentry_T *hisptr; +static void clear_hist_entry(histentry_T *hisptr) { hisptr->hisnum = 0; hisptr->viminfo = FALSE; @@ -4406,12 +4370,14 @@ histentry_T *hisptr; * Check if command line 'str' is already in history. * If 'move_to_front' is TRUE, matching entry is moved to end of history. */ -static int in_history(type, str, move_to_front, sep, writing) -int type; -char_u *str; -int move_to_front; /* Move the entry to the front if it exists */ -int sep; -int writing; /* ignore entries read from viminfo */ +static int +in_history ( + int type, + char_u *str, + int move_to_front, /* Move the entry to the front if it exists */ + int sep, + int writing /* ignore entries read from viminfo */ +) { int i; int last_i = -1; @@ -4460,8 +4426,7 @@ int writing; /* ignore entries read from viminfo */ * When "name" is empty, return "cmd" history. * Returns -1 for unknown history name. */ -int get_histtype(name) -char_u *name; +int get_histtype(char_u *name) { int i; int len = (int)STRLEN(name); @@ -4487,11 +4452,13 @@ static int last_maptick = -1; /* last seen maptick */ * history then it is moved to the front. "histype" may be one of he HIST_ * values. */ -void add_to_history(histype, new_entry, in_map, sep) -int histype; -char_u *new_entry; -int in_map; /* consider maptick when inside a mapping */ -int sep; /* separator character used (search hist) */ +void +add_to_history ( + int histype, + char_u *new_entry, + int in_map, /* consider maptick when inside a mapping */ + int sep /* separator character used (search hist) */ +) { histentry_T *hisptr; int len; @@ -4543,8 +4510,7 @@ int sep; /* separator character used (search hist) */ * Get identifier of newest history entry. * "histype" may be one of the HIST_ values. */ -int get_history_idx(histype) -int histype; +int get_history_idx(int histype) { if (hislen == 0 || histype < 0 || histype >= HIST_COUNT || hisidx[histype] < 0) @@ -4559,7 +4525,7 @@ static struct cmdline_info *get_ccline_ptr __ARGS((void)); * Get pointer to the command line info to use. cmdline_paste() may clear * ccline and put the previous value in prev_ccline. */ -static struct cmdline_info * get_ccline_ptr() +static struct cmdline_info *get_ccline_ptr(void) { if ((State & CMDLINE) == 0) return NULL; @@ -4575,7 +4541,7 @@ static struct cmdline_info * get_ccline_ptr() * Only works when the command line is being edited. * Returns NULL when something is wrong. */ -char_u * get_cmdline_str() { +char_u *get_cmdline_str(void) { struct cmdline_info *p = get_ccline_ptr(); if (p == NULL) @@ -4589,7 +4555,7 @@ char_u * get_cmdline_str() { * Only works when the command line is being edited. * Returns -1 when something is wrong. */ -int get_cmdline_pos() { +int get_cmdline_pos(void) { struct cmdline_info *p = get_ccline_ptr(); if (p == NULL) @@ -4602,8 +4568,7 @@ int get_cmdline_pos() { * Only works when the command line is being edited. * Returns 1 when failed, 0 when OK. */ -int set_cmdline_pos(pos) -int pos; +int set_cmdline_pos(int pos) { struct cmdline_info *p = get_ccline_ptr(); @@ -4625,7 +4590,7 @@ int pos; * Only works when the command line is being edited. * Returns NUL when something is wrong. */ -int get_cmdline_type() { +int get_cmdline_type(void) { struct cmdline_info *p = get_ccline_ptr(); if (p == NULL) @@ -4641,9 +4606,7 @@ int get_cmdline_type() { * num < 0: relative position in history wrt newest entry * "histype" may be one of the HIST_ values. */ -static int calc_hist_idx(histype, num) -int histype; -int num; +static int calc_hist_idx(int histype, int num) { int i; histentry_T *hist; @@ -4678,9 +4641,7 @@ int num; * Get a history entry by its index. * "histype" may be one of the HIST_ values. */ -char_u * get_history_entry(histype, idx) -int histype; -int idx; +char_u *get_history_entry(int histype, int idx) { idx = calc_hist_idx(histype, idx); if (idx >= 0) @@ -4693,8 +4654,7 @@ int idx; * Clear all entries of a history. * "histype" may be one of the HIST_ values. */ -int clr_history(histype) -int histype; +int clr_history(int histype) { int i; histentry_T *hisptr; @@ -4716,9 +4676,7 @@ int histype; * Remove all entries matching {str} from a history. * "histype" may be one of the HIST_ values. */ -int del_history_entry(histype, str) -int histype; -char_u *str; +int del_history_entry(int histype, char_u *str) { regmatch_T regmatch; histentry_T *hisptr; @@ -4767,9 +4725,7 @@ char_u *str; * Remove an indexed entry from a history. * "histype" may be one of the HIST_ values. */ -int del_history_idx(histype, idx) -int histype; -int idx; +int del_history_idx(int histype, int idx) { int i, j; @@ -4802,7 +4758,7 @@ int idx; * Very specific function to remove the value in ":set key=val" from the * history. */ -void remove_key_from_history() { +void remove_key_from_history(void) { char_u *p; int i; @@ -4830,10 +4786,7 @@ void remove_key_from_history() { * text lines in a buffer!) from a string. Used for ":history" and ":clist". * Returns OK if parsed successfully, otherwise FAIL. */ -int get_list_range(str, num1, num2) -char_u **str; -int *num1; -int *num2; +int get_list_range(char_u **str, int *num1, int *num2) { int len; int first = FALSE; @@ -4863,8 +4816,7 @@ int *num2; /* * :history command - print a history */ -void ex_history(eap) -exarg_T *eap; +void ex_history(exarg_T *eap) { histentry_T *hist; int histype1 = HIST_CMD; @@ -4956,9 +4908,11 @@ static int hist_type2char __ARGS((int type, int use_question)); /* * Translate a history type number to the associated character. */ -static int hist_type2char(type, use_question) -int type; -int use_question; /* use '?' instead of '/' */ +static int +hist_type2char ( + int type, + int use_question /* use '?' instead of '/' */ +) { if (type == HIST_CMD) return ':'; @@ -4977,9 +4931,7 @@ int use_question; /* use '?' instead of '/' */ * Prepare for reading the history from the viminfo file. * This allocates history arrays to store the read history lines. */ -void prepare_viminfo_history(asklen, writing) -int asklen; -int writing; +void prepare_viminfo_history(int asklen, int writing) { int i; int num; @@ -5017,9 +4969,7 @@ int writing; * Accept a line from the viminfo, store it in the history array when it's * new. */ -int read_viminfo_history(virp, writing) -vir_T *virp; -int writing; +int read_viminfo_history(vir_T *virp, int writing) { int type; long_u len; @@ -5061,7 +5011,7 @@ int writing; /* * Finish reading history lines from viminfo. Not used when writing viminfo. */ -void finish_viminfo_history() { +void finish_viminfo_history(void) { int idx; int i; int type; @@ -5114,9 +5064,7 @@ void finish_viminfo_history() { * file, data is in viminfo_history[]. * When "merge" is FALSE just write all history lines. Used for ":wviminfo!". */ -void write_viminfo_history(fp, merge) -FILE *fp; -int merge; +void write_viminfo_history(FILE *fp, int merge) { int i; int type; @@ -5202,8 +5150,7 @@ int merge; * Write a character at the current cursor+offset position. * It is directly written into the command buffer block. */ -void cmd_pchar(c, offset) -int c, offset; +void cmd_pchar(int c, int offset) { if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0) { EMSG(_("E198: cmd_pchar beyond the command length")); @@ -5213,8 +5160,7 @@ int c, offset; ccline.cmdbuff[ccline.cmdlen] = NUL; } -int cmd_gchar(offset) -int offset; +int cmd_gchar(int offset) { if (ccline.cmdpos + offset >= ccline.cmdlen || ccline.cmdpos + offset < 0) { /* EMSG(_("cmd_gchar beyond the command length")); */ @@ -5231,7 +5177,7 @@ int offset; * Ctrl_C if it is to be abandoned * K_IGNORE if editing continues */ -static int ex_window() { +static int ex_window(void) { struct cmdline_info save_ccline; buf_T *old_curbuf = curbuf; win_T *old_curwin = curwin; @@ -5447,9 +5393,7 @@ static int ex_window() { * endmarker * Returns a pointer to allocated memory with {script} or NULL. */ -char_u * script_get(eap, cmd) -exarg_T *eap; -char_u *cmd; +char_u *script_get(exarg_T *eap, char_u *cmd) { char_u *theline; char *end_pattern = NULL; diff --git a/src/farsi.c b/src/farsi.c index a76f37fd26..9c28284166 100644 --- a/src/farsi.c +++ b/src/farsi.c @@ -37,8 +37,7 @@ static void lrswapbuf __ARGS((char_u *buf, int len)); /* ** Convert the given Farsi character into a _X or _X_ type */ -static int toF_Xor_X_(c) -int c; +static int toF_Xor_X_(int c) { int tempc; @@ -127,8 +126,7 @@ int c; /* ** Convert the given Farsi character into Farsi capital character . */ -int toF_TyA(c) -int c; +int toF_TyA(int c) { switch (c) { case ALEF_: @@ -205,8 +203,7 @@ int c; ** That is a character that is combined with the others. ** Note: the offset is used only for command line buffer. */ -static int F_is_TyB_TyC_TyD(src, offset) -int src, offset; +static int F_is_TyB_TyC_TyD(int src, int offset) { int c; @@ -255,8 +252,7 @@ int src, offset; /* ** Is the Farsi character one of the terminating only type. */ -static int F_is_TyE(c) -int c; +static int F_is_TyE(int c) { switch (c) { case ALEF_A: @@ -277,8 +273,7 @@ int c; /* ** Is the Farsi character one of the none leading type. */ -static int F_is_TyC_TyD(c) -int c; +static int F_is_TyC_TyD(int c) { switch (c) { case ALEF_: @@ -300,8 +295,7 @@ int c; /* ** Convert a none leading Farsi char into a leading type. */ -static int toF_TyB(c) -int c; +static int toF_TyB(int c) { switch (c) { case ALEF_: return ALEF; @@ -322,8 +316,7 @@ int c; /* ** Overwrite the current redo and cursor characters + left adjust */ -static void put_curr_and_l_to_X(c) -int c; +static void put_curr_and_l_to_X(int c) { int tempc; @@ -353,8 +346,7 @@ int c; put_and_redo(c); } -static void put_and_redo(c) -int c; +static void put_and_redo(int c) { pchar_cursor(c); AppendCharToRedobuff(K_BS); @@ -364,7 +356,7 @@ int c; /* ** Change the char. under the cursor to a X_ or X type */ -static void chg_c_toX_orX() { +static void chg_c_toX_orX(void) { int tempc, curc; switch ((curc = gchar_cursor())) { @@ -481,7 +473,7 @@ static void chg_c_toX_orX() { ** Change the char. under the cursor to a _X_ or X_ type */ -static void chg_c_to_X_orX_() { +static void chg_c_to_X_orX_(void) { int tempc; switch (gchar_cursor()) { @@ -529,7 +521,7 @@ static void chg_c_to_X_orX_() { /* ** Change the char. under the cursor to a _X_ or _X type */ -static void chg_c_to_X_or_X () { +static void chg_c_to_X_or_X(void) { int tempc; tempc = gchar_cursor(); @@ -556,7 +548,7 @@ static void chg_c_to_X_or_X () { /* ** Change the character left to the cursor to a _X_ or X_ type */ -static void chg_l_to_X_orX_ () { +static void chg_l_to_X_orX_(void) { int tempc; if (curwin->w_cursor.col != 0 && @@ -622,7 +614,7 @@ static void chg_l_to_X_orX_ () { ** Change the character left to the cursor to a X or _X type */ -static void chg_l_toXor_X () { +static void chg_l_toXor_X(void) { int tempc; if (curwin->w_cursor.col != 0 && @@ -688,7 +680,7 @@ static void chg_l_toXor_X () { ** Change the character right to the cursor to a _X or _X_ type */ -static void chg_r_to_Xor_X_() { +static void chg_r_to_Xor_X_(void) { int tempc, c; if (curwin->w_cursor.col) { @@ -710,8 +702,7 @@ static void chg_r_to_Xor_X_() { ** Map Farsi keyboard when in fkmap mode. */ -int fkmap(c) -int c; +int fkmap(int c) { int tempc; static int revins; @@ -1387,8 +1378,7 @@ int c; /* ** Convert a none leading Farsi char into a leading type. */ -static int toF_leading(c) -int c; +static int toF_leading(int c) { switch (c) { case ALEF_: return ALEF; @@ -1440,8 +1430,7 @@ int c; /* ** Convert a given Farsi char into right joining type. */ -static int toF_Rjoin(c) -int c; +static int toF_Rjoin(int c) { switch (c) { case ALEF: return ALEF_; @@ -1495,8 +1484,7 @@ int c; /* ** Can a given Farsi character join via its left edj. */ -static int canF_Ljoin(c) -int c; +static int canF_Ljoin(int c) { switch (c) { case _BE: @@ -1568,8 +1556,7 @@ int c; /* ** Can a given Farsi character join via its right edj. */ -static int canF_Rjoin(c) -int c; +static int canF_Rjoin(int c) { switch (c) { case ALEF: @@ -1595,8 +1582,7 @@ int c; /* ** is a given Farsi character a terminating type. */ -static int F_isterm(c) -int c; +static int F_isterm(int c) { switch (c) { case ALEF: @@ -1621,8 +1607,7 @@ int c; /* ** Convert the given Farsi character into a ending type . */ -static int toF_ending(c) -int c; +static int toF_ending(int c) { switch (c) { @@ -1697,7 +1682,7 @@ int c; /* ** Convert the Farsi 3342 standard into Farsi VIM. */ -void conv_to_pvim() { +void conv_to_pvim(void) { char_u *ptr; int lnum, llen, i; @@ -1739,7 +1724,7 @@ void conv_to_pvim() { /* * Convert the Farsi VIM into Farsi 3342 standard. */ -void conv_to_pstd() { +void conv_to_pstd(void) { char_u *ptr; int lnum, llen, i; @@ -1768,9 +1753,7 @@ void conv_to_pstd() { /* * left-right swap the characters in buf[len]. */ -static void lrswapbuf(buf, len) -char_u *buf; -int len; +static void lrswapbuf(char_u *buf, int len) { char_u *s, *e; int c; @@ -1790,8 +1773,7 @@ int len; /* * swap all the characters in reverse direction */ -char_u * lrswap(ibuf) -char_u *ibuf; +char_u *lrswap(char_u *ibuf) { if (ibuf != NULL && *ibuf != NUL) lrswapbuf(ibuf, (int)STRLEN(ibuf)); @@ -1801,9 +1783,7 @@ char_u *ibuf; /* * swap all the Farsi characters in reverse direction */ -char_u * lrFswap(cmdbuf, len) -char_u *cmdbuf; -int len; +char_u *lrFswap(char_u *cmdbuf, int len) { int i, cnt; @@ -1831,8 +1811,7 @@ int len; * accordingly. * TODO: handle different separator characters. Use skip_regexp(). */ -char_u * lrF_sub(ibuf) -char_u *ibuf; +char_u *lrF_sub(char_u *ibuf) { char_u *p, *ep; int i, cnt; @@ -1870,8 +1849,7 @@ char_u *ibuf; /* * Map Farsi keyboard when in cmd_fkmap mode. */ -int cmdl_fkmap(c) -int c; +int cmdl_fkmap(int c) { int tempc; @@ -2124,8 +2102,7 @@ int c; /* * F_isalpha returns TRUE if 'c' is a Farsi alphabet */ -int F_isalpha(c) -int c; +int F_isalpha(int c) { return ( c >= TEE_ && c <= _YE) || (c >= ALEF_A && c <= YE) @@ -2135,8 +2112,7 @@ int c; /* * F_isdigit returns TRUE if 'c' is a Farsi digit */ -int F_isdigit(c) -int c; +int F_isdigit(int c) { return c >= FARSI_0 && c <= FARSI_9; } @@ -2144,14 +2120,12 @@ int c; /* * F_ischar returns TRUE if 'c' is a Farsi character. */ -int F_ischar(c) -int c; +int F_ischar(int c) { return c >= TEE_ && c <= YE_; } -void farsi_fkey(cap) -cmdarg_T *cap; +void farsi_fkey(cmdarg_T *cap) { int c = cap->cmdchar; diff --git a/src/fileio.c b/src/fileio.c index d05181e654..e4d261d902 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -121,11 +121,7 @@ static void vim_settempdir __ARGS((char_u *tempdir)); static char *e_auchangedbuf = N_( "E812: Autocommands changed buffer or buffer name"); -void filemess(buf, name, s, attr) -buf_T *buf; -char_u *name; -char_u *s; -int attr; +void filemess(buf_T *buf, char_u *name, char_u *s, int attr) { int msg_scroll_save; @@ -180,14 +176,16 @@ int attr; * * return FAIL for failure, OK otherwise */ -int readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags) -char_u *fname; -char_u *sfname; -linenr_T from; -linenr_T lines_to_skip; -linenr_T lines_to_read; -exarg_T *eap; /* can be NULL! */ -int flags; +int +readfile ( + char_u *fname, + char_u *sfname, + linenr_T from, + linenr_T lines_to_skip, + linenr_T lines_to_read, + exarg_T *eap, /* can be NULL! */ + int flags +) { int fd = 0; int newfile = (flags & READ_NEW); @@ -2020,8 +2018,7 @@ failed: * some shells on some operating systems, e.g., bash on SunOS. * Do not accept "/dev/fd/[012]", opening these may hang Vim. */ -static int is_dev_fd_file(fname) -char_u *fname; +static int is_dev_fd_file(char_u *fname) { return STRNCMP(fname, "/dev/fd/", 8) == 0 && VIM_ISDIGIT(fname[8]) @@ -2037,10 +2034,12 @@ char_u *fname; * line number where we are now. * Used for error messages that include a line number. */ -static linenr_T readfile_linenr(linecnt, p, endp) -linenr_T linecnt; /* line count before reading more bytes */ -char_u *p; /* start of more bytes read */ -char_u *endp; /* end of more bytes read */ +static linenr_T +readfile_linenr ( + linenr_T linecnt, /* line count before reading more bytes */ + char_u *p, /* start of more bytes read */ + char_u *endp /* end of more bytes read */ +) { char_u *s; linenr_T lnum; @@ -2057,9 +2056,7 @@ char_u *endp; /* end of more bytes read */ * equal to the buffer "buf". Used for calling readfile(). * Returns OK or FAIL. */ -int prep_exarg(eap, buf) -exarg_T *eap; -buf_T *buf; +int prep_exarg(exarg_T *eap, buf_T *buf) { eap->cmd = alloc((unsigned)(STRLEN(buf->b_p_ff) + STRLEN(buf->b_p_fenc) @@ -2081,9 +2078,7 @@ buf_T *buf; /* * Set default or forced 'fileformat' and 'binary'. */ -void set_file_options(set_options, eap) -int set_options; -exarg_T *eap; +void set_file_options(int set_options, exarg_T *eap) { /* set default 'fileformat' */ if (set_options) { @@ -2105,8 +2100,7 @@ exarg_T *eap; /* * Set forced 'fileencoding'. */ -void set_forced_fenc(eap) -exarg_T *eap; +void set_forced_fenc(exarg_T *eap) { if (eap->force_enc != 0) { char_u *fenc = enc_canonize(eap->cmd + eap->force_enc); @@ -2125,8 +2119,7 @@ exarg_T *eap; * NULL. * When *pp is not set to NULL, the result is in allocated memory. */ -static char_u * next_fenc(pp) -char_u **pp; +static char_u *next_fenc(char_u **pp) { char_u *p; char_u *r; @@ -2163,10 +2156,12 @@ char_u **pp; * after reading it). * Returns NULL if the conversion failed ("*fdp" is not set) . */ -static char_u * readfile_charconvert(fname, fenc, fdp) -char_u *fname; /* name of input file */ -char_u *fenc; /* converted from */ -int *fdp; /* in/out: file descriptor of file */ +static char_u * +readfile_charconvert ( + char_u *fname, /* name of input file */ + char_u *fenc, /* converted from */ + int *fdp /* in/out: file descriptor of file */ +) { char_u *tmpname; char_u *errmsg = NULL; @@ -2208,7 +2203,7 @@ int *fdp; /* in/out: file descriptor of file */ * Read marks for the current buffer from the viminfo file, when we support * buffer marks and the buffer has a name. */ -static void check_marks_read() { +static void check_marks_read(void) { if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0 && curbuf->b_ffname != NULL) read_viminfo(NULL, VIF_WANT_MARKS); @@ -2223,9 +2218,7 @@ static void check_marks_read() { * start of the file. * Returns -1 when no encryption used. */ -static int crypt_method_from_magic(ptr, len) -char *ptr; -int len; +static int crypt_method_from_magic(char *ptr, int len) { int i; @@ -2249,16 +2242,16 @@ int len; * *filesizep are updated. * Return the (new) encryption key, NULL for no encryption. */ -static char_u * check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, - fname, - did_ask) -char_u *cryptkey; /* previous encryption key or NULL */ -char_u *ptr; /* pointer to read bytes */ -long *sizep; /* length of read bytes */ -off_t *filesizep; /* nr of bytes used from file */ -int newfile; /* editing a new buffer */ -char_u *fname; /* file name to display */ -int *did_ask; /* flag: whether already asked for key */ +static char_u * +check_for_cryptkey ( + char_u *cryptkey, /* previous encryption key or NULL */ + char_u *ptr, /* pointer to read bytes */ + long *sizep, /* length of read bytes */ + off_t *filesizep, /* nr of bytes used from file */ + int newfile, /* editing a new buffer */ + char_u *fname, /* file name to display */ + int *did_ask /* flag: whether already asked for key */ +) { int method = crypt_method_from_magic((char *)ptr, *sizep); int b_p_ro = curbuf->b_p_ro; @@ -2327,8 +2320,7 @@ int *did_ask; /* flag: whether already asked for key */ * Check for magic number used for encryption. Applies to the current buffer. * If found and decryption is possible returns OK; */ -int prepare_crypt_read(fp) -FILE *fp; +int prepare_crypt_read(FILE *fp) { int method; char_u buffer[CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX @@ -2364,9 +2356,7 @@ FILE *fp; * When out of memory returns NULL. * Otherwise calls crypt_push_state(), call crypt_pop_state() later. */ -char_u * prepare_crypt_write(buf, lenp) -buf_T *buf; -int *lenp; +char_u *prepare_crypt_write(buf_T *buf, int *lenp) { char_u *header; int seed_len = crypt_seed_len[get_crypt_method(buf)]; @@ -2398,10 +2388,12 @@ int *lenp; #ifdef UNIX -static void set_file_time(fname, atime, mtime) -char_u *fname; -time_t atime; /* access time */ -time_t mtime; /* modification time */ +static void +set_file_time ( + char_u *fname, + time_t atime, /* access time */ + time_t mtime /* modification time */ +) { # if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) struct utimbuf buf; @@ -2427,9 +2419,11 @@ time_t mtime; /* modification time */ /* * Return TRUE if a file appears to be read-only from the file permissions. */ -int check_file_readonly(fname, perm) -char_u *fname; /* full path to file */ -int perm; /* known permissions on file */ +int +check_file_readonly ( + char_u *fname, /* full path to file */ + int perm /* known permissions on file */ +) { #ifndef USE_MCH_ACCESS int fd = 0; @@ -2465,18 +2459,20 @@ int perm; /* known permissions on file */ * * return FAIL for failure, OK otherwise */ -int buf_write(buf, fname, sfname, start, end, eap, append, forceit, - reset_changed, filtering) -buf_T *buf; -char_u *fname; -char_u *sfname; -linenr_T start, end; -exarg_T *eap; /* for forced 'ff' and 'fenc', can be +int +buf_write ( + buf_T *buf, + char_u *fname, + char_u *sfname, + linenr_T start, + linenr_T end, + exarg_T *eap, /* for forced 'ff' and 'fenc', can be NULL! */ -int append; /* append to the file */ -int forceit; -int reset_changed; -int filtering; + int append, /* append to the file */ + int forceit, + int reset_changed, + int filtering +) { int fd; char_u *backup = NULL; @@ -4094,9 +4090,7 @@ nofail: * Set the name of the current buffer. Use when the buffer doesn't have a * name and a ":r" or ":w" command with a file name is used. */ -static int set_rw_fname(fname, sfname) -char_u *fname; -char_u *sfname; +static int set_rw_fname(char_u *fname, char_u *sfname) { buf_T *buf = curbuf; @@ -4135,9 +4129,7 @@ char_u *sfname; /* * Put file name into IObuff with quotes. */ -void msg_add_fname(buf, fname) -buf_T *buf; -char_u *fname; +void msg_add_fname(buf_T *buf, char_u *fname) { if (fname == NULL) fname = (char_u *)"-stdin-"; @@ -4150,8 +4142,7 @@ char_u *fname; * Append message for text mode to IObuff. * Return TRUE if something appended. */ -static int msg_add_fileformat(eol_type) -int eol_type; +static int msg_add_fileformat(int eol_type) { #ifndef USE_CRNL if (eol_type == EOL_DOS) { @@ -4177,10 +4168,7 @@ int eol_type; /* * Append line and character count to IObuff. */ -void msg_add_lines(insert_space, lnum, nchars) -int insert_space; -long lnum; -off_t nchars; +void msg_add_lines(int insert_space, long lnum, off_t nchars) { char_u *p; @@ -4220,7 +4208,7 @@ off_t nchars; /* * Append message for missing line separator to IObuff. */ -static void msg_add_eol() { +static void msg_add_eol(void) { STRCAT(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); } @@ -4230,9 +4218,7 @@ static void msg_add_eol() { * The size isn't checked, because using a tool like "gzip" takes care of * using the same timestamp but can't set the size. */ -static int check_mtime(buf, st) -buf_T *buf; -struct stat *st; +static int check_mtime(buf_T *buf, struct stat *st) { if (buf->b_mtime_read != 0 && time_differs((long)st->st_mtime, buf->b_mtime_read)) { @@ -4249,8 +4235,7 @@ struct stat *st; return OK; } -static int time_differs(t1, t2) -long t1, t2; +static int time_differs(long t1, long t2) { #if defined(__linux__) || defined(MSDOS) || defined(MSWIN) /* On a FAT filesystem, esp. under Linux, there are only 5 bits to store @@ -4268,8 +4253,7 @@ long t1, t2; * * Return FAIL for failure, OK otherwise. */ -static int buf_write_bytes(ip) -struct bw_info *ip; +static int buf_write_bytes(struct bw_info *ip) { int wlen; char_u *buf = ip->bw_buf; /* data to write */ @@ -4479,10 +4463,12 @@ struct bw_info *ip; * Convert a Unicode character to bytes. * Return TRUE for an error, FALSE when it's OK. */ -static int ucs2bytes(c, pp, flags) -unsigned c; /* in: character */ -char_u **pp; /* in/out: pointer to result */ -int flags; /* FIO_ flags */ +static int +ucs2bytes ( + unsigned c, /* in: character */ + char_u **pp, /* in/out: pointer to result */ + int flags /* FIO_ flags */ +) { char_u *p = *pp; int error = FALSE; @@ -4544,8 +4530,7 @@ int flags; /* FIO_ flags */ * Return TRUE if file encoding "fenc" requires conversion from or to * 'encoding'. */ -static int need_conversion(fenc) -char_u *fenc; +static int need_conversion(char_u *fenc) { int same_encoding; int enc_flags; @@ -4577,8 +4562,7 @@ char_u *fenc; * internal conversion. * if "ptr" is an empty string, use 'encoding'. */ -static int get_fio_flags(ptr) -char_u *ptr; +static int get_fio_flags(char_u *ptr) { int prop; @@ -4618,11 +4602,7 @@ char_u *ptr; * Return the name of the encoding and set "*lenp" to the length. * Returns NULL when no BOM found. */ -static char_u * check_for_bom(p, size, lenp, flags) -char_u *p; -long size; -int *lenp; -int flags; +static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags) { char *name = NULL; int len = 2; @@ -4663,9 +4643,7 @@ int flags; * Generate a BOM in "buf[4]" for encoding "name". * Return the length of the BOM (zero when no BOM). */ -static int make_bom(buf, name) -char_u *buf; -char_u *name; +static int make_bom(char_u *buf, char_u *name) { int flags; char_u *p; @@ -4694,8 +4672,7 @@ char_u *name; * directory. * Returns "full_path" or pointer into "full_path" if shortened. */ -char_u * shorten_fname1(full_path) -char_u *full_path; +char_u *shorten_fname1(char_u *full_path) { char_u *dirname; char_u *p = full_path; @@ -4719,9 +4696,7 @@ char_u *full_path; * Returns NULL if not shorter name possible, pointer into "full_path" * otherwise. */ -char_u * shorten_fname(full_path, dir_name) -char_u *full_path; -char_u *dir_name; +char_u *shorten_fname(char_u *full_path, char_u *dir_name) { int len; char_u *p; @@ -4751,8 +4726,7 @@ char_u *dir_name; * For buffers that have buftype "nofile" or "scratch": never change the file * name. */ -void shorten_fnames(force) -int force; +void shorten_fnames(int force) { char_u dirname[MAXPATHL]; buf_T *buf; @@ -4792,9 +4766,7 @@ int force; /* * Shorten all filenames in "fnames[count]" by current directory. */ -void shorten_filenames(fnames, count) -char_u **fnames; -int count; +void shorten_filenames(char_u **fnames, int count) { int i; char_u dirname[MAXPATHL]; @@ -4827,9 +4799,12 @@ int count; * Space for the returned name is allocated, must be freed later. * Returns NULL when out of memory. */ -char_u * modname(fname, ext, prepend_dot) -char_u *fname, *ext; -int prepend_dot; /* may prepend a '.' to file name */ +char_u * +modname ( + char_u *fname, + char_u *ext, + int prepend_dot /* may prepend a '.' to file name */ +) { return buf_modname( #ifdef SHORT_FNAME @@ -4840,10 +4815,13 @@ int prepend_dot; /* may prepend a '.' to file name */ fname, ext, prepend_dot); } -char_u * buf_modname(shortname, fname, ext, prepend_dot) -int shortname; /* use 8.3 file name */ -char_u *fname, *ext; -int prepend_dot; /* may prepend a '.' to file name */ +char_u * +buf_modname ( + int shortname, /* use 8.3 file name */ + char_u *fname, + char_u *ext, + int prepend_dot /* may prepend a '.' to file name */ +) { char_u *retval; char_u *s; @@ -5009,10 +4987,7 @@ int prepend_dot; /* may prepend a '.' to file name */ * Like fgets(), but if the file line is too long, it is truncated and the * rest of the line is thrown away. Returns TRUE for end-of-file. */ -int vim_fgets(buf, size, fp) -char_u *buf; -int size; -FILE *fp; +int vim_fgets(char_u *buf, int size, FILE *fp) { char *eof; #define FGETS_SIZE 200 @@ -5046,10 +5021,7 @@ FILE *fp; * Returns TRUE for end-of-file. * Only used for the Mac, because it's much slower than vim_fgets(). */ -int tag_fgets(buf, size, fp) -char_u *buf; -int size; -FILE *fp; +int tag_fgets(char_u *buf, int size, FILE *fp) { int i = 0; int c; @@ -5085,9 +5057,7 @@ FILE *fp; * function will (attempts to?) copy the file across if rename fails -- webb * Return -1 for failure, 0 for success. */ -int vim_rename(from, to) -char_u *from; -char_u *to; +int vim_rename(char_u *from, char_u *to) { int fd_in; int fd_out; @@ -5255,8 +5225,10 @@ static int already_warned = FALSE; * Returns TRUE if some message was written (screen should be redrawn and * cursor positioned). */ -int check_timestamps(focus) -int focus; /* called for GUI focus event */ +int +check_timestamps ( + int focus /* called for GUI focus event */ +) { buf_T *buf; int didit = 0; @@ -5314,9 +5286,7 @@ int focus; /* called for GUI focus event */ * Return OK or FAIL. When FAIL "tobuf" is incomplete and/or "frombuf" is not * empty. */ -static int move_lines(frombuf, tobuf) -buf_T *frombuf; -buf_T *tobuf; +static int move_lines(buf_T *frombuf, buf_T *tobuf) { buf_T *tbuf = curbuf; int retval = OK; @@ -5358,9 +5328,11 @@ buf_T *tobuf; * return 2 if a message has been displayed. * return 0 otherwise. */ -int buf_check_timestamp(buf, focus) -buf_T *buf; -int focus UNUSED; /* called for GUI focus event */ +int +buf_check_timestamp ( + buf_T *buf, + int focus /* called for GUI focus event */ +) { struct stat st; int stat_res; @@ -5582,9 +5554,7 @@ int focus UNUSED; /* called for GUI focus event */ * "orig_mode" is buf->b_orig_mode before the need for reloading was detected. * buf->b_orig_mode may have been reset already. */ -void buf_reload(buf, orig_mode) -buf_T *buf; -int orig_mode; +void buf_reload(buf_T *buf, int orig_mode) { exarg_T ea; pos_T old_cursor; @@ -5712,10 +5682,7 @@ int orig_mode; /* Careful: autocommands may have made "buf" invalid! */ } -void buf_store_time(buf, st, fname) -buf_T *buf; -struct stat *st; -char_u *fname UNUSED; +void buf_store_time(buf_T *buf, struct stat *st, char_u *fname) { buf->b_mtime = (long)st->st_mtime; buf->b_orig_size = st->st_size; @@ -5730,8 +5697,7 @@ char_u *fname UNUSED; * Adjust the line with missing eol, used for the next write. * Used for do_filter(), when the input lines for the filter are deleted. */ -void write_lnum_adjust(offset) -linenr_T offset; +void write_lnum_adjust(linenr_T offset) { if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */ curbuf->b_no_eol_lnum += offset; @@ -5743,7 +5709,7 @@ static long temp_count = 0; /* Temp filename counter. */ /* * Delete the temp directory and all files it contains. */ -void vim_deltempdir() { +void vim_deltempdir(void) { char_u **files; int file_count; int i; @@ -5772,8 +5738,7 @@ void vim_deltempdir() { * it in "vim_tempdir". This avoids that using ":cd" would confuse us. * "tempdir" must be no longer than MAXPATHL. */ -static void vim_settempdir(tempdir) -char_u *tempdir; +static void vim_settempdir(char_u *tempdir) { char_u *buf; @@ -5796,8 +5761,10 @@ char_u *tempdir; * The returned pointer is to allocated memory. * The returned pointer is NULL if no valid name was found. */ -char_u * vim_tempname(extra_char) -int extra_char UNUSED; /* char to use in the name instead of '?' */ +char_u * +vim_tempname ( + int extra_char /* char to use in the name instead of '?' */ +) { #ifdef USE_TMPNAM char_u itmp[L_tmpnam]; /* use tmpnam() */ @@ -5945,8 +5912,7 @@ int extra_char UNUSED; /* char to use in the name instead of '?' */ /* * Convert all backslashes in fname to forward slashes in-place. */ -void forward_slash(fname) -char_u *fname; +void forward_slash(char_u *fname) { char_u *p; @@ -6183,9 +6149,7 @@ static int autocmd_blocked = 0; /* block all autocmds */ /* * Show the autocommands for one AutoPat. */ -static void show_autocmd(ap, event) -AutoPat *ap; -event_T event; +static void show_autocmd(AutoPat *ap, event_T event) { AutoCmd *ac; @@ -6241,8 +6205,7 @@ event_T event; /* * Mark an autocommand pattern for deletion. */ -static void au_remove_pat(ap) -AutoPat *ap; +static void au_remove_pat(AutoPat *ap) { vim_free(ap->pat); ap->pat = NULL; @@ -6253,8 +6216,7 @@ AutoPat *ap; /* * Mark all commands for a pattern for deletion. */ -static void au_remove_cmds(ap) -AutoPat *ap; +static void au_remove_cmds(AutoPat *ap) { AutoCmd *ac; @@ -6269,7 +6231,7 @@ AutoPat *ap; * Cleanup autocommands and patterns that have been deleted. * This is only done when not executing autocommands. */ -static void au_cleanup() { +static void au_cleanup(void) { AutoPat *ap, **prev_ap; AutoCmd *ac, **prev_ac; event_T event; @@ -6313,8 +6275,7 @@ static void au_cleanup() { * Called when buffer is freed, to remove/invalidate related buffer-local * autocmds. */ -void aubuflocal_remove(buf) -buf_T *buf; +void aubuflocal_remove(buf_T *buf) { AutoPat *ap; event_T event; @@ -6347,8 +6308,7 @@ buf_T *buf; * Add an autocmd group name. * Return it's ID. Returns AUGROUP_ERROR (< 0) for error. */ -static int au_new_group(name) -char_u *name; +static int au_new_group(char_u *name) { int i; @@ -6371,8 +6331,7 @@ char_u *name; return i; } -static void au_del_group(name) -char_u *name; +static void au_del_group(char_u *name) { int i; @@ -6389,8 +6348,7 @@ char_u *name; * Find the ID of an autocmd group name. * Return it's ID. Returns AUGROUP_ERROR (< 0) for error. */ -static int au_find_group(name) -char_u *name; +static int au_find_group(char_u *name) { int i; @@ -6403,8 +6361,7 @@ char_u *name; /* * Return TRUE if augroup "name" exists. */ -int au_has_group(name) -char_u *name; +int au_has_group(char_u *name) { return au_find_group(name) != AUGROUP_ERROR; } @@ -6412,9 +6369,7 @@ char_u *name; /* * ":augroup {name}". */ -void do_augroup(arg, del_group) -char_u *arg; -int del_group; +void do_augroup(char_u *arg, int del_group) { int i; @@ -6443,7 +6398,7 @@ int del_group; } #if defined(EXITFREE) || defined(PROTO) -void free_all_autocmds() { +void free_all_autocmds(void) { for (current_augroup = -1; current_augroup < augroups.ga_len; ++current_augroup) do_autocmd((char_u *)"", TRUE); @@ -6457,9 +6412,7 @@ void free_all_autocmds() { * Return NUM_EVENTS if the event name was not found. * Return a pointer to the next event name in "end". */ -static event_T event_name2nr(start, end) -char_u *start; -char_u **end; +static event_T event_name2nr(char_u *start, char_u **end) { char_u *p; int i; @@ -6484,8 +6437,7 @@ char_u **end; /* * Return the name for event "event". */ -static char_u * event_nr2name(event) -event_T event; +static char_u *event_nr2name(event_T event) { int i; @@ -6498,9 +6450,11 @@ event_T event; /* * Scan over the events. "*" stands for all events. */ -static char_u * find_end_event(arg, have_group) -char_u *arg; -int have_group; /* TRUE when group name was found */ +static char_u * +find_end_event ( + char_u *arg, + int have_group /* TRUE when group name was found */ +) { char_u *pat; char_u *p; @@ -6528,8 +6482,7 @@ int have_group; /* TRUE when group name was found */ /* * Return TRUE if "event" is included in 'eventignore'. */ -static int event_ignored(event) -event_T event; +static int event_ignored(event_T event) { char_u *p = p_ei; @@ -6546,7 +6499,7 @@ event_T event; /* * Return OK when the contents of p_ei is valid, FAIL otherwise. */ -int check_ei() { +int check_ei(void) { char_u *p = p_ei; while (*p) { @@ -6566,8 +6519,7 @@ int check_ei() { * buffer loaded into the window. "what" must start with a comma. * Returns the old value of 'eventignore' in allocated memory. */ -char_u * au_event_disable(what) -char *what; +char_u *au_event_disable(char *what) { char_u *new_ei; char_u *save_ei; @@ -6588,8 +6540,7 @@ char *what; return save_ei; } -void au_event_restore(old_ei) -char_u *old_ei; +void au_event_restore(char_u *old_ei) { if (old_ei != NULL) { set_string_option_direct((char_u *)"ei", -1, old_ei, @@ -6630,9 +6581,7 @@ char_u *old_ei; * * Mostly a {group} argument can optionally appear before . */ -void do_autocmd(arg, forceit) -char_u *arg; -int forceit; +void do_autocmd(char_u *arg, int forceit) { char_u *pat; char_u *envpat = NULL; @@ -6740,8 +6689,7 @@ int forceit; * * Returns the group ID, AUGROUP_ERROR for error (out of memory). */ -static int au_get_grouparg(argp) -char_u **argp; +static int au_get_grouparg(char_u **argp) { char_u *group_name; char_u *p; @@ -6770,13 +6718,7 @@ char_u **argp; * If forceit == TRUE delete entries. * If group is not AUGROUP_ALL, only use this group. */ -static int do_autocmd_event(event, pat, nested, cmd, forceit, group) -event_T event; -char_u *pat; -int nested; -char_u *cmd; -int forceit; -int group; +static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group) { AutoPat *ap; AutoPat **prev_ap; @@ -6991,9 +6933,11 @@ int group; * Implementation of ":doautocmd [group] event [fname]". * Return OK for success, FAIL for failure; */ -int do_doautocmd(arg, do_msg) -char_u *arg; -int do_msg; /* give message for no matching autocmds? */ +int +do_doautocmd ( + char_u *arg, + int do_msg /* give message for no matching autocmds? */ +) { char_u *fname; int nothing_done = TRUE; @@ -7038,8 +6982,7 @@ int do_msg; /* give message for no matching autocmds? */ /* * ":doautoall": execute autocommands for each loaded buffer. */ -void ex_doautoall(eap) -exarg_T *eap; +void ex_doautoall(exarg_T *eap) { int retval; aco_save_T aco; @@ -7086,8 +7029,7 @@ exarg_T *eap; * return TRUE and advance *argp to after it. * Thus return TRUE when do_modelines() should be called. */ -int check_nomodeline(argp) -char_u **argp; +int check_nomodeline(char_u **argp) { if (STRNCMP(*argp, "", 12) == 0) { *argp = skipwhite(*argp + 12); @@ -7103,9 +7045,11 @@ char_u **argp; * Set "curbuf" and "curwin" to match "buf". * When FEAT_AUTOCMD is not defined another version is used, see below. */ -void aucmd_prepbuf(aco, buf) -aco_save_T *aco; /* structure to save values in */ -buf_T *buf; /* new curbuf */ +void +aucmd_prepbuf ( + aco_save_T *aco, /* structure to save values in */ + buf_T *buf /* new curbuf */ +) { win_T *win; int save_ea; @@ -7187,8 +7131,10 @@ buf_T *buf; /* new curbuf */ * Restore the window as it was (if possible). * When FEAT_AUTOCMD is not defined another version is used, see below. */ -void aucmd_restbuf(aco) -aco_save_T *aco; /* structure holding saved values */ +void +aucmd_restbuf ( + aco_save_T *aco /* structure holding saved values */ +) { int dummy; @@ -7270,12 +7216,14 @@ static int autocmd_nested = FALSE; * Execute autocommands for "event" and file name "fname". * Return TRUE if some commands were executed. */ -int apply_autocmds(event, fname, fname_io, force, buf) -event_T event; -char_u *fname; /* NULL or empty means use actual file name */ -char_u *fname_io; /* fname to use for on cmdline */ -int force; /* when TRUE, ignore autocmd_busy */ -buf_T *buf; /* buffer for */ +int +apply_autocmds ( + event_T event, + char_u *fname, /* NULL or empty means use actual file name */ + char_u *fname_io, /* fname to use for on cmdline */ + int force, /* when TRUE, ignore autocmd_busy */ + buf_T *buf /* buffer for */ +) { return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL); @@ -7285,13 +7233,7 @@ buf_T *buf; /* buffer for */ * Like apply_autocmds(), but with extra "eap" argument. This takes care of * setting v:filearg. */ -static int apply_autocmds_exarg(event, fname, fname_io, force, buf, eap) -event_T event; -char_u *fname; -char_u *fname_io; -int force; -buf_T *buf; -exarg_T *eap; +static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap) { return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, eap); @@ -7303,13 +7245,15 @@ exarg_T *eap; * conditional, no autocommands are executed. If otherwise the autocommands * cause the script to be aborted, retval is set to FAIL. */ -int apply_autocmds_retval(event, fname, fname_io, force, buf, retval) -event_T event; -char_u *fname; /* NULL or empty means use actual file name */ -char_u *fname_io; /* fname to use for on cmdline */ -int force; /* when TRUE, ignore autocmd_busy */ -buf_T *buf; /* buffer for */ -int *retval; /* pointer to caller's retval */ +int +apply_autocmds_retval ( + event_T event, + char_u *fname, /* NULL or empty means use actual file name */ + char_u *fname_io, /* fname to use for on cmdline */ + int force, /* when TRUE, ignore autocmd_busy */ + buf_T *buf, /* buffer for */ + int *retval /* pointer to caller's retval */ +) { int did_cmd; @@ -7328,7 +7272,7 @@ int *retval; /* pointer to caller's retval */ /* * Return TRUE when there is a CursorHold autocommand defined. */ -int has_cursorhold() { +int has_cursorhold(void) { return first_autopat[(int)(get_real_state() == NORMAL_BUSY ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL; } @@ -7336,7 +7280,7 @@ int has_cursorhold() { /* * Return TRUE if the CursorHold event can be triggered. */ -int trigger_cursorhold() { +int trigger_cursorhold(void) { int state; if (!did_cursorhold @@ -7355,47 +7299,49 @@ int trigger_cursorhold() { /* * Return TRUE when there is a CursorMoved autocommand defined. */ -int has_cursormoved() { +int has_cursormoved(void) { return first_autopat[(int)EVENT_CURSORMOVED] != NULL; } /* * Return TRUE when there is a CursorMovedI autocommand defined. */ -int has_cursormovedI() { +int has_cursormovedI(void) { return first_autopat[(int)EVENT_CURSORMOVEDI] != NULL; } /* * Return TRUE when there is a TextChanged autocommand defined. */ -int has_textchanged() { +int has_textchanged(void) { return first_autopat[(int)EVENT_TEXTCHANGED] != NULL; } /* * Return TRUE when there is a TextChangedI autocommand defined. */ -int has_textchangedI() { +int has_textchangedI(void) { return first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL; } /* * Return TRUE when there is an InsertCharPre autocommand defined. */ -int has_insertcharpre() { +int has_insertcharpre(void) { return first_autopat[(int)EVENT_INSERTCHARPRE] != NULL; } -static int apply_autocmds_group(event, fname, fname_io, force, group, buf, eap) -event_T event; -char_u *fname; /* NULL or empty means use actual file name */ -char_u *fname_io; /* fname to use for on cmdline, NULL means +static int +apply_autocmds_group ( + event_T event, + char_u *fname, /* NULL or empty means use actual file name */ + char_u *fname_io, /* fname to use for on cmdline, NULL means use fname */ -int force; /* when TRUE, ignore autocmd_busy */ -int group; /* group ID, or AUGROUP_ALL */ -buf_T *buf; /* buffer for */ -exarg_T *eap; /* command arguments */ + int force, /* when TRUE, ignore autocmd_busy */ + int group, /* group ID, or AUGROUP_ALL */ + buf_T *buf, /* buffer for */ + exarg_T *eap /* command arguments */ +) { char_u *sfname = NULL; /* short file name */ char_u *tail; @@ -7716,14 +7662,14 @@ static char_u *old_termresponse = NULL; * Block triggering autocommands until unblock_autocmd() is called. * Can be used recursively, so long as it's symmetric. */ -void block_autocmds() { +void block_autocmds(void) { /* Remember the value of v:termresponse. */ if (autocmd_blocked == 0) old_termresponse = get_vim_var_str(VV_TERMRESPONSE); ++autocmd_blocked; } -void unblock_autocmds() { +void unblock_autocmds(void) { --autocmd_blocked; /* When v:termresponse was set while autocommands were blocked, trigger @@ -7734,16 +7680,18 @@ void unblock_autocmds() { apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); } -int is_autocmd_blocked() { +int is_autocmd_blocked(void) { return autocmd_blocked != 0; } /* * Find next autocommand pattern that matches. */ -static void auto_next_pat(apc, stop_at_last) -AutoPatCmd *apc; -int stop_at_last; /* stop when 'last' flag is set */ +static void +auto_next_pat ( + AutoPatCmd *apc, + int stop_at_last /* stop when 'last' flag is set */ +) { AutoPat *ap; AutoCmd *cp; @@ -7801,10 +7749,7 @@ int stop_at_last; /* stop when 'last' flag is set */ * Called by do_cmdline() to get the next line for ":if". * Returns allocated string, or NULL for end of autocommands. */ -char_u * getnextac(c, cookie, indent) -int c UNUSED; -void *cookie; -int indent UNUSED; +char_u *getnextac(int c, void *cookie, int indent) { AutoPatCmd *acp = (AutoPatCmd *)cookie; char_u *retval; @@ -7860,10 +7805,7 @@ int indent UNUSED; * To account for buffer-local autocommands, function needs to know * in which buffer the file will be opened. */ -int has_autocmd(event, sfname, buf) -event_T event; -char_u *sfname; -buf_T *buf; +int has_autocmd(event_T event, char_u *sfname, buf_T *buf) { AutoPat *ap; char_u *fname; @@ -7908,9 +7850,7 @@ buf_T *buf; * Function given to ExpandGeneric() to obtain the list of autocommand group * names. */ -char_u * get_augroup_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_augroup_name(expand_T *xp, int idx) { if (idx == augroups.ga_len) /* add "END" add the end */ return (char_u *)"END"; @@ -7923,10 +7863,12 @@ int idx; static int include_groups = FALSE; -char_u * set_context_in_autocmd(xp, arg, doautocmd) -expand_T *xp; -char_u *arg; -int doautocmd; /* TRUE for :doauto*, FALSE for :autocmd */ +char_u * +set_context_in_autocmd ( + expand_T *xp, + char_u *arg, + int doautocmd /* TRUE for :doauto*, FALSE for :autocmd */ +) { char_u *p; int group; @@ -7972,9 +7914,7 @@ int doautocmd; /* TRUE for :doauto*, FALSE for :autocmd */ /* * Function given to ExpandGeneric() to obtain the list of event names. */ -char_u * get_event_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_event_name(expand_T *xp, int idx) { if (idx < augroups.ga_len) { /* First list group names, if wanted */ if (!include_groups || AUGROUP_NAME(idx) == NULL) @@ -7988,8 +7928,7 @@ int idx; /* * Return TRUE if autocmd is supported. */ -int autocmd_supported(name) -char_u *name; +int autocmd_supported(char_u *name) { char_u *p; @@ -8008,8 +7947,7 @@ char_u *name; * exists("#Event") or * exists("#Event#pat") */ -int au_exists(arg) -char_u *arg; +int au_exists(char_u *arg) { char_u *arg_save; char_u *pattern = NULL; @@ -8098,13 +8036,15 @@ theend: * Used for autocommands and 'wildignore'. * Returns TRUE if there is a match, FALSE otherwise. */ -int match_file_pat(pattern, prog, fname, sfname, tail, allow_dirs) -char_u *pattern; /* pattern to match with */ -regprog_T *prog; /* pre-compiled regprog or NULL */ -char_u *fname; /* full path of file name */ -char_u *sfname; /* short file name or NULL */ -char_u *tail; /* tail of path */ -int allow_dirs; /* allow matching with dir */ +int +match_file_pat ( + char_u *pattern, /* pattern to match with */ + regprog_T *prog, /* pre-compiled regprog or NULL */ + char_u *fname, /* full path of file name */ + char_u *sfname, /* short file name or NULL */ + char_u *tail, /* tail of path */ + int allow_dirs /* allow matching with dir */ +) { regmatch_T regmatch; int result = FALSE; @@ -8185,10 +8125,7 @@ int allow_dirs; /* allow matching with dir */ * "list" is a comma-separated list of patterns, like 'wildignore'. * "sfname" is the short file name or NULL, "ffname" the long file name. */ -int match_file_list(list, sfname, ffname) -char_u *list; -char_u *sfname; -char_u *ffname; +int match_file_list(char_u *list, char_u *sfname, char_u *ffname) { char_u buf[100]; char_u *tail; @@ -8227,11 +8164,13 @@ char_u *ffname; * * Returns NULL when out of memory. */ -char_u * file_pat_to_reg_pat(pat, pat_end, allow_dirs, no_bslash) -char_u *pat; -char_u *pat_end; /* first char after pattern or NULL */ -char *allow_dirs; /* Result passed back out in here */ -int no_bslash UNUSED; /* Don't use a backward slash as pathsep */ +char_u * +file_pat_to_reg_pat ( + char_u *pat, + char_u *pat_end, /* first char after pattern or NULL */ + char *allow_dirs, /* Result passed back out in here */ + int no_bslash /* Don't use a backward slash as pathsep */ +) { int size; char_u *endp; diff --git a/src/fold.c b/src/fold.c index b3a3d84a2b..7a967d8be0 100644 --- a/src/fold.c +++ b/src/fold.c @@ -104,9 +104,7 @@ static int foldendmarkerlen; /* * Copy that folding state from window "wp_from" to window "wp_to". */ -void copyFoldingState(wp_from, wp_to) -win_T *wp_from; -win_T *wp_to; +void copyFoldingState(win_T *wp_from, win_T *wp_to) { wp_to->w_fold_manual = wp_from->w_fold_manual; wp_to->w_foldinvalid = wp_from->w_foldinvalid; @@ -117,8 +115,7 @@ win_T *wp_to; /* * Return TRUE if there may be folded lines in the current window. */ -int hasAnyFolding(win) -win_T *win; +int hasAnyFolding(win_T *win) { /* very simple now, but can become more complex later */ return win->w_p_fen @@ -132,22 +129,21 @@ win_T *win; * When returning TRUE, *firstp and *lastp are set to the first and last * lnum of the sequence of folded lines (skipped when NULL). */ -int hasFolding(lnum, firstp, lastp) -linenr_T lnum; -linenr_T *firstp; -linenr_T *lastp; +int hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp) { return hasFoldingWin(curwin, lnum, firstp, lastp, TRUE, NULL); } /* hasFoldingWin() {{{2 */ -int hasFoldingWin(win, lnum, firstp, lastp, cache, infop) -win_T *win; -linenr_T lnum; -linenr_T *firstp; -linenr_T *lastp; -int cache; /* when TRUE: use cached values of window */ -foldinfo_T *infop; /* where to store fold info */ +int +hasFoldingWin ( + win_T *win, + linenr_T lnum, + linenr_T *firstp, + linenr_T *lastp, + int cache, /* when TRUE: use cached values of window */ + foldinfo_T *infop /* where to store fold info */ +) { int had_folded = FALSE; linenr_T first = 0; @@ -242,8 +238,7 @@ foldinfo_T *infop; /* where to store fold info */ /* * Return fold level at line number "lnum" in the current window. */ -int foldLevel(lnum) -linenr_T lnum; +int foldLevel(linenr_T lnum) { /* While updating the folds lines between invalid_top and invalid_bot have * an undefined fold level. Otherwise update the folds first. */ @@ -268,9 +263,7 @@ linenr_T lnum; * Return FALSE if line is not folded. * Return MAYBE if the line is folded when next to a folded line. */ -int lineFolded(win, lnum) -win_T *win; -linenr_T lnum; +int lineFolded(win_T *win, linenr_T lnum) { return foldedCount(win, lnum, NULL) != 0; } @@ -284,10 +277,7 @@ linenr_T lnum; * Returns number of folded lines from "lnum", or 0 if line is not folded. * When "infop" is not NULL, fills *infop with the fold level info. */ -long foldedCount(win, lnum, infop) -win_T *win; -linenr_T lnum; -foldinfo_T *infop; +long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop) { linenr_T last; @@ -300,8 +290,7 @@ foldinfo_T *infop; /* * Return TRUE if 'foldmethod' is "manual" */ -int foldmethodIsManual(wp) -win_T *wp; +int foldmethodIsManual(win_T *wp) { return wp->w_p_fdm[3] == 'u'; } @@ -310,8 +299,7 @@ win_T *wp; /* * Return TRUE if 'foldmethod' is "indent" */ -int foldmethodIsIndent(wp) -win_T *wp; +int foldmethodIsIndent(win_T *wp) { return wp->w_p_fdm[0] == 'i'; } @@ -320,8 +308,7 @@ win_T *wp; /* * Return TRUE if 'foldmethod' is "expr" */ -int foldmethodIsExpr(wp) -win_T *wp; +int foldmethodIsExpr(win_T *wp) { return wp->w_p_fdm[1] == 'x'; } @@ -330,8 +317,7 @@ win_T *wp; /* * Return TRUE if 'foldmethod' is "marker" */ -int foldmethodIsMarker(wp) -win_T *wp; +int foldmethodIsMarker(win_T *wp) { return wp->w_p_fdm[2] == 'r'; } @@ -340,8 +326,7 @@ win_T *wp; /* * Return TRUE if 'foldmethod' is "syntax" */ -int foldmethodIsSyntax(wp) -win_T *wp; +int foldmethodIsSyntax(win_T *wp) { return wp->w_p_fdm[0] == 's'; } @@ -350,8 +335,7 @@ win_T *wp; /* * Return TRUE if 'foldmethod' is "diff" */ -int foldmethodIsDiff(wp) -win_T *wp; +int foldmethodIsDiff(win_T *wp) { return wp->w_p_fdm[0] == 'd'; } @@ -361,9 +345,7 @@ win_T *wp; * Close fold for current window at line "lnum". * Repeat "count" times. */ -void closeFold(lnum, count) -linenr_T lnum; -long count; +void closeFold(linenr_T lnum, long count) { setFoldRepeat(lnum, count, FALSE); } @@ -372,8 +354,7 @@ long count; /* * Close fold for current window at line "lnum" recursively. */ -void closeFoldRecurse(lnum) -linenr_T lnum; +void closeFoldRecurse(linenr_T lnum) { (void)setManualFold(lnum, FALSE, TRUE, NULL); } @@ -383,12 +364,14 @@ linenr_T lnum; * Open or Close folds for current window in lines "first" to "last". * Used for "zo", "zO", "zc" and "zC" in Visual mode. */ -void opFoldRange(first, last, opening, recurse, had_visual) -linenr_T first; -linenr_T last; -int opening; /* TRUE to open, FALSE to close */ -int recurse; /* TRUE to do it recursively */ -int had_visual; /* TRUE when Visual selection used */ +void +opFoldRange ( + linenr_T first, + linenr_T last, + int opening, /* TRUE to open, FALSE to close */ + int recurse, /* TRUE to do it recursively */ + int had_visual /* TRUE when Visual selection used */ +) { int done = DONE_NOTHING; /* avoid error messages */ linenr_T lnum; @@ -418,9 +401,7 @@ int had_visual; /* TRUE when Visual selection used */ * Open fold for current window at line "lnum". * Repeat "count" times. */ -void openFold(lnum, count) -linenr_T lnum; -long count; +void openFold(linenr_T lnum, long count) { setFoldRepeat(lnum, count, TRUE); } @@ -429,8 +410,7 @@ long count; /* * Open fold for current window at line "lnum" recursively. */ -void openFoldRecurse(lnum) -linenr_T lnum; +void openFoldRecurse(linenr_T lnum) { (void)setManualFold(lnum, TRUE, TRUE, NULL); } @@ -439,7 +419,7 @@ linenr_T lnum; /* * Open folds until the cursor line is not in a closed fold. */ -void foldOpenCursor() { +void foldOpenCursor(void) { int done; checkupdate(curwin); @@ -456,7 +436,7 @@ void foldOpenCursor() { /* * Set new foldlevel for current window. */ -void newFoldLevel() { +void newFoldLevel(void) { newFoldLevelWin(curwin); if (foldmethodIsDiff(curwin) && curwin->w_p_scb) { @@ -475,8 +455,7 @@ void newFoldLevel() { } } -static void newFoldLevelWin(wp) -win_T *wp; +static void newFoldLevelWin(win_T *wp) { fold_T *fp; int i; @@ -498,7 +477,7 @@ win_T *wp; /* * Apply 'foldlevel' to all folds that don't contain the cursor. */ -void foldCheckClose() { +void foldCheckClose(void) { if (*p_fcl != NUL) { /* can only be "all" right now */ checkupdate(curwin); if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum, @@ -508,10 +487,7 @@ void foldCheckClose() { } /* checkCloseRec() {{{2 */ -static int checkCloseRec(gap, lnum, level) -garray_T *gap; -linenr_T lnum; -int level; +static int checkCloseRec(garray_T *gap, linenr_T lnum, int level) { fold_T *fp; int retval = FALSE; @@ -538,8 +514,7 @@ int level; * Return TRUE if it's allowed to manually create or delete a fold. * Give an error message and return FALSE if not. */ -int foldManualAllowed(create) -int create; +int foldManualAllowed(int create) { if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin)) return TRUE; @@ -555,9 +530,7 @@ int create; * Create a fold from line "start" to line "end" (inclusive) in the current * window. */ -void foldCreate(start, end) -linenr_T start; -linenr_T end; +void foldCreate(linenr_T start, linenr_T end) { fold_T *fp; garray_T *gap; @@ -671,11 +644,13 @@ linenr_T end; * When "end" is not 0, delete all folds from "start" to "end". * When "recursive" is TRUE delete recursively. */ -void deleteFold(start, end, recursive, had_visual) -linenr_T start; -linenr_T end; -int recursive; -int had_visual; /* TRUE when Visual selection used */ +void +deleteFold ( + linenr_T start, + linenr_T end, + int recursive, + int had_visual /* TRUE when Visual selection used */ +) { garray_T *gap; fold_T *fp; @@ -757,8 +732,7 @@ int had_visual; /* TRUE when Visual selection used */ /* * Remove all folding for window "win". */ -void clearFolding(win) -win_T *win; +void clearFolding(win_T *win) { deleteFoldRecurse(&win->w_folds); win->w_foldinvalid = FALSE; @@ -771,10 +745,7 @@ win_T *win; * calling foldMarkAdjust(). * The changes in lines from top to bot (inclusive). */ -void foldUpdate(wp, top, bot) -win_T *wp; -linenr_T top; -linenr_T bot; +void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) { fold_T *fp; @@ -807,8 +778,7 @@ linenr_T bot; * The actual updating is postponed until fold info is used, to avoid doing * every time a setting is changed or a syntax item is added. */ -void foldUpdateAll(win) -win_T *win; +void foldUpdateAll(win_T *win) { win->w_foldinvalid = TRUE; redraw_win_later(win, NOT_VALID); @@ -820,10 +790,12 @@ win_T *win; * If "updown" is TRUE: move to fold at the same level. * If not moved return FAIL. */ -int foldMoveTo(updown, dir, count) -int updown; -int dir; /* FORWARD or BACKWARD */ -long count; +int +foldMoveTo ( + int updown, + int dir, /* FORWARD or BACKWARD */ + long count +) { long n; int retval = FAIL; @@ -936,8 +908,7 @@ long count; /* * Init the fold info in a new window. */ -void foldInitWin(new_win) -win_T *new_win; +void foldInitWin(win_T *new_win) { ga_init2(&new_win->w_folds, (int)sizeof(fold_T), 10); } @@ -949,9 +920,7 @@ win_T *new_win; * line number can be wrong). * Returns index of entry or -1 if not found. */ -int find_wl_entry(win, lnum) -win_T *win; -linenr_T lnum; +int find_wl_entry(win_T *win, linenr_T lnum) { int i; @@ -969,7 +938,7 @@ linenr_T lnum; /* * Adjust the Visual area to include any fold at the start or end completely. */ -void foldAdjustVisual() { +void foldAdjustVisual(void) { pos_T *start, *end; char_u *ptr; @@ -1000,7 +969,7 @@ void foldAdjustVisual() { /* * Move the cursor to the first line of a closed fold. */ -void foldAdjustCursor() { +void foldAdjustCursor(void) { (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); } @@ -1011,9 +980,7 @@ void foldAdjustCursor() { * * Return FAIL if the operation cannot be completed, otherwise OK. */ -void cloneFoldGrowArray(from, to) -garray_T *from; -garray_T *to; +void cloneFoldGrowArray(garray_T *from, garray_T *to) { int i; fold_T *from_p; @@ -1045,10 +1012,7 @@ garray_T *to; * the first fold below it (careful: it can be beyond the end of the array!). * Returns FALSE when there is no fold that contains "lnum". */ -static int foldFind(gap, lnum, fpp) -garray_T *gap; -linenr_T lnum; -fold_T **fpp; +static int foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp) { linenr_T low, high; fold_T *fp; @@ -1084,9 +1048,7 @@ fold_T **fpp; /* * Return fold level at line number "lnum" in window "wp". */ -static int foldLevelWin(wp, lnum) -win_T *wp; -linenr_T lnum; +static int foldLevelWin(win_T *wp, linenr_T lnum) { fold_T *fp; linenr_T lnum_rel = lnum; @@ -1111,8 +1073,7 @@ linenr_T lnum; /* * Check if the folds in window "wp" are invalid and update them if needed. */ -static void checkupdate(wp) -win_T *wp; +static void checkupdate(win_T *wp) { if (wp->w_foldinvalid) { foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); /* will update all */ @@ -1125,10 +1086,7 @@ win_T *wp; * Open or close fold for current window at line "lnum". * Repeat "count" times. */ -static void setFoldRepeat(lnum, count, do_open) -linenr_T lnum; -long count; -int do_open; +static void setFoldRepeat(linenr_T lnum, long count, int do_open) { int done; long n; @@ -1150,11 +1108,13 @@ int do_open; * Open or close the fold in the current window which contains "lnum". * Also does this for other windows in diff mode when needed. */ -static linenr_T setManualFold(lnum, opening, recurse, donep) -linenr_T lnum; -int opening; /* TRUE when opening, FALSE when closing */ -int recurse; /* TRUE when closing/opening recursive */ -int *donep; +static linenr_T +setManualFold ( + linenr_T lnum, + int opening, /* TRUE when opening, FALSE when closing */ + int recurse, /* TRUE when closing/opening recursive */ + int *donep +) { if (foldmethodIsDiff(curwin) && curwin->w_p_scb) { win_T *wp; @@ -1187,12 +1147,14 @@ int *donep; * Return the line number of the next line that could be closed. * It's only valid when "opening" is TRUE! */ -static linenr_T setManualFoldWin(wp, lnum, opening, recurse, donep) -win_T *wp; -linenr_T lnum; -int opening; /* TRUE when opening, FALSE when closing */ -int recurse; /* TRUE when closing/opening recursive */ -int *donep; +static linenr_T +setManualFoldWin ( + win_T *wp, + linenr_T lnum, + int opening, /* TRUE when opening, FALSE when closing */ + int recurse, /* TRUE when closing/opening recursive */ + int *donep +) { fold_T *fp; fold_T *fp2; @@ -1286,8 +1248,7 @@ int *donep; /* * Open all nested folds in fold "fpr" recursively. */ -static void foldOpenNested(fpr) -fold_T *fpr; +static void foldOpenNested(fold_T *fpr) { int i; fold_T *fp; @@ -1305,10 +1266,7 @@ fold_T *fpr; * When "recursive" is TRUE also delete all the folds contained in it. * When "recursive" is FALSE contained folds are moved one level up. */ -static void deleteFoldEntry(gap, idx, recursive) -garray_T *gap; -int idx; -int recursive; +static void deleteFoldEntry(garray_T *gap, int idx, int recursive) { fold_T *fp; int i; @@ -1356,8 +1314,7 @@ int recursive; /* * Delete nested folds in a fold. */ -void deleteFoldRecurse(gap) -garray_T *gap; +void deleteFoldRecurse(garray_T *gap) { int i; @@ -1370,12 +1327,7 @@ garray_T *gap; /* * Update line numbers of folds for inserted/deleted lines. */ -void foldMarkAdjust(wp, line1, line2, amount, amount_after) -win_T *wp; -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after) { /* If deleting marks from line1 to line2, but not deleting all those * lines, set line2 so that only deleted lines have their folds removed. */ @@ -1389,12 +1341,7 @@ long amount_after; } /* foldMarkAdjustRecurse() {{{2 */ -static void foldMarkAdjustRecurse(gap, line1, line2, amount, amount_after) -garray_T *gap; -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, long amount, long amount_after) { fold_T *fp; int i; @@ -1487,13 +1434,12 @@ long amount_after; * Get the lowest 'foldlevel' value that makes the deepest nested fold in the * current window open. */ -int getDeepestNesting() { +int getDeepestNesting(void) { checkupdate(curwin); return getDeepestNestingRecurse(&curwin->w_folds); } -static int getDeepestNestingRecurse(gap) -garray_T *gap; +static int getDeepestNestingRecurse(garray_T *gap) { int i; int level; @@ -1514,13 +1460,15 @@ garray_T *gap; /* * Check if a fold is closed and update the info needed to check nested folds. */ -static int check_closed(win, fp, use_levelp, level, maybe_smallp, lnum_off) -win_T *win; -fold_T *fp; -int *use_levelp; /* TRUE: outer fold had FD_LEVEL */ -int level; /* folding depth */ -int *maybe_smallp; /* TRUE: outer this had fd_small == MAYBE */ -linenr_T lnum_off; /* line number offset for fp->fd_top */ +static int +check_closed ( + win_T *win, + fold_T *fp, + int *use_levelp, /* TRUE: outer fold had FD_LEVEL */ + int level, /* folding depth */ + int *maybe_smallp, /* TRUE: outer this had fd_small == MAYBE */ + linenr_T lnum_off /* line number offset for fp->fd_top */ +) { int closed = FALSE; @@ -1550,10 +1498,12 @@ linenr_T lnum_off; /* line number offset for fp->fd_top */ /* * Update fd_small field of fold "fp". */ -static void checkSmall(wp, fp, lnum_off) -win_T *wp; -fold_T *fp; -linenr_T lnum_off; /* offset for fp->fd_top */ +static void +checkSmall ( + win_T *wp, + fold_T *fp, + linenr_T lnum_off /* offset for fp->fd_top */ +) { int count; int n; @@ -1582,8 +1532,7 @@ linenr_T lnum_off; /* offset for fp->fd_top */ /* * Set small flags in "gap" to MAYBE. */ -static void setSmallMaybe(gap) -garray_T *gap; +static void setSmallMaybe(garray_T *gap) { int i; fold_T *fp; @@ -1598,9 +1547,7 @@ garray_T *gap; * Create a fold from line "start" to line "end" (inclusive) in the current * window by adding markers. */ -static void foldCreateMarkers(start, end) -linenr_T start; -linenr_T end; +static void foldCreateMarkers(linenr_T start, linenr_T end) { if (!curbuf->b_p_ma) { EMSG(_(e_modifiable)); @@ -1620,10 +1567,7 @@ linenr_T end; /* * Add "marker[markerlen]" in 'commentstring' to line "lnum". */ -static void foldAddMarker(lnum, marker, markerlen) -linenr_T lnum; -char_u *marker; -int markerlen; +static void foldAddMarker(linenr_T lnum, char_u *marker, int markerlen) { char_u *cms = curbuf->b_p_cms; char_u *line; @@ -1656,10 +1600,12 @@ int markerlen; /* * Delete the markers for a fold, causing it to be deleted. */ -static void deleteFoldMarkers(fp, recursive, lnum_off) -fold_T *fp; -int recursive; -linenr_T lnum_off; /* offset for fp->fd_top */ +static void +deleteFoldMarkers ( + fold_T *fp, + int recursive, + linenr_T lnum_off /* offset for fp->fd_top */ +) { int i; @@ -1679,10 +1625,7 @@ linenr_T lnum_off; /* offset for fp->fd_top */ * If the marker is not found, there is no error message. Could a missing * close-marker. */ -static void foldDelMarker(lnum, marker, markerlen) -linenr_T lnum; -char_u *marker; -int markerlen; +static void foldDelMarker(linenr_T lnum, char_u *marker, int markerlen) { char_u *line; char_u *newline; @@ -1727,11 +1670,7 @@ int markerlen; * When 'foldtext' isn't set puts the result in "buf[51]". Otherwise the * result is in allocated memory. */ -char_u * get_foldtext(wp, lnum, lnume, foldinfo, buf) -win_T *wp; -linenr_T lnum, lnume; -foldinfo_T *foldinfo; -char_u *buf; +char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T *foldinfo, char_u *buf) { char_u *text = NULL; /* an error occurred when evaluating 'fdt' setting */ @@ -1827,8 +1766,7 @@ char_u *buf; /* * Remove 'foldmarker' and 'commentstring' from "str" (in-place). */ -void foldtext_cleanup(str) -char_u *str; +void foldtext_cleanup(char_u *str) { char_u *cms_start; /* first part or the whole comment */ int cms_slen = 0; /* length of cms_start */ @@ -1943,10 +1881,7 @@ static void foldlevelSyntax __ARGS((fline_T *flp)); * Update the folding for window "wp", at least from lines "top" to "bot". * Return TRUE if any folds did change. */ -static void foldUpdateIEMS(wp, top, bot) -win_T *wp; -linenr_T top; -linenr_T bot; +static void foldUpdateIEMS(win_T *wp, linenr_T top, linenr_T bot) { linenr_T start; linenr_T end; @@ -2550,9 +2485,7 @@ int topflags; /* flags used by containing fold */ * Insert a new fold in "gap" at position "i". * Returns OK for success, FAIL for failure. */ -static int foldInsert(gap, i) -garray_T *gap; -int i; +static int foldInsert(garray_T *gap, int i) { fold_T *fp; @@ -2574,11 +2507,7 @@ int i; * The caller must first have taken care of any nested folds from "top" to * "bot"! */ -static void foldSplit(gap, i, top, bot) -garray_T *gap; -int i; -linenr_T top; -linenr_T bot; +static void foldSplit(garray_T *gap, int i, linenr_T top, linenr_T bot) { fold_T *fp; fold_T *fp2; @@ -2635,10 +2564,7 @@ linenr_T bot; * 5: made to start below "bot". * 6: not changed */ -static void foldRemove(gap, top, bot) -garray_T *gap; -linenr_T top; -linenr_T bot; +static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot) { fold_T *fp = NULL; @@ -2692,10 +2618,7 @@ linenr_T bot; * The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1". * Fold entry "fp2" in "gap" is deleted. */ -static void foldMerge(fp1, gap, fp2) -fold_T *fp1; -garray_T *gap; -fold_T *fp2; +static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2) { fold_T *fp3; fold_T *fp4; @@ -2730,8 +2653,7 @@ fold_T *fp2; * Doesn't use any caching. * Returns a level of -1 if the foldlevel depends on surrounding lines. */ -static void foldlevelIndent(flp) -fline_T *flp; +static void foldlevelIndent(fline_T *flp) { char_u *s; buf_T *buf; @@ -2762,8 +2684,7 @@ fline_T *flp; * Low level function to get the foldlevel for the "diff" method. * Doesn't use any caching. */ -static void foldlevelDiff(flp) -fline_T *flp; +static void foldlevelDiff(fline_T *flp) { if (diff_infold(flp->wp, flp->lnum + flp->off)) flp->lvl = 1; @@ -2777,8 +2698,7 @@ fline_T *flp; * Doesn't use any caching. * Returns a level of -1 if the foldlevel depends on surrounding lines. */ -static void foldlevelExpr(flp) -fline_T *flp; +static void foldlevelExpr(fline_T *flp) { win_T *win; int n; @@ -2869,8 +2789,7 @@ fline_T *flp; * "foldendmarkerlen". * Relies on the option value to have been checked for correctness already. */ -static void parseMarker(wp) -win_T *wp; +static void parseMarker(win_T *wp) { foldendmarker = vim_strchr(wp->w_p_fmr, ','); foldstartmarkerlen = (int)(foldendmarker++ - wp->w_p_fmr); @@ -2887,8 +2806,7 @@ win_T *wp; * Doesn't use any caching. * Sets flp->start when a start marker was found. */ -static void foldlevelMarker(flp) -fline_T *flp; +static void foldlevelMarker(fline_T *flp) { char_u *startmarker; int cstart; @@ -2958,8 +2876,7 @@ fline_T *flp; * Low level function to get the foldlevel for the "syntax" method. * Doesn't use any caching. */ -static void foldlevelSyntax(flp) -fline_T *flp; +static void foldlevelSyntax(fline_T *flp) { linenr_T lnum = flp->lnum + flp->off; int n; @@ -2987,9 +2904,7 @@ static int put_fold_open_close __ARGS((FILE *fd, fold_T *fp, linenr_T off)); * Write commands to "fd" to restore the manual folds in window "wp". * Return FAIL if writing fails. */ -int put_folds(fd, wp) -FILE *fd; -win_T *wp; +int put_folds(FILE *fd, win_T *wp) { if (foldmethodIsManual(wp)) { if (put_line(fd, "silent! normal! zE") == FAIL @@ -3009,10 +2924,7 @@ win_T *wp; * Write commands to "fd" to recreate manually created folds. * Returns FAIL when writing failed. */ -static int put_folds_recurse(fd, gap, off) -FILE *fd; -garray_T *gap; -linenr_T off; +static int put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off) { int i; fold_T *fp; @@ -3036,11 +2948,7 @@ linenr_T off; * Write commands to "fd" to open and close manually opened/closed folds. * Returns FAIL when writing failed. */ -static int put_foldopen_recurse(fd, wp, gap, off) -FILE *fd; -win_T *wp; -garray_T *gap; -linenr_T off; +static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off) { int i; int level; @@ -3086,10 +2994,7 @@ linenr_T off; * Write the open or close command to "fd". * Returns FAIL when writing failed. */ -static int put_fold_open_close(fd, fp, off) -FILE *fd; -fold_T *fp; -linenr_T off; +static int put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off) { if (fprintf(fd, "%ld", fp->fd_top + off) < 0 || put_eol(fd) == FAIL diff --git a/src/getchar.c b/src/getchar.c index 92e1ece639..91779b348a 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -134,8 +134,7 @@ static char_u *eval_map_expr __ARGS((char_u *str, int c)); /* * Free and clear a buffer. */ -void free_buff(buf) -struct buffheader *buf; +void free_buff(struct buffheader *buf) { struct buffblock *p, *np; @@ -150,9 +149,11 @@ struct buffheader *buf; * Return the contents of a buffer as a single string. * K_SPECIAL and CSI in the returned string are escaped. */ -static char_u * get_buffcont(buffer, dozero) -struct buffheader *buffer; -int dozero; /* count == zero is not an error */ +static char_u * +get_buffcont ( + struct buffheader *buffer, + int dozero /* count == zero is not an error */ +) { long_u count = 0; char_u *p = NULL; @@ -179,7 +180,7 @@ int dozero; /* count == zero is not an error */ * and clear the record buffer. * K_SPECIAL and CSI in the returned string are escaped. */ -char_u * get_recorded() { +char_u *get_recorded(void) { char_u *p; size_t len; @@ -210,7 +211,7 @@ char_u * get_recorded() { * Return the contents of the redo buffer as a single string. * K_SPECIAL and CSI in the returned string are escaped. */ -char_u * get_inserted() { +char_u *get_inserted(void) { return get_buffcont(&redobuff, FALSE); } @@ -218,10 +219,12 @@ char_u * get_inserted() { * Add string "s" after the current block of buffer "buf". * K_SPECIAL and CSI should have been escaped already. */ -static void add_buff(buf, s, slen) -struct buffheader *buf; -char_u *s; -long slen; /* length of "s" or -1 */ +static void +add_buff ( + struct buffheader *buf, + char_u *s, + long slen /* length of "s" or -1 */ +) { struct buffblock *p; long_u len; @@ -269,9 +272,7 @@ long slen; /* length of "s" or -1 */ /* * Add number "n" to buffer "buf". */ -static void add_num_buff(buf, n) -struct buffheader *buf; -long n; +static void add_num_buff(struct buffheader *buf, long n) { char_u number[32]; @@ -283,9 +284,7 @@ long n; * Add character 'c' to buffer "buf". * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. */ -static void add_char_buff(buf, c) -struct buffheader *buf; -int c; +static void add_char_buff(struct buffheader *buf, int c) { char_u bytes[MB_MAXBYTES + 1]; int len; @@ -319,8 +318,7 @@ int c; * If advance == TRUE go to the next char. * No translation is done K_SPECIAL and CSI are escaped. */ -static int read_stuff(advance) -int advance; +static int read_stuff(int advance) { char_u c; struct buffblock *curr; @@ -344,7 +342,7 @@ int advance; /* * Prepare the stuff buffer for reading (if it contains something). */ -static void start_stuff() { +static void start_stuff(void) { if (stuffbuff.bh_first.b_next != NULL) { stuffbuff.bh_curr = &(stuffbuff.bh_first); stuffbuff.bh_space = 0; @@ -354,15 +352,14 @@ static void start_stuff() { /* * Return TRUE if the stuff buffer is empty. */ -int stuff_empty() { +int stuff_empty(void) { return stuffbuff.bh_first.b_next == NULL; } /* * Set a typeahead character that won't be flushed. */ -void typeahead_noflush(c) -int c; +void typeahead_noflush(int c) { typeahead_char = c; } @@ -372,8 +369,7 @@ int c; * typeahead buffer (used in case of an error). If "flush_typeahead" is true, * flush all typeahead characters (used when interrupted by a CTRL-C). */ -void flush_buffers(flush_typeahead) -int flush_typeahead; +void flush_buffers(int flush_typeahead) { init_typebuf(); @@ -406,7 +402,7 @@ int flush_typeahead; * The previous contents of the redo buffer is kept in old_redobuffer. * This is used for the CTRL-O <.> command in insert mode. */ -void ResetRedobuff() { +void ResetRedobuff(void) { if (!block_redo) { free_buff(&old_redobuff); old_redobuff = redobuff; @@ -418,7 +414,7 @@ void ResetRedobuff() { * Discard the contents of the redo buffer and restore the previous redo * buffer. */ -void CancelRedo() { +void CancelRedo(void) { if (!block_redo) { free_buff(&redobuff); redobuff = old_redobuff; @@ -435,7 +431,7 @@ void CancelRedo() { */ static int save_level = 0; -void saveRedobuff() { +void saveRedobuff(void) { char_u *s; if (save_level++ == 0) { @@ -457,7 +453,7 @@ void saveRedobuff() { * Restore redobuff and old_redobuff from save_redobuff and save_old_redobuff. * Used after executing autocommands and user functions. */ -void restoreRedobuff() { +void restoreRedobuff(void) { if (--save_level == 0) { free_buff(&redobuff); redobuff = save_redobuff; @@ -470,8 +466,7 @@ void restoreRedobuff() { * Append "s" to the redo buffer. * K_SPECIAL and CSI should already have been escaped. */ -void AppendToRedobuff(s) -char_u *s; +void AppendToRedobuff(char_u *s) { if (!block_redo) add_buff(&redobuff, s, -1L); @@ -481,9 +476,11 @@ char_u *s; * Append to Redo buffer literally, escaping special characters with CTRL-V. * K_SPECIAL and CSI are escaped as well. */ -void AppendToRedobuffLit(str, len) -char_u *str; -int len; /* length of "str" or -1 for up to the NUL */ +void +AppendToRedobuffLit ( + char_u *str, + int len /* length of "str" or -1 for up to the NUL */ +) { char_u *s = str; int c; @@ -532,8 +529,7 @@ int len; /* length of "str" or -1 for up to the NUL */ * Append a character to the redo buffer. * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. */ -void AppendCharToRedobuff(c) -int c; +void AppendCharToRedobuff(int c) { if (!block_redo) add_char_buff(&redobuff, c); @@ -542,8 +538,7 @@ int c; /* * Append a number to the redo buffer. */ -void AppendNumberToRedobuff(n) -long n; +void AppendNumberToRedobuff(long n) { if (!block_redo) add_num_buff(&redobuff, n); @@ -553,15 +548,12 @@ long n; * Append string "s" to the stuff buffer. * CSI and K_SPECIAL must already have been escaped. */ -void stuffReadbuff(s) -char_u *s; +void stuffReadbuff(char_u *s) { add_buff(&stuffbuff, s, -1L); } -void stuffReadbuffLen(s, len) -char_u *s; -long len; +void stuffReadbuffLen(char_u *s, long len) { add_buff(&stuffbuff, s, len); } @@ -571,8 +563,7 @@ long len; * escaping other K_SPECIAL and CSI bytes. * Change CR, LF and ESC into a space. */ -void stuffReadbuffSpec(s) -char_u *s; +void stuffReadbuffSpec(char_u *s) { int c; @@ -594,8 +585,7 @@ char_u *s; * Append a character to the stuff buffer. * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. */ -void stuffcharReadbuff(c) -int c; +void stuffcharReadbuff(int c) { add_char_buff(&stuffbuff, c); } @@ -603,8 +593,7 @@ int c; /* * Append a number to the stuff buffer. */ -void stuffnumReadbuff(n) -long n; +void stuffnumReadbuff(long n) { add_num_buff(&stuffbuff, n); } @@ -617,9 +606,7 @@ long n; * otherwise. * If old is TRUE, use old_redobuff instead of redobuff. */ -static int read_redo(init, old_redo) -int init; -int old_redo; +static int read_redo(int init, int old_redo) { static struct buffblock *bp; static char_u *p; @@ -675,8 +662,7 @@ int old_redo; * If old_redo is TRUE, use old_redobuff instead of redobuff. * The escaped K_SPECIAL and CSI are copied without translation. */ -static void copy_redo(old_redo) -int old_redo; +static void copy_redo(int old_redo) { int c; @@ -693,9 +679,7 @@ int old_redo; * * return FAIL for failure, OK otherwise */ -int start_redo(count, old_redo) -long count; -int old_redo; +int start_redo(long count, int old_redo) { int c; @@ -744,7 +728,7 @@ int old_redo; * the redo buffer into the stuffbuff. * return FAIL for failure, OK otherwise */ -int start_redo_ins() { +int start_redo_ins(void) { int c; if (read_redo(TRUE, FALSE) == FAIL) @@ -766,7 +750,7 @@ int start_redo_ins() { return OK; } -void stop_redo_ins() { +void stop_redo_ins(void) { block_redo = FALSE; } @@ -775,7 +759,7 @@ void stop_redo_ins() { * alloc() cannot be used here: In out-of-memory situations it would * be impossible to type anything. */ -static void init_typebuf() { +static void init_typebuf(void) { if (typebuf.tb_buf == NULL) { typebuf.tb_buf = typebuf_init; typebuf.tb_noremap = noremapbuf_init; @@ -805,12 +789,7 @@ static void init_typebuf() { * * return FAIL for failure, OK otherwise */ -int ins_typebuf(str, noremap, offset, nottyped, silent) -char_u *str; -int noremap; -int offset; -int nottyped; -int silent; +int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, int silent) { char_u *s1, *s2; int newlen; @@ -931,8 +910,7 @@ int silent; * Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to * the char. */ -void ins_char_typebuf(c) -int c; +void ins_char_typebuf(int c) { char_u buf[MB_MAXBYTES + 1]; if (IS_SPECIAL(c)) { @@ -955,8 +933,10 @@ int c; * Or "typebuf.tb_off" may have been changed and we would overwrite characters * that was just added. */ -int typebuf_changed(tb_change_cnt) -int tb_change_cnt; /* old value of typebuf.tb_change_cnt */ +int +typebuf_changed ( + int tb_change_cnt /* old value of typebuf.tb_change_cnt */ +) { return tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt || typebuf_was_filled @@ -967,23 +947,21 @@ int tb_change_cnt; /* old value of typebuf.tb_change_cnt */ * Return TRUE if there are no characters in the typeahead buffer that have * not been typed (result from a mapping or come from ":normal"). */ -int typebuf_typed() { +int typebuf_typed(void) { return typebuf.tb_maplen == 0; } /* * Return the number of characters that are mapped (or not typed). */ -int typebuf_maplen() { +int typebuf_maplen(void) { return typebuf.tb_maplen; } /* * remove "len" characters from typebuf.tb_buf[typebuf.tb_off + offset] */ -void del_typebuf(len, offset) -int len; -int offset; +void del_typebuf(int len, int offset) { int i; @@ -1053,9 +1031,7 @@ int offset; * Write typed characters to script file. * If recording is on put the character in the recordbuffer. */ -static void gotchars(chars, len) -char_u *chars; -int len; +static void gotchars(char_u *chars, int len) { char_u *s = chars; int c; @@ -1095,7 +1071,7 @@ int len; * - While reading a script file. * - When no_u_sync is non-zero. */ -static void may_sync_undo() { +static void may_sync_undo(void) { if ((!(State & (INSERT + CMDLINE)) || arrow_used) && scriptin[curscript] == NULL) u_sync(FALSE); @@ -1105,7 +1081,7 @@ static void may_sync_undo() { * Make "typebuf" empty and allocate new buffers. * Returns FAIL when out of memory. */ -int alloc_typebuf() { +int alloc_typebuf(void) { typebuf.tb_buf = alloc(TYPELEN_INIT); typebuf.tb_noremap = alloc(TYPELEN_INIT); if (typebuf.tb_buf == NULL || typebuf.tb_noremap == NULL) { @@ -1126,7 +1102,7 @@ int alloc_typebuf() { /* * Free the buffers of "typebuf". */ -void free_typebuf() { +void free_typebuf(void) { if (typebuf.tb_buf == typebuf_init) EMSG2(_(e_intern2), "Free typebuf 1"); else @@ -1143,7 +1119,7 @@ void free_typebuf() { */ static typebuf_T saved_typebuf[NSCRIPT]; -int save_typebuf() { +int save_typebuf(void) { init_typebuf(); saved_typebuf[curscript] = typebuf; /* If out of memory: restore typebuf and close file. */ @@ -1163,8 +1139,7 @@ static int old_mouse_col; /* mouse_col related to old_char */ /* * Save all three kinds of typeahead, so that the user must type at a prompt. */ -void save_typeahead(tp) -tasave_T *tp; +void save_typeahead(tasave_T *tp) { tp->save_typebuf = typebuf; tp->typebuf_valid = (alloc_typebuf() == OK); @@ -1186,8 +1161,7 @@ tasave_T *tp; * Restore the typeahead to what it was before calling save_typeahead(). * The allocated memory is freed, can only be called once! */ -void restore_typeahead(tp) -tasave_T *tp; +void restore_typeahead(tasave_T *tp) { if (tp->typebuf_valid) { free_typebuf(); @@ -1207,9 +1181,11 @@ tasave_T *tp; /* * Open a new script file for the ":source!" command. */ -void openscript(name, directly) -char_u *name; -int directly; /* when TRUE execute directly */ +void +openscript ( + char_u *name, + int directly /* when TRUE execute directly */ +) { if (curscript + 1 == NSCRIPT) { EMSG(_(e_nesting)); @@ -1272,7 +1248,7 @@ int directly; /* when TRUE execute directly */ /* * Close the currently active input script. */ -static void closescript() { +static void closescript(void) { free_typebuf(); typebuf = saved_typebuf[curscript]; @@ -1283,7 +1259,7 @@ static void closescript() { } #if defined(EXITFREE) || defined(PROTO) -void close_all_scripts() { +void close_all_scripts(void) { while (scriptin[0] != NULL) closescript(); } @@ -1293,7 +1269,7 @@ void close_all_scripts() { /* * Return TRUE when reading keys from a script file. */ -int using_script() { +int using_script(void) { return scriptin[curscript] != NULL; } @@ -1301,7 +1277,7 @@ int using_script() { * This function is called just before doing a blocking wait. Thus after * waiting 'updatetime' for a character to arrive. */ -void before_blocking() { +void before_blocking(void) { updatescript(0); if (may_garbage_collect) garbage_collect(); @@ -1314,8 +1290,7 @@ void before_blocking() { * All the changed memfiles are synced if c == 0 or when the number of typed * characters reaches 'updatecount' and 'updatecount' is non-zero. */ -void updatescript(c) -int c; +void updatescript(int c) { static int count = 0; @@ -1336,7 +1311,7 @@ int c; * Collects the bytes of a multibyte character into the whole character. * Returns the modifiers in the global "mod_mask". */ -int vgetc() { +int vgetc(void) { int c, c2; int n; char_u buf[MB_MAXBYTES + 1]; @@ -1481,7 +1456,7 @@ int vgetc() { * Like vgetc(), but never return a NUL when called recursively, get a key * directly from the user (ignoring typeahead). */ -int safe_vgetc() { +int safe_vgetc(void) { int c; c = vgetc(); @@ -1494,7 +1469,7 @@ int safe_vgetc() { * Like safe_vgetc(), but loop to handle K_IGNORE. * Also ignore scrollbar events. */ -int plain_vgetc() { +int plain_vgetc(void) { int c; do { @@ -1508,7 +1483,7 @@ int plain_vgetc() { * If the next character is a special character or multi-byte, the returned * character is not valid!. */ -int vpeekc() { +int vpeekc(void) { if (old_char != -1) return old_char; return vgetorpeek(FALSE); @@ -1518,7 +1493,7 @@ int vpeekc() { * Like vpeekc(), but don't allow mapping. Do allow checking for terminal * codes. */ -int vpeekc_nomap() { +int vpeekc_nomap(void) { int c; ++no_mapping; @@ -1534,7 +1509,7 @@ int vpeekc_nomap() { * Trick: when no typeahead found, but there is something in the typeahead * buffer, it must be an ESC that is recognized as the start of a key code. */ -int vpeekc_any() { +int vpeekc_any(void) { int c; c = vpeekc(); @@ -1547,7 +1522,7 @@ int vpeekc_any() { * Call vpeekc() without causing anything to be mapped. * Return TRUE if a character is available, FALSE otherwise. */ -int char_avail() { +int char_avail(void) { int retval; ++no_mapping; @@ -1556,8 +1531,10 @@ int char_avail() { return retval != NUL; } -void vungetc(c) /* unget one character (can only be done once!) */ -int c; +void +vungetc ( /* unget one character (can only be done once!) */ + int c +) { old_char = c; old_mod_mask = mod_mask; @@ -1588,8 +1565,7 @@ int c; * Only returns one byte (of a multi-byte character). * K_SPECIAL and CSI may be escaped, need to get two more bytes then. */ -static int vgetorpeek(advance) -int advance; +static int vgetorpeek(int advance) { int c, c1; int keylen; @@ -2363,11 +2339,13 @@ int advance; * Return the number of obtained characters. * Return -1 when end of input script reached. */ -int inchar(buf, maxlen, wait_time, tb_change_cnt) -char_u *buf; -int maxlen; -long wait_time; /* milli seconds */ -int tb_change_cnt; +int +inchar ( + char_u *buf, + int maxlen, + long wait_time, /* milli seconds */ + int tb_change_cnt +) { int len = 0; /* init for GCC */ int retesc = FALSE; /* return ESC with gotint */ @@ -2464,10 +2442,12 @@ int tb_change_cnt; * buf[] must have room to triple the number of bytes! * Returns the new length. */ -int fix_input_buffer(buf, len, script) -char_u *buf; -int len; -int script; /* TRUE when reading from a script */ +int +fix_input_buffer ( + char_u *buf, + int len, + int script /* TRUE when reading from a script */ +) { int i; char_u *p = buf; @@ -2505,7 +2485,7 @@ int script; /* TRUE when reading from a script */ * or feedkeys() may insert characters in the typeahead buffer while we are * waiting for input to arrive. */ -int input_available() { +int input_available(void) { return !vim_is_input_buf_empty() || typebuf_was_filled ; @@ -2551,11 +2531,13 @@ int input_available() { * 4 for out of mem * 5 for entry not unique */ -int do_map(maptype, arg, mode, abbrev) -int maptype; -char_u *arg; -int mode; -int abbrev; /* not a mapping but an abbreviation */ +int +do_map ( + int maptype, + char_u *arg, + int mode, + int abbrev /* not a mapping but an abbreviation */ +) { char_u *keys; mapblock_T *mp, **mpp; @@ -3020,8 +3002,7 @@ theend: * Delete one entry from the abbrlist or maphash[]. * "mpp" is a pointer to the m_next field of the PREVIOUS entry! */ -static void map_free(mpp) -mapblock_T **mpp; +static void map_free(mapblock_T **mpp) { mapblock_T *mp; @@ -3036,7 +3017,7 @@ mapblock_T **mpp; /* * Initialize maphash[] for first use. */ -static void validate_maphash() { +static void validate_maphash(void) { if (!maphash_valid) { vim_memset(maphash, 0, sizeof(maphash)); maphash_valid = TRUE; @@ -3046,9 +3027,7 @@ static void validate_maphash() { /* * Get the mapping mode from the command name. */ -int get_map_mode(cmdp, forceit) -char_u **cmdp; -int forceit; +int get_map_mode(char_u **cmdp, int forceit) { char_u *p; int modec; @@ -3088,11 +3067,7 @@ int forceit; * Clear all mappings or abbreviations. * 'abbr' should be FALSE for mappings, TRUE for abbreviations. */ -void map_clear(cmdp, arg, forceit, abbr) -char_u *cmdp; -char_u *arg UNUSED; -int forceit; -int abbr; +void map_clear(char_u *cmdp, char_u *arg, int forceit, int abbr) { int mode; int local; @@ -3112,11 +3087,13 @@ int abbr; /* * Clear all mappings in "mode". */ -void map_clear_int(buf, mode, local, abbr) -buf_T *buf UNUSED; /* buffer for local mappings */ -int mode; /* mode in which to delete */ -int local UNUSED; /* TRUE for buffer-local mappings */ -int abbr; /* TRUE for abbreviations */ +void +map_clear_int ( + buf_T *buf, /* buffer for local mappings */ + int mode, /* mode in which to delete */ + int local, /* TRUE for buffer-local mappings */ + int abbr /* TRUE for abbreviations */ +) { mapblock_T *mp, **mpp; int hash; @@ -3171,8 +3148,7 @@ int abbr; /* TRUE for abbreviations */ * Return characters to represent the map mode in an allocated string. * Returns NULL when out of memory. */ -char_u * map_mode_to_chars(mode) -int mode; +char_u *map_mode_to_chars(int mode) { garray_T mapmode; @@ -3208,9 +3184,11 @@ int mode; return (char_u *)mapmode.ga_data; } -static void showmap(mp, local) -mapblock_T *mp; -int local; /* TRUE for buffer-local map */ +static void +showmap ( + mapblock_T *mp, + int local /* TRUE for buffer-local map */ +) { int len = 1; char_u *mapchars; @@ -3274,10 +3252,7 @@ int local; /* TRUE for buffer-local map */ * Recognize termcap codes in "str". * Also checks mappings local to the current buffer. */ -int map_to_exists(str, modechars, abbr) -char_u *str; -char_u *modechars; -int abbr; +int map_to_exists(char_u *str, char_u *modechars, int abbr) { int mode = 0; char_u *rhs; @@ -3313,10 +3288,7 @@ int abbr; * Return TRUE if a map exists that has "str" in the rhs for mode "mode". * Also checks mappings local to the current buffer. */ -int map_to_exists_mode(rhs, mode, abbr) -char_u *rhs; -int mode; -int abbr; +int map_to_exists_mode(char_u *rhs, int mode, int abbr) { mapblock_T *mp; int hash; @@ -3363,15 +3335,16 @@ static int expand_buffer = FALSE; * Work out what to complete when doing command line completion of mapping * or abbreviation names. */ -char_u * set_context_in_map_cmd(xp, cmd, arg, forceit, isabbrev, isunmap, - cmdidx) -expand_T *xp; -char_u *cmd; -char_u *arg; -int forceit; /* TRUE if '!' given */ -int isabbrev; /* TRUE if abbreviation */ -int isunmap; /* TRUE if unmap/unabbrev command */ -cmdidx_T cmdidx; +char_u * +set_context_in_map_cmd ( + expand_T *xp, + char_u *cmd, + char_u *arg, + int forceit, /* TRUE if '!' given */ + int isabbrev, /* TRUE if abbreviation */ + int isunmap, /* TRUE if unmap/unabbrev command */ + cmdidx_T cmdidx +) { if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap) xp->xp_context = EXPAND_NOTHING; @@ -3425,10 +3398,7 @@ cmdidx_T cmdidx; * For command line expansion of ":[un]map" and ":[un]abbrev" in all modes. * Return OK if matches found, FAIL otherwise. */ -int ExpandMappings(regmatch, num_file, file) -regmatch_T *regmatch; -int *num_file; -char_u ***file; +int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file) { mapblock_T *mp; int hash; @@ -3551,11 +3521,7 @@ char_u ***file; * * return TRUE if there is an abbreviation, FALSE if not */ -int check_abbr(c, ptr, col, mincol) -int c; -char_u *ptr; -int col; -int mincol; +int check_abbr(int c, char_u *ptr, int col, int mincol) { int len; int scol; /* starting column of the abbr. */ @@ -3703,9 +3669,11 @@ int mincol; * Evaluate the RHS of a mapping or abbreviations and take care of escaping * special characters. */ -static char_u * eval_map_expr(str, c) -char_u *str; -int c; /* NUL or typed character for abbreviation */ +static char_u * +eval_map_expr ( + char_u *str, + int c /* NUL or typed character for abbreviation */ +) { char_u *res; char_u *p; @@ -3760,8 +3728,7 @@ int c; /* NUL or typed character for abbreviation */ * can be put in the typeahead buffer. * Returns NULL when out of memory. */ -char_u * vim_strsave_escape_csi(p) -char_u *p; +char_u *vim_strsave_escape_csi(char_u *p) { char_u *res; char_u *s, *d; @@ -3799,8 +3766,7 @@ char_u *p; * Remove escaping from CSI and K_SPECIAL characters. Reverse of * vim_strsave_escape_csi(). Works in-place. */ -void vim_unescape_csi(p) -char_u *p; +void vim_unescape_csi(char_u *p) { char_u *s = p, *d = p; @@ -3822,9 +3788,11 @@ char_u *p; * Write map commands for the current mappings to an .exrc file. * Return FAIL on error, OK otherwise. */ -int makemap(fd, buf) -FILE *fd; -buf_T *buf; /* buffer for local mappings or NULL */ +int +makemap ( + FILE *fd, + buf_T *buf /* buffer for local mappings or NULL */ +) { mapblock_T *mp; char_u c1, c2, c3; @@ -4019,10 +3987,7 @@ buf_T *buf; /* buffer for local mappings or NULL */ * * return FAIL for failure, OK otherwise */ -int put_escstr(fd, strstart, what) -FILE *fd; -char_u *strstart; -int what; +int put_escstr(FILE *fd, char_u *strstart, int what) { char_u *str = strstart; int c; @@ -4118,7 +4083,7 @@ int what; * Check all mappings for the presence of special key codes. * Used after ":set term=xxx". */ -void check_map_keycodes() { +void check_map_keycodes(void) { mapblock_T *mp; char_u *p; int i; @@ -4187,14 +4152,16 @@ void check_map_keycodes() { * Return pointer to rhs of mapping (mapblock->m_str). * NULL when no mapping found. */ -char_u * check_map(keys, mode, exact, ign_mod, abbr, mp_ptr, local_ptr) -char_u *keys; -int mode; -int exact; /* require exact match */ -int ign_mod; /* ignore preceding modifier */ -int abbr; /* do abbreviations */ -mapblock_T **mp_ptr; /* return: pointer to mapblock or NULL */ -int *local_ptr; /* return: buffer-local mapping or NULL */ +char_u * +check_map ( + char_u *keys, + int mode, + int exact, /* require exact match */ + int ign_mod, /* ignore preceding modifier */ + int abbr, /* do abbreviations */ + mapblock_T **mp_ptr, /* return: pointer to mapblock or NULL */ + int *local_ptr /* return: buffer-local mapping or NULL */ +) { int hash; int len, minlen; @@ -4255,9 +4222,7 @@ int *local_ptr; /* return: buffer-local mapping or NULL */ * Add a mapping "map" for mode "mode". * Need to put string in allocated memory, because do_map() will modify it. */ -void add_map(map, mode) -char_u *map; -int mode; +void add_map(char_u *map, int mode) { char_u *s; char_u *cpo_save = p_cpo; diff --git a/src/hangulin.c b/src/hangulin.c index 7f41509e83..c04a1800ba 100644 --- a/src/hangulin.c +++ b/src/hangulin.c @@ -96,9 +96,7 @@ static short_u kind_table_for_3[] = * 3 bulsik: (current initial sound, input english) -> compound initial sound. */ -static int comfcon3(v, c) -int v; -int c; +static int comfcon3(int v, int c) { if (v == 2 && c == 2) return 3; @@ -117,9 +115,7 @@ int c; * 3 bulsik: (current vowel, input english) -> compound vowel. */ -static int comvow3(v, c) -int v; -int c; +static int comvow3(int v, int c) { switch (v) { case 13: /* ¤Ç */ @@ -156,9 +152,7 @@ int c; * VIM: V = initial sound, I = medial vowel, M = final consonant. */ -static int comcon3(k, c) -int k; -int c; +static int comcon3(int k, int c) { switch (k) { case 2: /* ¤¡ */ @@ -212,8 +206,7 @@ int c; /****** 2 ¹ú½ÄÀÚÆÇÀ» À§ÇÑ ·çƾ (Routines for 2 bulsik keyboard) ******/ /**********************************************************************/ -static int kind_table_for_2(c) -int c; +static int kind_table_for_2(int c) { static char_u table[] = { @@ -235,8 +228,7 @@ int c; * (2 bulsik: conversion english char. to initial sound of compound type) * °á°ú: ÃʼºÀÌ ¾Æ´Ï¸é 0 (If it is not initial sound, return 0). */ -static int fcon(c) -int c; +static int fcon(int c) { static char_u table[] = { @@ -259,8 +251,7 @@ int c; * (2 bulsik: conversion english char. to medial vowel) * °á°ú: Áß¼ºÀÌ ¾Æ´Ï¸é 0 (If it is not medial vowel, return 0). */ -static int vow(c) -int c; +static int vow(int c) { static char_u table[] = { @@ -282,8 +273,7 @@ int c; * (2 bulsik: conversion english char. to prop) * °á°ú: ¹ÞħÀÌ ¾Æ´Ï¸é 0 (If not prop, return 0) */ -static int lcon(c) -int c; +static int lcon(int c) { static char_u table[] = { @@ -304,9 +294,7 @@ int c; * (2 bulsik: conversion (curr. prop, input english) to prop) */ -static int comcon2(k, c) -int k; -int c; +static int comcon2(int k, int c) { switch (k) { case 2: /* ¤¡ */ @@ -359,9 +347,7 @@ int c; * vowel) */ -static int comvow2(v, c) -int v; -int c; +static int comvow2(int v, int c) { switch (v) { case 13: /* ¤Ç */ @@ -396,22 +382,21 @@ int c; return 0; } -int hangul_input_state_get() { +int hangul_input_state_get(void) { return hangul_input_state; } -void hangul_input_state_set(state) -int state; +void hangul_input_state_set(int state) { hangul_input_state = state; hangul_input_clear(); } -int im_get_status() { +int im_get_status(void) { return hangul_input_state_get(); } -void hangul_input_state_toggle() { +void hangul_input_state_toggle(void) { if (hangul_input_state_get()) { hangul_input_state_set(0); if (composing_hangul) { @@ -428,9 +413,7 @@ void hangul_input_state_toggle() { } -static int hangul_automata2(buf, c) -char_u *buf; -int_u *c; +static int hangul_automata2(char_u *buf, int_u *c) { int t,t2; @@ -570,9 +553,7 @@ int_u *c; return AUTOMATA_ERROR; /* RrEeAaLlLlYy EeRrRrOoRr */ } -static int hangul_automata3(buf, c) -char_u *buf; -int_u *c; +static int hangul_automata3(char_u *buf, int_u *c) { int t, t2; @@ -665,7 +646,7 @@ int_u *c; return AUTOMATA_SPECIAL; } -void hangul_keyboard_set() { +void hangul_keyboard_set(void) { int keyboard; char *s; @@ -683,9 +664,7 @@ void hangul_keyboard_set() { } } -int hangul_input_process(s, len) -char_u *s; -int len; +int hangul_input_process(char_u *s, int len) { int n; unsigned int c; @@ -746,7 +725,7 @@ int len; return len; } -void hangul_input_clear() { +void hangul_input_clear(void) { sp = 0; f = F_NULL; m = M_NULL; @@ -1416,11 +1395,7 @@ static const char_u johab_lcon_to_wan[] = 0xbb, 0xbc, 0xbd, 0xbe /* ¤», ¤¼, ¤½, ¤¾ */ }; -static void convert_ks_to_3(src, fp, mp, lp) -const char_u *src; -int *fp; -int *mp; -int *lp; +static void convert_ks_to_3(const char_u *src, int *fp, int *mp, int *lp) { int h = *src; int low = *(src + 1); @@ -1447,11 +1422,7 @@ int *lp; } } -static int convert_3_to_ks(fv, mv, lv, des) -int fv; -int mv; -int lv; -char_u *des; +static int convert_3_to_ks(int fv, int mv, int lv, char_u *des) { char_u key[3]; register int hi, lo, mi = 0, result, found; diff --git a/src/hardcopy.c b/src/hardcopy.c index 5869b55a49..9ebe087bca 100644 --- a/src/hardcopy.c +++ b/src/hardcopy.c @@ -151,7 +151,7 @@ static void prt_get_attr __ARGS((int hl_id, prt_text_attr_T* pattr, int modec)); * Parse 'printoptions' and set the flags in "printer_opts". * Returns an error message or NULL; */ -char_u * parse_printoptions() { +char_u *parse_printoptions(void) { return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS); } @@ -159,7 +159,7 @@ char_u * parse_printoptions() { * Parse 'printoptions' and set the flags in "printer_opts". * Returns an error message or NULL; */ -char_u * parse_printmbfont() { +char_u *parse_printmbfont(void) { return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS); } @@ -172,10 +172,7 @@ char_u * parse_printmbfont() { * Returns an error message for an illegal option, NULL otherwise. * Only used for the printer at the moment... */ -static char_u * parse_list_options(option_str, table, table_size) -char_u *option_str; -option_table_T *table; -int table_size; +static char_u *parse_list_options(char_u *option_str, option_table_T *table, int table_size) { char_u *stringp; char_u *colonp; @@ -234,16 +231,14 @@ int table_size; * If using a dark background, the colors will probably be too bright to show * up well on white paper, so reduce their brightness. */ -static long_u darken_rgb(rgb) -long_u rgb; +static long_u darken_rgb(long_u rgb) { return ((rgb >> 17) << 16) + (((rgb & 0xff00) >> 9) << 8) + ((rgb & 0xff) >> 1); } -static long_u prt_get_term_color(colorindex) -int colorindex; +static long_u prt_get_term_color(int colorindex) { /* TODO: Should check for xterm with 88 or 256 colors. */ if (t_colors > 8) @@ -251,10 +246,7 @@ int colorindex; return cterm_color_8[colorindex % 8]; } -static void prt_get_attr(hl_id, pattr, modec) -int hl_id; -prt_text_attr_T *pattr; -int modec; +static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec) { int colorindex; long_u fg_color; @@ -290,8 +282,7 @@ int modec; pattr->bg_color = bg_color; } -static void prt_set_fg(fg) -long_u fg; +static void prt_set_fg(long_u fg) { if (fg != curr_fg) { curr_fg = fg; @@ -299,8 +290,7 @@ long_u fg; } } -static void prt_set_bg(bg) -long_u bg; +static void prt_set_bg(long_u bg) { if (bg != curr_bg) { curr_bg = bg; @@ -308,10 +298,7 @@ long_u bg; } } -static void prt_set_font(bold, italic, underline) -int bold; -int italic; -int underline; +static void prt_set_font(int bold, int italic, int underline) { if (curr_bold != bold || curr_italic != italic @@ -326,10 +313,7 @@ int underline; /* * Print the line number in the left margin. */ -static void prt_line_number(psettings, page_line, lnum) -prt_settings_T *psettings; -int page_line; -linenr_T lnum; +static void prt_line_number(prt_settings_T *psettings, int page_line, linenr_T lnum) { int i; char_u tbuf[20]; @@ -360,7 +344,7 @@ linenr_T lnum; /* * Get the currently effective header height. */ -int prt_header_height() { +int prt_header_height(void) { if (printer_opts[OPT_PRINT_HEADERHEIGHT].present) return printer_opts[OPT_PRINT_HEADERHEIGHT].number; return 2; @@ -369,7 +353,7 @@ int prt_header_height() { /* * Return TRUE if using a line number for printing. */ -int prt_use_number() { +int prt_use_number(void) { return printer_opts[OPT_PRINT_NUMBER].present && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y'; } @@ -378,8 +362,7 @@ int prt_use_number() { * Return the unit used in a margin item in 'printoptions'. * Returns PRT_UNIT_NONE if not recognized. */ -int prt_get_unit(idx) -int idx; +int prt_get_unit(int idx) { int u = PRT_UNIT_NONE; int i; @@ -397,10 +380,7 @@ int idx; /* * Print the page header. */ -static void prt_header(psettings, pagenum, lnum) -prt_settings_T *psettings; -int pagenum; -linenr_T lnum UNUSED; +static void prt_header(prt_settings_T *psettings, int pagenum, linenr_T lnum) { int width = psettings->chars_per_line; int page_line; @@ -481,16 +461,14 @@ linenr_T lnum UNUSED; /* * Display a print status message. */ -static void prt_message(s) -char_u *s; +static void prt_message(char_u *s) { screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R)); out_flush(); } -void ex_hardcopy(eap) -exarg_T *eap; +void ex_hardcopy(exarg_T *eap) { linenr_T lnum; int collated_copies, uncollated_copies; @@ -726,10 +704,7 @@ print_fail_no_begin: * Print one page line. * Return the next column to print, or zero if the line is finished. */ -static colnr_T hardcopy_line(psettings, page_line, ppos) -prt_settings_T *psettings; -int page_line; -prt_pos_T *ppos; +static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos) { colnr_T col; char_u *line; @@ -1337,9 +1312,7 @@ static int prt_half_width; static char *prt_ascii_encoding; static char_u prt_hexchar[] = "0123456789abcdef"; -static void prt_write_file_raw_len(buffer, bytes) -char_u *buffer; -int bytes; +static void prt_write_file_raw_len(char_u *buffer, int bytes) { if (!prt_file_error && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd) @@ -1349,15 +1322,12 @@ int bytes; } } -static void prt_write_file(buffer) -char_u *buffer; +static void prt_write_file(char_u *buffer) { prt_write_file_len(buffer, (int)STRLEN(buffer)); } -static void prt_write_file_len(buffer, bytes) -char_u *buffer; -int bytes; +static void prt_write_file_len(char_u *buffer, int bytes) { prt_write_file_raw_len(buffer, bytes); } @@ -1365,8 +1335,7 @@ int bytes; /* * Write a string. */ -static void prt_write_string(s) -char *s; +static void prt_write_string(char *s) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s); prt_write_file(prt_line_buffer); @@ -1375,8 +1344,7 @@ char *s; /* * Write an int and a space. */ -static void prt_write_int(i) -int i; +static void prt_write_int(int i) { sprintf((char *)prt_line_buffer, "%d ", i); prt_write_file(prt_line_buffer); @@ -1385,8 +1353,7 @@ int i; /* * Write a boolean and a space. */ -static void prt_write_boolean(b) -int b; +static void prt_write_boolean(int b) { sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F")); prt_write_file(prt_line_buffer); @@ -1395,11 +1362,7 @@ int b; /* * Write PostScript to re-encode and define the font. */ -static void prt_def_font(new_name, encoding, height, font) -char *new_name; -char *encoding; -int height; -char *font; +static void prt_def_font(char *new_name, char *encoding, int height, char *font) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "/_%s /VIM-%s /%s ref\n", new_name, encoding, font); @@ -1416,10 +1379,7 @@ char *font; /* * Write a line to define the CID font. */ -static void prt_def_cidfont(new_name, height, cidfont) -char *new_name; -int height; -char *cidfont; +static void prt_def_cidfont(char *new_name, int height, char *cidfont) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont); @@ -1432,9 +1392,7 @@ char *cidfont; /* * Write a line to define a duplicate of a CID font */ -static void prt_dup_cidfont(original_name, new_name) -char *original_name; -char *new_name; +static void prt_dup_cidfont(char *original_name, char *new_name) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "/%s %s d\n", new_name, original_name); @@ -1446,11 +1404,7 @@ char *new_name; * the fractional part being in the range [0,10^precision). The fractional part * is also rounded based on the precision + 1'th fractional digit. */ -static void prt_real_bits(real, precision, pinteger, pfraction) -double real; -int precision; -int *pinteger; -int *pfraction; +static void prt_real_bits(double real, int precision, int *pinteger, int *pfraction) { int i; int integer; @@ -1472,9 +1426,7 @@ int *pfraction; * We use prt_real_bits() as %f in sprintf uses the locale setting to decide * what decimal point character to use, but PS always requires a '.'. */ -static void prt_write_real(val, prec) -double val; -int prec; +static void prt_write_real(double val, int prec) { int integer; int fraction; @@ -1501,10 +1453,7 @@ int prec; /* * Write a line to define a numeric variable. */ -static void prt_def_var(name, value, prec) -char *name; -double value; -int prec; +static void prt_def_var(char *name, double value, int prec) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "/%s ", name); @@ -1517,7 +1466,7 @@ int prec; /* Convert size from font space to user space at current font scale */ #define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0)) -static void prt_flush_buffer() { +static void prt_flush_buffer(void) { if (prt_ps_buffer.ga_len > 0) { /* Any background color must be drawn first */ if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE)) { @@ -1585,9 +1534,7 @@ static void prt_flush_buffer() { } } -static void prt_resource_name(filename, cookie) -char_u *filename; -void *cookie; +static void prt_resource_name(char_u *filename, void *cookie) { char_u *resource_filename = cookie; @@ -1597,9 +1544,7 @@ void *cookie; STRCPY(resource_filename, filename); } -static int prt_find_resource(name, resource) -char *name; -struct prt_ps_resource_S *resource; +static int prt_find_resource(char *name, struct prt_ps_resource_S *resource) { char_u *buffer; int retval; @@ -1638,7 +1583,7 @@ struct prt_resfile_buffer_S { static struct prt_resfile_buffer_S prt_resfile; -static int prt_resfile_next_line() { +static int prt_resfile_next_line(void) { int idx; /* Move to start of next line and then find end of line */ @@ -1660,10 +1605,7 @@ static int prt_resfile_next_line() { return idx < prt_resfile.len; } -static int prt_resfile_strncmp(offset, string, len) -int offset; -char *string; -int len; +static int prt_resfile_strncmp(int offset, char *string, int len) { /* Force not equal if string is longer than remainder of line */ if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))) @@ -1673,8 +1615,7 @@ int len; string, len); } -static int prt_resfile_skip_nonws(offset) -int offset; +static int prt_resfile_skip_nonws(int offset) { int idx; @@ -1687,8 +1628,7 @@ int offset; return -1; } -static int prt_resfile_skip_ws(offset) -int offset; +static int prt_resfile_skip_ws(int offset) { int idx; @@ -1703,8 +1643,7 @@ int offset; /* prt_next_dsc() - returns detail on next DSC comment line found. Returns true * if a DSC comment is found, else false */ -static int prt_next_dsc(p_dsc_line) -struct prt_dsc_line_S *p_dsc_line; +static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line) { int comment; int offset; @@ -1749,8 +1688,7 @@ struct prt_dsc_line_S *p_dsc_line; /* Improved hand crafted parser to get the type, title, and version number of a * PS resource file so the file details can be added to the DSC header comments. */ -static int prt_open_resource(resource) -struct prt_ps_resource_S *resource; +static int prt_open_resource(struct prt_ps_resource_S *resource) { int offset; int seen_all; @@ -1866,9 +1804,7 @@ struct prt_ps_resource_S *resource; return TRUE; } -static int prt_check_resource(resource, version) -struct prt_ps_resource_S *resource; -char_u *version; +static int prt_check_resource(struct prt_ps_resource_S *resource, char_u *version) { /* Version number m.n should match, the revision number does not matter */ if (STRNCMP(resource->version, version, STRLEN(version))) { @@ -1881,30 +1817,25 @@ char_u *version; return TRUE; } -static void prt_dsc_start() { +static void prt_dsc_start(void) { prt_write_string("%!PS-Adobe-3.0\n"); } -static void prt_dsc_noarg(comment) -char *comment; +static void prt_dsc_noarg(char *comment) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%%%%%s\n", comment); prt_write_file(prt_line_buffer); } -static void prt_dsc_textline(comment, text) -char *comment; -char *text; +static void prt_dsc_textline(char *comment, char *text) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%%%%%s: %s\n", comment, text); prt_write_file(prt_line_buffer); } -static void prt_dsc_text(comment, text) -char *comment; -char *text; +static void prt_dsc_text(char *comment, char *text) { /* TODO - should scan 'text' for any chars needing escaping! */ vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), @@ -1914,10 +1845,7 @@ char *text; #define prt_dsc_atend(c) prt_dsc_text((c), "atend") -static void prt_dsc_ints(comment, count, ints) -char *comment; -int count; -int *ints; +static void prt_dsc_ints(char *comment, int count, int *ints) { int i; @@ -1933,10 +1861,12 @@ int *ints; prt_write_string("\n"); } -static void prt_dsc_resources(comment, type, string) -char *comment; /* if NULL add to previous */ -char *type; -char *string; +static void +prt_dsc_resources ( + char *comment, /* if NULL add to previous */ + char *type, + char *string +) { if (comment != NULL) vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), @@ -1951,9 +1881,7 @@ char *string; prt_write_file(prt_line_buffer); } -static void prt_dsc_font_resource(resource, ps_font) -char *resource; -struct prt_ps_font_S *ps_font; +static void prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font) { int i; @@ -1964,12 +1892,7 @@ struct prt_ps_font_S *ps_font; prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]); } -static void prt_dsc_requirements(duplex, tumble, collate, color, num_copies) -int duplex; -int tumble; -int collate; -int color; -int num_copies; +static void prt_dsc_requirements(int duplex, int tumble, int collate, int color, int num_copies) { /* Only output the comment if we need to. * Note: tumble is ignored if we are not duplexing @@ -1999,13 +1922,7 @@ int num_copies; prt_write_string("\n"); } -static void prt_dsc_docmedia(paper_name, width, height, weight, colour, type) -char *paper_name; -double width; -double height; -double weight; -char *colour; -char *type; +static void prt_dsc_docmedia(char *paper_name, double width, double height, double weight, char *colour, char *type) { vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%%%%DocumentMedia: %s ", paper_name); @@ -2025,7 +1942,7 @@ char *type; prt_write_string("\n"); } -void mch_print_cleanup() { +void mch_print_cleanup(void) { if (prt_out_mbyte) { int i; @@ -2055,10 +1972,7 @@ void mch_print_cleanup() { } } -static float to_device_units(idx, physsize, def_number) -int idx; -double physsize; -int def_number; +static float to_device_units(int idx, double physsize, int def_number) { float ret; int u; @@ -2093,13 +2007,7 @@ int def_number; /* * Calculate margins for given width and height from printoptions settings. */ -static void prt_page_margins(width, height, left, right, top, bottom) -double width; -double height; -double *left; -double *right; -double *top; -double *bottom; +static void prt_page_margins(double width, double height, double *left, double *right, double *top, double *bottom) { *left = to_device_units(OPT_PRINT_LEFT, width, 10); *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5); @@ -2107,15 +2015,14 @@ double *bottom; *bottom = to_device_units(OPT_PRINT_BOT, height, 5); } -static void prt_font_metrics(font_scale) -int font_scale; +static void prt_font_metrics(int font_scale) { prt_line_height = (float)font_scale; prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx); } -static int prt_get_cpl() { +static int prt_get_cpl(void) { if (prt_use_number()) { prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width; /* If we are outputting multi-byte characters then line numbers will be @@ -2130,10 +2037,7 @@ static int prt_get_cpl() { return (int)((prt_right_margin - prt_left_margin) / prt_char_width); } -static int prt_build_cid_fontname(font, name, name_len) -int font; -char_u *name; -int name_len; +static int prt_build_cid_fontname(int font, char_u *name, int name_len) { char *fontname; @@ -2149,7 +2053,7 @@ int name_len; /* * Get number of lines of text that fit on a page (excluding the header). */ -static int prt_get_lpp() { +static int prt_get_lpp(void) { int lpp; /* @@ -2177,10 +2081,7 @@ static int prt_get_lpp() { return lpp - prt_header_height(); } -static int prt_match_encoding(p_encoding, p_cmap, pp_mbenc) -char *p_encoding; -struct prt_ps_mbfont_S *p_cmap; -struct prt_ps_encoding_S **pp_mbenc; +static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc) { int mbenc; int enc_len; @@ -2200,10 +2101,7 @@ struct prt_ps_encoding_S **pp_mbenc; return FALSE; } -static int prt_match_charset(p_charset, p_cmap, pp_mbchar) -char *p_charset; -struct prt_ps_mbfont_S *p_cmap; -struct prt_ps_charset_S **pp_mbchar; +static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar) { int mbchar; int char_len; @@ -2224,10 +2122,7 @@ struct prt_ps_charset_S **pp_mbchar; return FALSE; } -int mch_print_init(psettings, jobname, forceit) -prt_settings_T *psettings; -char_u *jobname; -int forceit UNUSED; +int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) { int i; char *paper_name; @@ -2510,8 +2405,7 @@ int forceit UNUSED; return OK; } -static int prt_add_resource(resource) -struct prt_ps_resource_S *resource; +static int prt_add_resource(struct prt_ps_resource_S *resource) { FILE* fd_resource; char_u resource_buffer[512]; @@ -2553,8 +2447,7 @@ struct prt_ps_resource_S *resource; return TRUE; } -int mch_print_begin(psettings) -prt_settings_T *psettings; +int mch_print_begin(prt_settings_T *psettings) { time_t now; int bbox[4]; @@ -2925,8 +2818,7 @@ theend: return retval; } -void mch_print_end(psettings) -prt_settings_T *psettings; +void mch_print_end(prt_settings_T *psettings) { prt_dsc_noarg("Trailer"); @@ -2960,7 +2852,7 @@ prt_settings_T *psettings; mch_print_cleanup(); } -int mch_print_end_page() { +int mch_print_end_page(void) { prt_flush_buffer(); prt_write_string("re sp\n"); @@ -2970,8 +2862,7 @@ int mch_print_end_page() { return !prt_file_error; } -int mch_print_begin_page(str) -char_u *str UNUSED; +int mch_print_begin_page(char_u *str) { int page_num[2]; @@ -3008,16 +2899,14 @@ char_u *str UNUSED; return !prt_file_error; } -int mch_print_blank_page() { +int mch_print_blank_page(void) { return mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE; } static float prt_pos_x = 0; static float prt_pos_y = 0; -void mch_print_start_line(margin, page_line) -int margin; -int page_line; +void mch_print_start_line(int margin, int page_line) { prt_pos_x = prt_left_margin; if (margin) @@ -3031,9 +2920,7 @@ int page_line; prt_half_width = FALSE; } -int mch_print_text_out(p, len) -char_u *p; -int len UNUSED; +int mch_print_text_out(char_u *p, int len) { int need_break; char_u ch; @@ -3214,10 +3101,7 @@ int len UNUSED; return need_break; } -void mch_print_set_font(iBold, iItalic, iUnderline) -int iBold; -int iItalic; -int iUnderline; +void mch_print_set_font(int iBold, int iItalic, int iUnderline) { int font = 0; @@ -3238,16 +3122,14 @@ int iUnderline; } } -void mch_print_set_bg(bgcol) -long_u bgcol; +void mch_print_set_bg(long_u bgcol) { prt_bgcol = (int)bgcol; prt_attribute_change = TRUE; prt_need_bgcol = TRUE; } -void mch_print_set_fg(fgcol) -long_u fgcol; +void mch_print_set_fg(long_u fgcol) { if (fgcol != (long_u)prt_fgcol) { prt_fgcol = (int)fgcol; diff --git a/src/hashtab.c b/src/hashtab.c index 4bab277f78..2682885113 100644 --- a/src/hashtab.c +++ b/src/hashtab.c @@ -40,8 +40,7 @@ static int hash_may_resize __ARGS((hashtab_T *ht, int minitems)); /* * Initialize an empty hash table. */ -void hash_init(ht) -hashtab_T *ht; +void hash_init(hashtab_T *ht) { /* This zeroes all "ht_" entries and all the "hi_key" in "ht_smallarray". */ vim_memset(ht, 0, sizeof(hashtab_T)); @@ -53,8 +52,7 @@ hashtab_T *ht; * Free the array of a hash table. Does not free the items it contains! * If "ht" is not freed then you should call hash_init() next! */ -void hash_clear(ht) -hashtab_T *ht; +void hash_clear(hashtab_T *ht) { if (ht->ht_array != ht->ht_smallarray) vim_free(ht->ht_array); @@ -65,9 +63,7 @@ hashtab_T *ht; * have been allocated. "off" is the offset from the start of the allocate * memory to the location of the key (it's always positive). */ -void hash_clear_all(ht, off) -hashtab_T *ht; -int off; +void hash_clear_all(hashtab_T *ht, int off) { long todo; hashitem_T *hi; @@ -90,9 +86,7 @@ int off; * WARNING: The returned pointer becomes invalid when the hashtable is changed * (adding, setting or removing an item)! */ -hashitem_T * hash_find(ht, key) -hashtab_T *ht; -char_u *key; +hashitem_T *hash_find(hashtab_T *ht, char_u *key) { return hash_lookup(ht, key, hash_hash(key)); } @@ -100,10 +94,7 @@ char_u *key; /* * Like hash_find(), but caller computes "hash". */ -hashitem_T * hash_lookup(ht, key, hash) -hashtab_T *ht; -char_u *key; -hash_T hash; +hashitem_T *hash_lookup(hashtab_T *ht, char_u *key, hash_T hash) { hash_T perturb; hashitem_T *freeitem; @@ -163,7 +154,7 @@ hash_T hash; * Useful when trying different hash algorithms. * Called when exiting. */ -void hash_debug_results() { +void hash_debug_results(void) { #ifdef HT_DEBUG fprintf(stderr, "\r\n\r\n\r\n\r\n"); fprintf(stderr, "Number of hashtable lookups: %ld\r\n", hash_count_lookup); @@ -177,9 +168,7 @@ void hash_debug_results() { * Add item with key "key" to hashtable "ht". * Returns FAIL when out of memory or the key is already present. */ -int hash_add(ht, key) -hashtab_T *ht; -char_u *key; +int hash_add(hashtab_T *ht, char_u *key) { hash_T hash = hash_hash(key); hashitem_T *hi; @@ -198,11 +187,7 @@ char_u *key; * "hi" is invalid after this! * Returns OK or FAIL (out of memory). */ -int hash_add_item(ht, hi, key, hash) -hashtab_T *ht; -hashitem_T *hi; -char_u *key; -hash_T hash; +int hash_add_item(hashtab_T *ht, hashitem_T *hi, char_u *key, hash_T hash) { /* If resizing failed before and it fails again we can't add an item. */ if (ht->ht_error && hash_may_resize(ht, 0) == FAIL) @@ -224,9 +209,7 @@ hash_T hash; * hash_lookup(). * The caller must take care of freeing the item itself. */ -void hash_remove(ht, hi) -hashtab_T *ht; -hashitem_T *hi; +void hash_remove(hashtab_T *ht, hashitem_T *hi) { --ht->ht_used; hi->hi_key = HI_KEY_REMOVED; @@ -238,8 +221,7 @@ hashitem_T *hi; * Don't use this when items are to be added! * Must call hash_unlock() later. */ -void hash_lock(ht) -hashtab_T *ht; +void hash_lock(hashtab_T *ht) { ++ht->ht_locked; } @@ -250,8 +232,7 @@ hashtab_T *ht; * Table will be resized (shrink) when necessary. * This must balance a call to hash_lock(). */ -void hash_unlock(ht) -hashtab_T *ht; +void hash_unlock(hashtab_T *ht) { --ht->ht_locked; (void)hash_may_resize(ht, 0); @@ -262,9 +243,11 @@ hashtab_T *ht; * Grow a hashtable when there is not enough empty space. * Returns OK or FAIL (out of memory). */ -static int hash_may_resize(ht, minitems) -hashtab_T *ht; -int minitems; /* minimal number of items */ +static int +hash_may_resize ( + hashtab_T *ht, + int minitems /* minimal number of items */ +) { hashitem_T temparray[HT_INIT_SIZE]; hashitem_T *oldarray, *newarray; @@ -395,8 +378,7 @@ int minitems; /* minimal number of items */ * when exiting. Try that with the current hash algorithm and yours. The * lower the percentage the better. */ -hash_T hash_hash(key) -char_u *key; +hash_T hash_hash(char_u *key) { hash_T hash; char_u *p; diff --git a/src/if_cscope.c b/src/if_cscope.c index 2ef1d61cba..cbdcf6b255 100644 --- a/src/if_cscope.c +++ b/src/if_cscope.c @@ -83,8 +83,7 @@ static cscmd_T cs_cmds[] = { NULL, NULL, NULL, NULL, 0 } }; -static void cs_usage_msg(x) -csid_e x; +static void cs_usage_msg(csid_e x) { (void)EMSG2(_("E560: Usage: cs[cope] %s"), cs_cmds[(int)x].usage); } @@ -101,9 +100,7 @@ static enum { * Function given to ExpandGeneric() to obtain the cscope command * expansion. */ -char_u * get_cscope_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_cscope_name(expand_T *xp, int idx) { int current_idx; int i; @@ -160,10 +157,7 @@ int idx; /* * Handle command line completion for :cscope command. */ -void set_context_in_cscope_cmd(xp, arg, cmdidx) -expand_T *xp; -char_u *arg; -cmdidx_T cmdidx; +void set_context_in_cscope_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx) { char_u *p; @@ -199,9 +193,11 @@ cmdidx_T cmdidx; * Find the command, print help if invalid, and then call the corresponding * command function. */ -static void do_cscope_general(eap, make_split) -exarg_T *eap; -int make_split; /* whether to split window */ +static void +do_cscope_general ( + exarg_T *eap, + int make_split /* whether to split window */ +) { cscmd_T *cmdp; @@ -230,8 +226,7 @@ int make_split; /* whether to split window */ /* * PUBLIC: do_cscope */ -void do_cscope(eap) -exarg_T *eap; +void do_cscope(exarg_T *eap) { do_cscope_general(eap, FALSE); } @@ -241,8 +236,7 @@ exarg_T *eap; * * same as do_cscope, but splits window, too. */ -void do_scscope(eap) -exarg_T *eap; +void do_scscope(exarg_T *eap) { do_cscope_general(eap, TRUE); } @@ -251,8 +245,7 @@ exarg_T *eap; * PUBLIC: do_cstag * */ -void do_cstag(eap) -exarg_T *eap; +void do_cstag(exarg_T *eap) { int ret = FALSE; @@ -319,9 +312,7 @@ exarg_T *eap; * * returns TRUE if eof, FALSE otherwise */ -int cs_fgets(buf, size) -char_u *buf; -int size; +int cs_fgets(char_u *buf, int size) { char *p; @@ -338,7 +329,7 @@ int size; * * called only from do_tag(), when popping the tag stack */ -void cs_free_tags() { +void cs_free_tags(void) { cs_manage_matches(NULL, NULL, -1, Free); } @@ -347,7 +338,7 @@ void cs_free_tags() { * * called from do_tag() */ -void cs_print_tags() { +void cs_print_tags(void) { cs_manage_matches(NULL, NULL, -1, Print); } @@ -378,10 +369,7 @@ void cs_print_tags() { * * Note: All string comparisons are case sensitive! */ -int cs_connection(num, dbpath, ppath) -int num; -char_u *dbpath; -char_u *ppath; +int cs_connection(int num, char_u *dbpath, char_u *ppath) { int i; @@ -439,8 +427,7 @@ char_u *ppath; * * MAXPATHL 256 */ -static int cs_add(eap) -exarg_T *eap UNUSED; +static int cs_add(exarg_T *eap) { char *fname, *ppath, *flags = NULL; @@ -454,8 +441,7 @@ exarg_T *eap UNUSED; return cs_add_common(fname, ppath, flags); } -static void cs_stat_emsg(fname) -char *fname; +static void cs_stat_emsg(char *fname) { char *stat_emsg = _("E563: stat(%s) error: %d"); char *buf = (char *)alloc((unsigned)strlen(stat_emsg) + MAXPATHL + 10); @@ -476,10 +462,12 @@ char *fname; * cs_add() and cs_reset(). i really don't like to do this, but this * routine uses a number of goto statements. */ -static int cs_add_common(arg1, arg2, flags) -char *arg1; /* filename - may contain environment variables */ -char *arg2; /* prepend path - may contain environment variables */ -char *flags; +static int +cs_add_common ( + char *arg1, /* filename - may contain environment variables */ + char *arg2, /* prepend path - may contain environment variables */ + char *flags +) { struct stat statbuf; int ret; @@ -595,11 +583,11 @@ add_err: } /* cs_add_common */ -static int cs_check_for_connections() { +static int cs_check_for_connections(void) { return cs_cnt_connections() > 0; } /* cs_check_for_connections */ -static int cs_check_for_tags() { +static int cs_check_for_tags(void) { return p_tags[0] != NUL && curbuf->b_p_tags != NULL; } /* cs_check_for_tags */ @@ -608,7 +596,7 @@ static int cs_check_for_tags() { * * count the number of cscope connections */ -static int cs_cnt_connections() { +static int cs_cnt_connections(void) { short i; short cnt = 0; @@ -619,8 +607,10 @@ static int cs_cnt_connections() { return cnt; } /* cs_cnt_connections */ -static void cs_reading_emsg(idx) -int idx; /* connection index */ +static void +cs_reading_emsg ( + int idx /* connection index */ +) { EMSGN(_("E262: error reading cscope connection %ld"), idx); } @@ -631,8 +621,7 @@ int idx; /* connection index */ * * count the number of matches for a given cscope connection. */ -static int cs_cnt_matches(idx) -int idx; +static int cs_cnt_matches(int idx) { char *stok; char *buf; @@ -689,9 +678,7 @@ int idx; * * Creates the actual cscope command query from what the user entered. */ -static char * cs_create_cmd(csoption, pattern) -char *csoption; -char *pattern; +static char *cs_create_cmd(char *csoption, char *pattern) { char *cmd; short search; @@ -750,8 +737,7 @@ char *pattern; * This piece of code was taken/adapted from nvi. do we need to add * the BSD license notice? */ -static int cs_create_connection(i) -int i; +static int cs_create_connection(int i) { #ifdef UNIX int to_cs[2], from_cs[2]; @@ -964,8 +950,7 @@ err_closing: * * returns TRUE if we jump to a tag or abort, FALSE if not. */ -static int cs_find(eap) -exarg_T *eap; +static int cs_find(exarg_T *eap) { char *opt, *pat; int i; @@ -1004,13 +989,7 @@ exarg_T *eap; * * common code for cscope find, shared by cs_find() and do_cstag() */ -static int cs_find_common(opt, pat, forceit, verbose, use_ll, cmdline) -char *opt; -char *pat; -int forceit; -int verbose; -int use_ll; -char_u *cmdline; +static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int use_ll, char_u *cmdline) { int i; char *cmd; @@ -1191,8 +1170,7 @@ char_u *cmdline; * * print help */ -static int cs_help(eap) -exarg_T *eap UNUSED; +static int cs_help(exarg_T *eap) { cscmd_T *cmdp = cs_cmds; @@ -1227,8 +1205,7 @@ exarg_T *eap UNUSED; } /* cs_help */ -static void clear_csinfo(i) -int i; +static void clear_csinfo(int i) { csinfo[i].fname = NULL; csinfo[i].ppath = NULL; @@ -1249,7 +1226,7 @@ int i; #ifndef UNIX static char *GetWin32Error __ARGS((void)); -static char * GetWin32Error() { +static char *GetWin32Error(void) { char *msg = NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPSTR)&msg, 0, NULL); @@ -1269,11 +1246,7 @@ static char * GetWin32Error() { * * insert a new cscope database filename into the filelist */ -static int cs_insert_filelist(fname, ppath, flags, sb) -char *fname; -char *ppath; -char *flags; -struct stat *sb UNUSED; +static int cs_insert_filelist(char *fname, char *ppath, char *flags, struct stat *sb) { short i, j; #ifndef UNIX @@ -1425,8 +1398,7 @@ exarg_T *eap; * * nuke em */ -static int cs_kill(eap) -exarg_T *eap UNUSED; +static int cs_kill(exarg_T *eap) { char *stok; short i; @@ -1473,9 +1445,11 @@ exarg_T *eap UNUSED; * * Actually kills a specific cscope connection. */ -static void cs_kill_execute(i, cname) -int i; /* cscope table index */ -char *cname; /* cscope database name */ +static void +cs_kill_execute ( + int i, /* cscope table index */ + char *cname /* cscope database name */ +) { if (p_csverbose) { msg_clr_eos(); @@ -1506,11 +1480,7 @@ char *cname; /* cscope database name */ * would still have to be modified to escape all the special regular expression * characters to comply with ctags formatting. */ -static char * cs_make_vim_style_matches(fname, slno, search, tagstr) -char *fname; -char *slno; -char *search; -char *tagstr; +static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, char *tagstr) { /* vim style is ctags: * @@ -1563,11 +1533,7 @@ char *tagstr; * * Print: prints the tags */ -static char * cs_manage_matches(matches, contexts, totmatches, cmd) -char **matches; -char **contexts; -int totmatches; -mcmd_e cmd; +static char *cs_manage_matches(char **matches, char **contexts, int totmatches, mcmd_e cmd) { static char **mp = NULL; static char **cp = NULL; @@ -1626,14 +1592,7 @@ mcmd_e cmd; * * parse cscope output */ -static char * cs_parse_results(cnumber, buf, bufsize, context, linenumber, - search) -int cnumber; -char *buf; -int bufsize; -char **context; -char **linenumber; -char **search; +static char *cs_parse_results(int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search) { int ch; char *p; @@ -1686,9 +1645,7 @@ char **search; * * write cscope find results to file */ -static void cs_file_results(f, nummatches_a) -FILE *f; -int *nummatches_a; +static void cs_file_results(FILE *f, int *nummatches_a) { int i, j; char *buf; @@ -1741,15 +1698,7 @@ int *nummatches_a; * into ctags format * When there are no matches sets "*matches_p" to NULL. */ -static void cs_fill_results(tagstr, totmatches, nummatches_a, matches_p, - cntxts_p, - matched) -char *tagstr; -int totmatches; -int *nummatches_a; -char ***matches_p; -char ***cntxts_p; -int *matched; +static void cs_fill_results(char *tagstr, int totmatches, int *nummatches_a, char ***matches_p, char ***cntxts_p, int *matched) { int i, j; char *buf; @@ -1819,8 +1768,7 @@ parse_out: /* get the requested path components */ -static char * cs_pathcomponents(path) -char *path; +static char *cs_pathcomponents(char *path) { int i; char *s; @@ -1844,10 +1792,7 @@ char *path; * * called from cs_manage_matches() */ -static void cs_print_tags_priv(matches, cntxts, num_matches) -char **matches; -char **cntxts; -int num_matches; +static void cs_print_tags_priv(char **matches, char **cntxts, int num_matches) { char *buf = NULL; int bufsize = 0; /* Track available bufsize */ @@ -1973,8 +1918,7 @@ int num_matches; * * read a cscope prompt (basically, skip over the ">> ") */ -static int cs_read_prompt(i) -int i; +static int cs_read_prompt(int i) { int ch; char *buf = NULL; /* buffer for possible error message from cscope */ @@ -2065,9 +2009,7 @@ sig_handler SIGDEFARG(sigarg) { * Does the actual free'ing for the cs ptr with an optional flag of whether * or not to free the filename. Called by cs_kill and cs_reset. */ -static void cs_release_csp(i, freefnpp) -int i; -int freefnpp; +static void cs_release_csp(int i, int freefnpp) { /* * Trying to exit normally (not sure whether it is fit to UNIX cscope @@ -2185,8 +2127,7 @@ int freefnpp; * * calls cs_kill on all cscope connections then reinits */ -static int cs_reset(eap) -exarg_T *eap UNUSED; +static int cs_reset(exarg_T *eap) { char **dblist = NULL, **pplist = NULL, **fllist = NULL; int i; @@ -2252,9 +2193,7 @@ exarg_T *eap UNUSED; * ships with Solaris 2.6), the output never has the prefix prepended. * Contrast this with my development system (Digital Unix), which does. */ -static char * cs_resolve_file(i, name) -int i; -char *name; +static char *cs_resolve_file(int i, char *name) { char *fullname; int len; @@ -2307,8 +2246,7 @@ char *name; * * show all cscope connections */ -static int cs_show(eap) -exarg_T *eap UNUSED; +static int cs_show(exarg_T *eap) { short i; if (cs_cnt_connections() == 0) @@ -2340,7 +2278,7 @@ exarg_T *eap UNUSED; * * Only called when VIM exits to quit any cscope sessions. */ -void cs_end() { +void cs_end(void) { int i; for (i = 0; i < csinfo_size; i++) diff --git a/src/main.c b/src/main.c index d073fbe9a9..f6093a5b38 100644 --- a/src/main.c +++ b/src/main.c @@ -116,10 +116,7 @@ static char *(main_errors[]) = }; #ifndef NO_VIM_MAIN /* skip this for unittests */ - int -main(argc, argv) - int argc; - char **argv; + int main(int argc, char **argv) { char_u *fname = NULL; /* file name from command line */ mparm_T params; /* various parameters passed between @@ -539,9 +536,11 @@ main(argc, argv) * Also used to handle ":visual" command after ":global": execute Normal mode * commands, return when entering Ex mode. "noexmode" is TRUE then. */ -void main_loop(cmdwin, noexmode) - int cmdwin; /* TRUE when working in the command-line window */ - int noexmode; /* TRUE when return on entering Ex mode */ +void +main_loop ( + int cmdwin, /* TRUE when working in the command-line window */ + int noexmode /* TRUE when return on entering Ex mode */ +) { oparg_T oa; /* operator arguments */ int previous_got_int = FALSE; /* "got_int" was TRUE */ @@ -748,8 +747,7 @@ void main_loop(cmdwin, noexmode) /* Exit properly */ -void getout(exitval) - int exitval; +void getout(int exitval) { buf_T *buf; win_T *wp; @@ -835,10 +833,12 @@ void getout(exitval) /* * Get a (optional) count for a Vim argument. */ -static int get_number_arg(p, idx, def) - char_u *p; /* pointer to argument */ - int *idx; /* index in argument, is incremented */ - int def; /* default value */ +static int +get_number_arg ( + char_u *p, /* pointer to argument */ + int *idx, /* index in argument, is incremented */ + int def /* default value */ +) { if (vim_isdigit(p[*idx])) { def = atoi((char *)&(p[*idx])); @@ -852,7 +852,7 @@ static int get_number_arg(p, idx, def) /* * Setup to use the current locale (for ctype() and many other things). */ -static void init_locale() { +static void init_locale(void) { setlocale(LC_ALL, ""); # if defined(FEAT_FLOAT) && defined(LC_NUMERIC) @@ -891,8 +891,7 @@ static void init_locale() { * If the next characters are "ex" we start in Ex mode. If it's followed * by "im" use improved Ex mode. */ -static void parse_command_name(parmp) - mparm_T *parmp; +static void parse_command_name(mparm_T *parmp) { char_u *initstr; @@ -961,8 +960,7 @@ static bool parse_string(input, val, len) /* * Scan the command line arguments. */ -static void command_line_scan(parmp) - mparm_T *parmp; +static void command_line_scan(mparm_T *parmp) { int argc = parmp->argc; char **argv = parmp->argv; @@ -1459,10 +1457,7 @@ scripterror: * Many variables are in "params" so that we can pass them to invoked * functions without a lot of arguments. "argc" and "argv" are also * copied, so that they can be changed. */ -static void init_params(paramp, argc, argv) - mparm_T *paramp; - int argc; - char **argv; +static void init_params(mparm_T *paramp, int argc, char **argv) { vim_memset(paramp, 0, sizeof(*paramp)); paramp->argc = argc; @@ -1475,8 +1470,7 @@ static void init_params(paramp, argc, argv) /* * Initialize global startuptime file if "--startuptime" passed as an argument. */ -static void init_startuptime(paramp) - mparm_T *paramp; +static void init_startuptime(mparm_T *paramp) { #ifdef STARTUPTIME int i; @@ -1495,7 +1489,7 @@ static void init_startuptime(paramp) * Allocate space for the generic buffers (needed for set_init_1() and * EMSG2()). */ -static void allocate_generic_buffers() +static void allocate_generic_buffers(void) { if ((IObuff = alloc(IOSIZE)) == NULL || (NameBuff = alloc(MAXPATHL)) == NULL) @@ -1509,8 +1503,7 @@ static void allocate_generic_buffers() * (needed for :! to * work). mch_check_win() will also handle the -d or * -dev argument. */ -static void check_and_set_isatty(paramp) - mparm_T *paramp; +static void check_and_set_isatty(mparm_T *paramp) { paramp->stdout_isatty = (mch_check_win(paramp->argc, paramp->argv) != FAIL); TIME_MSG("window checked"); @@ -1519,8 +1512,7 @@ static void check_and_set_isatty(paramp) /* * Get filename from command line, given that there is one. */ -static char_u* get_fname(parmp) - mparm_T *parmp; +static char_u *get_fname(mparm_T *parmp) { #if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) /* @@ -1541,8 +1533,7 @@ static char_u* get_fname(parmp) /* * Decide about window layout for diff mode after reading vimrc. */ -static void set_window_layout(paramp) - mparm_T *paramp; +static void set_window_layout(mparm_T *paramp) { if (paramp->diff_mode && paramp->window_layout == 0) { if (diffopt_horizontal()) @@ -1556,7 +1547,7 @@ static void set_window_layout(paramp) * Read all the plugin files. * Only when compiled with +eval, since most plugins need it. */ -static void load_plugins() +static void load_plugins(void) { if (p_lpl) { source_runtime((char_u *)"plugin/**/*.vim", TRUE); @@ -1568,8 +1559,7 @@ static void load_plugins() * "-q errorfile": Load the error file now. * If the error file can't be read, exit before doing anything else. */ -static void handle_quickfix(paramp) - mparm_T *paramp; +static void handle_quickfix(mparm_T *paramp) { if (paramp->edit_type == EDIT_QF) { if (paramp->use_ef != NULL) @@ -1588,8 +1578,7 @@ static void handle_quickfix(paramp) * Need to jump to the tag before executing the '-c command'. * Makes "vim -c '/return' -t main" work. */ -static void handle_tag(tagname) - char_u *tagname; +static void handle_tag(char_u *tagname) { if (tagname != NULL) { #if defined(HAS_SWAP_EXISTS_ACTION) @@ -1612,8 +1601,7 @@ static void handle_tag(tagname) * Print a warning if stdout is not a terminal. * When starting in Ex mode and commands come from a file, set Silent mode. */ -static void check_tty(parmp) - mparm_T *parmp; +static void check_tty(mparm_T *parmp) { int input_isatty; /* is active input a terminal? */ @@ -1637,7 +1625,7 @@ static void check_tty(parmp) /* * Read text from stdin. */ -static void read_stdin() { +static void read_stdin(void) { int i; #if defined(HAS_SWAP_EXISTS_ACTION) @@ -1667,8 +1655,7 @@ static void read_stdin() { * Create the requested number of windows and edit buffers in them. * Also does recovery if "recoverymode" set. */ -static void create_windows(parmp) - mparm_T *parmp UNUSED; +static void create_windows(mparm_T *parmp) { int dorewind; int done = 0; @@ -1783,8 +1770,7 @@ static void create_windows(parmp) * If opened more than one window, start editing files in the other * windows. make_windows() has already opened the windows. */ -static void edit_buffers(parmp) - mparm_T *parmp; +static void edit_buffers(mparm_T *parmp) { int arg_idx; /* index in argument list */ int i; @@ -1886,8 +1872,7 @@ static void edit_buffers(parmp) /* * Execute the commands from --cmd arguments "cmds[cnt]". */ -static void exe_pre_commands(parmp) - mparm_T *parmp; +static void exe_pre_commands(mparm_T *parmp) { char_u **cmds = parmp->pre_commands; int cnt = parmp->n_pre_commands; @@ -1908,8 +1893,7 @@ static void exe_pre_commands(parmp) /* * Execute "+", "-c" and "-S" arguments. */ -static void exe_commands(parmp) - mparm_T *parmp; +static void exe_commands(mparm_T *parmp) { int i; @@ -1945,8 +1929,7 @@ static void exe_commands(parmp) /* * Source startup scripts. */ -static void source_startup_scripts(parmp) - mparm_T *parmp; +static void source_startup_scripts(mparm_T *parmp) { int i; @@ -2075,7 +2058,7 @@ static void source_startup_scripts(parmp) /* * Setup to start using the GUI. Exit with an error when not available. */ -static void main_start_gui() { +static void main_start_gui(void) { mch_errmsg(_(e_nogvim)); mch_errmsg("\n"); mch_exit(2); @@ -2087,9 +2070,11 @@ static void main_start_gui() { * Get an environment variable, and execute it as Ex commands. * Returns FAIL if the environment variable was not executed, OK otherwise. */ -int process_env(env, is_viminit) - char_u *env; - int is_viminit; /* when TRUE, called for VIMINIT */ +int +process_env ( + char_u *env, + int is_viminit /* when TRUE, called for VIMINIT */ +) { char_u *initstr; char_u *save_sourcing_name; @@ -2120,8 +2105,7 @@ int process_env(env, is_viminit) * Used for ".vimrc" and ".exrc". * Use both stat() and lstat() for extra security. */ -static int file_owned(fname) - char *fname; +static int file_owned(char *fname) { struct stat s; # ifdef UNIX @@ -2141,9 +2125,11 @@ static int file_owned(fname) /* * Give an error message main_errors["n"] and exit. */ -static void mainerr(n, str) - int n; /* one of the ME_ defines */ - char_u *str; /* extra argument or NULL */ +static void +mainerr ( + int n, /* one of the ME_ defines */ + char_u *str /* extra argument or NULL */ +) { #if defined(UNIX) || defined(__EMX__) || defined(VMS) reset_signals(); /* kill us with CTRL-C here, if you like */ @@ -2162,8 +2148,7 @@ static void mainerr(n, str) mch_exit(1); } -void mainerr_arg_missing(str) - char_u *str; +void mainerr_arg_missing(char_u *str) { mainerr(ME_ARG_MISSING, str); } @@ -2172,8 +2157,7 @@ void mainerr_arg_missing(str) /* * print a message with three spaces prepended and '\n' appended. */ -static void main_msg(s) - char *s; +static void main_msg(char *s) { mch_msg(" "); mch_msg(s); @@ -2183,7 +2167,7 @@ static void main_msg(s) /* * Print messages for "vim -h" or "vim --help" and exit. */ -static void usage() { +static void usage(void) { int i; static char *(use[]) = { @@ -2272,7 +2256,7 @@ static void usage() { * When "Quit" selected, exit Vim. * When "Recover" selected, recover the file. */ -static void check_swap_exists_action() { +static void check_swap_exists_action(void) { if (swap_exists_action == SEA_QUIT) getout(1); handle_swap_exists(NULL); @@ -2292,8 +2276,7 @@ static struct timeval prev_timeval; * Save the previous time before doing something that could nest. * set "*tv_rel" to the time elapsed so far. */ -void time_push(tv_rel, tv_start) - void *tv_rel, *tv_start; +void time_push(void *tv_rel, void *tv_start) { *((struct timeval *)tv_rel) = prev_timeval; gettimeofday(&prev_timeval, NULL); @@ -2314,8 +2297,10 @@ void time_push(tv_rel, tv_start) * Note: The arguments are (void *) to avoid trouble with systems that don't * have struct timeval. */ -void time_pop(tp) - void *tp; /* actually (struct timeval *) */ +void +time_pop ( + void *tp /* actually (struct timeval *) */ +) { prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec; prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec; @@ -2325,9 +2310,7 @@ void time_pop(tp) } } -static void time_diff(then, now) - struct timeval *then; - struct timeval *now; +static void time_diff(struct timeval *then, struct timeval *now) { long usec; long msec; @@ -2338,10 +2321,12 @@ static void time_diff(then, now) fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L); } -void time_msg(mesg, tv_start) - char *mesg; - void *tv_start; /* only for do_source: start time; actually +void +time_msg ( + char *mesg, + void *tv_start /* only for do_source: start time; actually (struct timeval *) */ +) { static struct timeval start; struct timeval now; diff --git a/src/mark.c b/src/mark.c index 67d962dc9e..67888912d8 100644 --- a/src/mark.c +++ b/src/mark.c @@ -38,8 +38,7 @@ static void write_one_filemark __ARGS((FILE *fp, xfmark_T *fm, int c1, int c2)); * Set named mark "c" at current cursor position. * Returns OK on success, FAIL if bad name given. */ -int setmark(c) -int c; +int setmark(int c) { return setmark_pos(c, &curwin->w_cursor, curbuf->b_fnum); } @@ -49,10 +48,7 @@ int c; * When "c" is upper case use file "fnum". * Returns OK on success, FAIL if bad name given. */ -int setmark_pos(c, pos, fnum) -int c; -pos_T *pos; -int fnum; +int setmark_pos(int c, pos_T *pos, int fnum) { int i; @@ -120,7 +116,7 @@ int fnum; * Set the previous context mark to the current position and add it to the * jump list. */ -void setpcmark() { +void setpcmark(void) { int i; xfmark_T *fm; #ifdef JUMPLIST_ROTATE @@ -172,7 +168,7 @@ void setpcmark() { * context will only be changed if the cursor moved to a different line. * If pcmark was deleted (with "dG") the previous mark is restored. */ -void checkpcmark() { +void checkpcmark(void) { if (curwin->w_prev_pcmark.lnum != 0 && (equalpos(curwin->w_pcmark, curwin->w_cursor) || curwin->w_pcmark.lnum == 0)) { @@ -184,8 +180,7 @@ void checkpcmark() { /* * move "count" positions in the jump list (count may be negative) */ -pos_T * movemark(count) -int count; +pos_T *movemark(int count) { pos_T *pos; xfmark_T *jmp; @@ -238,8 +233,7 @@ int count; /* * Move "count" positions in the changelist (count may be negative). */ -pos_T * movechangelist(count) -int count; +pos_T *movechangelist(int count) { int n; @@ -272,26 +266,17 @@ int count; * - NULL if there is no mark called 'c'. * - -1 if mark is in other file and jumped there (only if changefile is TRUE) */ -pos_T * getmark_buf(buf, c, changefile) -buf_T *buf; -int c; -int changefile; +pos_T *getmark_buf(buf_T *buf, int c, int changefile) { return getmark_buf_fnum(buf, c, changefile, NULL); } -pos_T * getmark(c, changefile) -int c; -int changefile; +pos_T *getmark(int c, int changefile) { return getmark_buf_fnum(curbuf, c, changefile, NULL); } -pos_T * getmark_buf_fnum(buf, c, changefile, fnum) -buf_T *buf; -int c; -int changefile; -int *fnum; +pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum) { pos_T *posp; pos_T *startp, *endp; @@ -404,10 +389,12 @@ int *fnum; * * Returns pointer to pos_T of the next mark or NULL if no mark is found. */ -pos_T * getnextmark(startpos, dir, begin_line) -pos_T *startpos; /* where to start */ -int dir; /* direction for search */ -int begin_line; +pos_T * +getnextmark ( + pos_T *startpos, /* where to start */ + int dir, /* direction for search */ + int begin_line +) { int i; pos_T *result = NULL; @@ -446,8 +433,7 @@ int begin_line; * This is used for marks obtained from the .viminfo file. It's postponed * until the mark is used to avoid a long startup delay. */ -static void fname2fnum(fm) -xfmark_T *fm; +static void fname2fnum(xfmark_T *fm) { char_u *p; @@ -483,8 +469,7 @@ xfmark_T *fm; * May replace the name with an fnum. * Used for marks that come from the .viminfo file. */ -void fmarks_check_names(buf) -buf_T *buf; +void fmarks_check_names(buf_T *buf) { char_u *name; int i; @@ -509,10 +494,7 @@ buf_T *buf; vim_free(name); } -static void fmarks_check_one(fm, name, buf) -xfmark_T *fm; -char_u *name; -buf_T *buf; +static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf) { if (fm->fmark.fnum == 0 && fm->fname != NULL @@ -527,8 +509,7 @@ buf_T *buf; * Check a if a position from a mark is valid. * Give and error message and return FAIL if not. */ -int check_mark(pos) -pos_T *pos; +int check_mark(pos_T *pos) { if (pos == NULL) { EMSG(_(e_umark)); @@ -553,8 +534,7 @@ pos_T *pos; * * Used mainly when trashing the entire buffer during ":e" type commands */ -void clrallmarks(buf) -buf_T *buf; +void clrallmarks(buf_T *buf) { static int i = -1; @@ -581,9 +561,7 @@ buf_T *buf; * When it's in the current buffer, return the text at the mark. * Returns an allocated string. */ -char_u * fm_getname(fmark, lead_len) -fmark_T *fmark; -int lead_len; +char_u *fm_getname(fmark_T *fmark, int lead_len) { if (fmark->fnum == curbuf->b_fnum) /* current buffer */ return mark_line(&(fmark->mark), lead_len); @@ -594,9 +572,7 @@ int lead_len; * Return the line at mark "mp". Truncate to fit in window. * The returned string has been allocated. */ -static char_u * mark_line(mp, lead_len) -pos_T *mp; -int lead_len; +static char_u *mark_line(pos_T *mp, int lead_len) { char_u *s, *p; int len; @@ -620,8 +596,7 @@ int lead_len; /* * print the marks */ -void do_marks(eap) -exarg_T *eap; +void do_marks(exarg_T *eap) { char_u *arg = eap->arg; int i; @@ -656,12 +631,14 @@ exarg_T *eap; show_one_mark(-1, arg, NULL, NULL, FALSE); } -static void show_one_mark(c, arg, p, name, current) -int c; -char_u *arg; -pos_T *p; -char_u *name; -int current; /* in current file */ +static void +show_one_mark ( + int c, + char_u *arg, + pos_T *p, + char_u *name, + int current /* in current file */ +) { static int did_title = FALSE; int mustfree = FALSE; @@ -706,8 +683,7 @@ int current; /* in current file */ /* * ":delmarks[!] [marks]" */ -void ex_delmarks(eap) -exarg_T *eap; +void ex_delmarks(exarg_T *eap) { char_u *p; int from, to; @@ -778,8 +754,7 @@ exarg_T *eap; /* * print the jumplist */ -void ex_jumps(eap) -exarg_T *eap UNUSED; +void ex_jumps(exarg_T *eap) { int i; char_u *name; @@ -822,8 +797,7 @@ exarg_T *eap UNUSED; /* * print the changelist */ -void ex_changes(eap) -exarg_T *eap UNUSED; +void ex_changes(exarg_T *eap) { int i; char_u *name; @@ -896,11 +870,7 @@ exarg_T *eap UNUSED; * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0); * or: mark_adjust(56, 55, MAXLNUM, 2); */ -void mark_adjust(line1, line2, amount, amount_after) -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) { int i; int fnum = curbuf->b_fnum; @@ -1043,11 +1013,7 @@ long amount_after; * "lnum_amount" to the line number and add "col_amount" to the column * position. */ -void mark_col_adjust(lnum, mincol, lnum_amount, col_amount) -linenr_T lnum; -colnr_T mincol; -long lnum_amount; -long col_amount; +void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount) { int i; int fnum = curbuf->b_fnum; @@ -1118,7 +1084,7 @@ long col_amount; * When deleting lines, this may create duplicate marks in the * jumplist. They will be removed here for the current window. */ -static void cleanup_jumplist() { +static void cleanup_jumplist(void) { int i; int from, to; @@ -1146,9 +1112,7 @@ static void cleanup_jumplist() { /* * Copy the jumplist from window "from" to window "to". */ -void copy_jumplist(from, to) -win_T *from; -win_T *to; +void copy_jumplist(win_T *from, win_T *to) { int i; @@ -1164,8 +1128,7 @@ win_T *to; /* * Free items in the jumplist of window "wp". */ -void free_jumplist(wp) -win_T *wp; +void free_jumplist(win_T *wp) { int i; @@ -1173,15 +1136,14 @@ win_T *wp; vim_free(wp->w_jumplist[i].fname); } -void set_last_cursor(win) -win_T *win; +void set_last_cursor(win_T *win) { if (win->w_buffer != NULL) win->w_buffer->b_last_cursor = win->w_cursor; } #if defined(EXITFREE) || defined(PROTO) -void free_all_marks() { +void free_all_marks(void) { int i; for (i = 0; i < NMARKS + EXTRA_MARKS; i++) @@ -1191,9 +1153,7 @@ void free_all_marks() { #endif -int read_viminfo_filemark(virp, force) -vir_T *virp; -int force; +int read_viminfo_filemark(vir_T *virp, int force) { char_u *str; xfmark_T *fm; @@ -1239,8 +1199,7 @@ int force; return vim_fgets(virp->vir_line, LSIZE, virp->vir_fd); } -void write_viminfo_filemarks(fp) -FILE *fp; +void write_viminfo_filemarks(FILE *fp) { int i; char_u *name; @@ -1295,11 +1254,7 @@ FILE *fp; } } -static void write_one_filemark(fp, fm, c1, c2) -FILE *fp; -xfmark_T *fm; -int c1; -int c2; +static void write_one_filemark(FILE *fp, xfmark_T *fm, int c1, int c2) { char_u *name; @@ -1323,8 +1278,7 @@ int c2; /* * Return TRUE if "name" is on removable media (depending on 'viminfo'). */ -int removable(name) -char_u *name; +int removable(char_u *name) { char_u *p; char_u part[51]; @@ -1354,8 +1308,7 @@ static void write_one_mark __ARGS((FILE *fp_out, int c, pos_T *pos)); * Write all the named marks for all buffers. * Return the number of buffers for which marks have been written. */ -int write_viminfo_marks(fp_out) -FILE *fp_out; +int write_viminfo_marks(FILE *fp_out) { int count; buf_T *buf; @@ -1409,10 +1362,7 @@ FILE *fp_out; return count; } -static void write_one_mark(fp_out, c, pos) -FILE *fp_out; -int c; -pos_T *pos; +static void write_one_mark(FILE *fp_out, int c, pos_T *pos) { if (pos->lnum != 0) fprintf(fp_out, "\t%c\t%ld\t%d\n", c, (long)pos->lnum, (int)pos->col); @@ -1424,12 +1374,7 @@ pos_T *pos; * fp_out == NULL && (flags & VIF_WANT_MARKS): read marks for curbuf only * fp_out == NULL && (flags & VIF_GET_OLDFILES | VIF_FORCEIT): fill v:oldfiles */ -void copy_viminfo_marks(virp, fp_out, count, eof, flags) -vir_T *virp; -FILE *fp_out; -int count; -int eof; -int flags; +void copy_viminfo_marks(vir_T *virp, FILE *fp_out, int count, int eof, int flags) { char_u *line = virp->vir_line; buf_T *buf; diff --git a/src/mbyte.c b/src/mbyte.c index 8b7abe15ee..dfbaf29f1b 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -380,8 +380,7 @@ enc_alias_table[] = * Find encoding "name" in the list of canonical encoding names. * Returns -1 if not found. */ -static int enc_canon_search(name) -char_u *name; +static int enc_canon_search(char_u *name) { int i; @@ -397,8 +396,7 @@ char_u *name; * Find canonical encoding "name" in the list and return its properties. * Returns 0 if not found. */ -int enc_canon_props(name) -char_u *name; +int enc_canon_props(char_u *name) { int i; @@ -445,7 +443,7 @@ char_u * mb_init() { output_conv.vc_type = CONV_NONE; return NULL; } else if (STRNCMP(p_enc, "8bit-", 5) == 0 - || STRNCMP(p_enc, "iso-8859-", 9) == 0) { + || STRNCMP(p_enc, "iso-8859-", 9) == 0) { /* Accept any "8bit-" or "iso-8859-" name. */ enc_unicode = 0; enc_utf8 = FALSE; @@ -484,7 +482,7 @@ char_u * mb_init() { /* Detect an encoding that uses latin1 characters. */ enc_latin1like = (enc_utf8 || STRCMP(p_enc, "latin1") == 0 - || STRCMP(p_enc, "iso-8859-15") == 0); + || STRCMP(p_enc, "iso-8859-15") == 0); /* * Set the function pointers. @@ -651,7 +649,7 @@ int bomb_size() { } else if (STRCMP(curbuf->b_p_fenc, "utf-8") == 0) n = 3; else if (STRNCMP(curbuf->b_p_fenc, "ucs-2", 5) == 0 - || STRNCMP(curbuf->b_p_fenc, "utf-16", 6) == 0) + || STRNCMP(curbuf->b_p_fenc, "utf-16", 6) == 0) n = 2; else if (STRNCMP(curbuf->b_p_fenc, "ucs-4", 5) == 0) n = 4; @@ -662,8 +660,7 @@ int bomb_size() { /* * Remove all BOM from "s" by moving remaining text. */ -void remove_bom(s) -char_u *s; +void remove_bom(char_u *s) { if (enc_utf8) { char_u *p = s; @@ -684,15 +681,12 @@ char_u *s; * 2 for an (ASCII) word character * >2 for other word characters */ -int mb_get_class(p) -char_u *p; +int mb_get_class(char_u *p) { return mb_get_class_buf(p, curbuf); } -int mb_get_class_buf(p, buf) -char_u *p; -buf_T *buf; +int mb_get_class_buf(char_u *p, buf_T *buf) { if (MB_BYTE2LEN(p[0]) == 1) { if (p[0] == NUL || vim_iswhite(p[0])) @@ -712,143 +706,141 @@ buf_T *buf; * Get class of a double-byte character. This always returns 3 or bigger. * TODO: Should return 1 for punctuation. */ -int dbcs_class(lead, trail) -unsigned lead; -unsigned trail; +int dbcs_class(unsigned lead, unsigned trail) { switch (enc_dbcs) { - /* please add classify routine for your language in here */ - - case DBCS_JPNU: /* ? */ - case DBCS_JPN: - { - /* JIS code classification */ - unsigned char lb = lead; - unsigned char tb = trail; - - /* convert process code to JIS */ - /* - * XXX: Code page identification can not use with all - * system! So, some other encoding information - * will be needed. - * In japanese: SJIS,EUC,UNICODE,(JIS) - * Note that JIS-code system don't use as - * process code in most system because it uses - * escape sequences(JIS is context depend encoding). - */ - /* assume process code is JAPANESE-EUC */ - lb &= 0x7f; - tb &= 0x7f; - /* exceptions */ - switch (lb << 8 | tb) { - case 0x2121: /* ZENKAKU space */ - return 0; - case 0x2122: /* TOU-TEN (Japanese comma) */ - case 0x2123: /* KU-TEN (Japanese period) */ - case 0x2124: /* ZENKAKU comma */ - case 0x2125: /* ZENKAKU period */ - return 1; - case 0x213c: /* prolongedsound handled as KATAKANA */ - return 13; - } - /* sieved by KU code */ - switch (lb) { - case 0x21: - case 0x22: - /* special symbols */ - return 10; - case 0x23: - /* alpha-numeric */ - return 11; - case 0x24: - /* hiragana */ - return 12; - case 0x25: - /* katakana */ - return 13; - case 0x26: - /* greek */ - return 14; - case 0x27: - /* russian */ - return 15; - case 0x28: - /* lines */ - return 16; - default: - /* kanji */ - return 17; - } - } - - case DBCS_KORU: /* ? */ - case DBCS_KOR: - { - /* KS code classification */ - unsigned char c1 = lead; - unsigned char c2 = trail; - - /* - * 20 : Hangul - * 21 : Hanja - * 22 : Symbols - * 23 : Alpha-numeric/Roman Letter (Full width) - * 24 : Hangul Letter(Alphabet) - * 25 : Roman Numeral/Greek Letter - * 26 : Box Drawings - * 27 : Unit Symbols - * 28 : Circled/Parenthesized Letter - * 29 : Hiragana/Katakana - * 30 : Cyrillic Letter - */ + /* please add classify routine for your language in here */ + + case DBCS_JPNU: /* ? */ + case DBCS_JPN: + { + /* JIS code classification */ + unsigned char lb = lead; + unsigned char tb = trail; + + /* convert process code to JIS */ + /* + * XXX: Code page identification can not use with all + * system! So, some other encoding information + * will be needed. + * In japanese: SJIS,EUC,UNICODE,(JIS) + * Note that JIS-code system don't use as + * process code in most system because it uses + * escape sequences(JIS is context depend encoding). + */ + /* assume process code is JAPANESE-EUC */ + lb &= 0x7f; + tb &= 0x7f; + /* exceptions */ + switch (lb << 8 | tb) { + case 0x2121: /* ZENKAKU space */ + return 0; + case 0x2122: /* TOU-TEN (Japanese comma) */ + case 0x2123: /* KU-TEN (Japanese period) */ + case 0x2124: /* ZENKAKU comma */ + case 0x2125: /* ZENKAKU period */ + return 1; + case 0x213c: /* prolongedsound handled as KATAKANA */ + return 13; + } + /* sieved by KU code */ + switch (lb) { + case 0x21: + case 0x22: + /* special symbols */ + return 10; + case 0x23: + /* alpha-numeric */ + return 11; + case 0x24: + /* hiragana */ + return 12; + case 0x25: + /* katakana */ + return 13; + case 0x26: + /* greek */ + return 14; + case 0x27: + /* russian */ + return 15; + case 0x28: + /* lines */ + return 16; + default: + /* kanji */ + return 17; + } + } - if (c1 >= 0xB0 && c1 <= 0xC8) - /* Hangul */ - return 20; - - else if (c1 >= 0xCA && c1 <= 0xFD) - /* Hanja */ - return 21; - else switch (c1) { - case 0xA1: - case 0xA2: - /* Symbols */ - return 22; - case 0xA3: - /* Alpha-numeric */ - return 23; - case 0xA4: - /* Hangul Letter(Alphabet) */ - return 24; - case 0xA5: - /* Roman Numeral/Greek Letter */ - return 25; - case 0xA6: - /* Box Drawings */ - return 26; - case 0xA7: - /* Unit Symbols */ - return 27; - case 0xA8: - case 0xA9: - if (c2 <= 0xAF) - return 25; /* Roman Letter */ - else if (c2 >= 0xF6) - return 22; /* Symbols */ - else - /* Circled/Parenthesized Letter */ - return 28; - case 0xAA: - case 0xAB: - /* Hiragana/Katakana */ - return 29; - case 0xAC: - /* Cyrillic Letter */ - return 30; + case DBCS_KORU: /* ? */ + case DBCS_KOR: + { + /* KS code classification */ + unsigned char c1 = lead; + unsigned char c2 = trail; + + /* + * 20 : Hangul + * 21 : Hanja + * 22 : Symbols + * 23 : Alpha-numeric/Roman Letter (Full width) + * 24 : Hangul Letter(Alphabet) + * 25 : Roman Numeral/Greek Letter + * 26 : Box Drawings + * 27 : Unit Symbols + * 28 : Circled/Parenthesized Letter + * 29 : Hiragana/Katakana + * 30 : Cyrillic Letter + */ + + if (c1 >= 0xB0 && c1 <= 0xC8) + /* Hangul */ + return 20; + + else if (c1 >= 0xCA && c1 <= 0xFD) + /* Hanja */ + return 21; + else switch (c1) { + case 0xA1: + case 0xA2: + /* Symbols */ + return 22; + case 0xA3: + /* Alpha-numeric */ + return 23; + case 0xA4: + /* Hangul Letter(Alphabet) */ + return 24; + case 0xA5: + /* Roman Numeral/Greek Letter */ + return 25; + case 0xA6: + /* Box Drawings */ + return 26; + case 0xA7: + /* Unit Symbols */ + return 27; + case 0xA8: + case 0xA9: + if (c2 <= 0xAF) + return 25; /* Roman Letter */ + else if (c2 >= 0xF6) + return 22; /* Symbols */ + else + /* Circled/Parenthesized Letter */ + return 28; + case 0xAA: + case 0xAB: + /* Hiragana/Katakana */ + return 29; + case 0xAC: + /* Cyrillic Letter */ + return 30; + } } - } - default: - break; + default: + break; } return 3; } @@ -858,14 +850,12 @@ unsigned trail; * Return length in bytes of character "c". * Returns 1 for a single-byte character. */ -int latin_char2len(c) -int c UNUSED; +int latin_char2len(int c) { return 1; } -static int dbcs_char2len(c) -int c; +static int dbcs_char2len(int c) { if (c >= 0x100) return 2; @@ -877,17 +867,13 @@ int c; * Convert a character to its bytes. * Returns the length in bytes. */ -int latin_char2bytes(c, buf) -int c; -char_u *buf; +int latin_char2bytes(int c, char_u *buf) { buf[0] = c; return 1; } -static int dbcs_char2bytes(c, buf) -int c; -char_u *buf; +static int dbcs_char2bytes(int c, char_u *buf) { if (c >= 0x100) { buf[0] = (unsigned)c >> 8; @@ -908,14 +894,12 @@ char_u *buf; * For UTF-8 this includes following composing characters. * Returns 0 when *p is NUL. */ -int latin_ptr2len(p) -char_u *p; +int latin_ptr2len(char_u *p) { return MB_BYTE2LEN(*p); } -static int dbcs_ptr2len(p) -char_u *p; +static int dbcs_ptr2len(char_u *p) { int len; @@ -932,18 +916,14 @@ char_u *p; * Returns 0 for an empty string. * Returns 1 for an illegal char or an incomplete byte sequence. */ -int latin_ptr2len_len(p, size) -char_u *p; -int size; +int latin_ptr2len_len(char_u *p, int size) { if (size < 1 || *p == NUL) return 0; return 1; } -static int dbcs_ptr2len_len(p, size) -char_u *p; -int size; +static int dbcs_ptr2len_len(char_u *p, int size) { int len; @@ -967,10 +947,7 @@ static int intable __ARGS((struct interval *table, size_t size, int c)); /* * Return TRUE if "c" is in "table[size / sizeof(struct interval)]". */ -static int intable(table, size, c) -struct interval *table; -size_t size; -int c; +static int intable(struct interval *table, size_t size, int c) { int mid, bot, top; @@ -1000,8 +977,7 @@ int c; * When p_ambw is "double", return 2 for a character with East Asian Width * class 'A'(mbiguous). */ -int utf_char2cells(c) -int c; +int utf_char2cells(int c) { /* Sorted list of non-overlapping intervals of East Asian double width * characters, generated with ../runtime/tools/unicode.vim. */ @@ -1267,14 +1243,12 @@ int c; * Return the number of display cells character at "*p" occupies. * This doesn't take care of unprintable characters, use ptr2cells() for that. */ -int latin_ptr2cells(p) -char_u *p UNUSED; +int latin_ptr2cells(char_u *p) { return 1; } -int utf_ptr2cells(p) -char_u *p; +int utf_ptr2cells(char_u *p) { int c; @@ -1292,8 +1266,7 @@ char_u *p; return 1; } -int dbcs_ptr2cells(p) -char_u *p; +int dbcs_ptr2cells(char_u *p) { /* Number of cells is equal to number of bytes, except for euc-jp when * the first byte is 0x8e. */ @@ -1307,16 +1280,12 @@ char_u *p; * Like mb_ptr2cells(), but limit string length to "size". * For an empty string or truncated character returns 1. */ -int latin_ptr2cells_len(p, size) -char_u *p UNUSED; -int size UNUSED; +int latin_ptr2cells_len(char_u *p, int size) { return 1; } -static int utf_ptr2cells_len(p, size) -char_u *p; -int size; +static int utf_ptr2cells_len(char_u *p, int size) { int c; @@ -1336,9 +1305,7 @@ int size; return 1; } -static int dbcs_ptr2cells_len(p, size) -char_u *p; -int size; +static int dbcs_ptr2cells_len(char_u *p, int size) { /* Number of cells is equal to number of bytes, except for euc-jp when * the first byte is 0x8e. */ @@ -1352,14 +1319,12 @@ int size; * Return the number of display cells character "c" occupies. * Only takes care of multi-byte chars, not "^C" and such. */ -int latin_char2cells(c) -int c UNUSED; +int latin_char2cells(int c) { return 1; } -static int dbcs_char2cells(c) -int c; +static int dbcs_char2cells(int c) { /* Number of cells is equal to number of bytes, except for euc-jp when * the first byte is 0x8e. */ @@ -1373,9 +1338,7 @@ int c; * Return the number of cells occupied by string "p". * Stop at a NUL character. When "len" >= 0 stop at character "p[len]". */ -int mb_string2cells(p, len) -char_u *p; -int len; +int mb_string2cells(char_u *p, int len) { int i; int clen = 0; @@ -1390,16 +1353,12 @@ int len; * Return number of display cells for char at ScreenLines[off]. * We make sure that the offset used is less than "max_off". */ -int latin_off2cells(off, max_off) -unsigned off UNUSED; -unsigned max_off UNUSED; +int latin_off2cells(unsigned off, unsigned max_off) { return 1; } -int dbcs_off2cells(off, max_off) -unsigned off; -unsigned max_off; +int dbcs_off2cells(unsigned off, unsigned max_off) { /* never check beyond end of the line */ if (off >= max_off) @@ -1412,9 +1371,7 @@ unsigned max_off; return MB_BYTE2LEN(ScreenLines[off]); } -int utf_off2cells(off, max_off) -unsigned off; -unsigned max_off; +int utf_off2cells(unsigned off, unsigned max_off) { return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1; } @@ -1423,14 +1380,12 @@ unsigned max_off; * mb_ptr2char() function pointer. * Convert a byte sequence into a character. */ -int latin_ptr2char(p) -char_u *p; +int latin_ptr2char(char_u *p) { return *p; } -static int dbcs_ptr2char(p) -char_u *p; +static int dbcs_ptr2char(char_u *p) { if (MB_BYTE2LEN(*p) > 1 && p[1] != NUL) return (p[0] << 8) + p[1]; @@ -1443,8 +1398,7 @@ char_u *p; * returned. * Does not include composing characters, of course. */ -int utf_ptr2char(p) -char_u *p; +int utf_ptr2char(char_u *p) { int len; @@ -1458,20 +1412,20 @@ char_u *p; if ((p[2] & 0xc0) == 0x80) { if (len == 3) return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6) - + (p[2] & 0x3f); + + (p[2] & 0x3f); if ((p[3] & 0xc0) == 0x80) { if (len == 4) return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12) - + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f); + + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f); if ((p[4] & 0xc0) == 0x80) { if (len == 5) return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18) - + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6) - + (p[4] & 0x3f); + + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6) + + (p[4] & 0x3f); if ((p[5] & 0xc0) == 0x80 && len == 6) return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24) - + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12) - + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f); + + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12) + + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f); } } } @@ -1496,9 +1450,7 @@ char_u *p; * If byte sequence is illegal or incomplete, returns -1 and does not advance * "s". */ -static int utf_safe_read_char_adv(s, n) -char_u **s; -size_t *n; +static int utf_safe_read_char_adv(char_u **s, size_t *n) { int c, k; @@ -1540,8 +1492,7 @@ size_t *n; * Get character at **pp and advance *pp to the next character. * Note: composing characters are skipped! */ -int mb_ptr2char_adv(pp) -char_u **pp; +int mb_ptr2char_adv(char_u **pp) { int c; @@ -1554,8 +1505,7 @@ char_u **pp; * Get character at **pp and advance *pp to the next character. * Note: composing characters are returned as separate characters. */ -int mb_cptr2char_adv(pp) -char_u **pp; +int mb_cptr2char_adv(char_u **pp) { int c; @@ -1571,9 +1521,10 @@ char_u **pp; * Check whether we are dealing with Arabic combining characters. * Note: these are NOT really composing characters! */ -int arabic_combine(one, two) -int one; /* first character */ -int two; /* character just after "one" */ +int arabic_combine( + int one, /* first character */ + int two /* character just after "one" */ + ) { if (one == a_LAM) return arabic_maycombine(two); @@ -1584,14 +1535,13 @@ int two; /* character just after "one" */ * Check whether we are dealing with a character that could be regarded as an * Arabic combining character, need to check the character before this. */ -int arabic_maycombine(two) -int two; +int arabic_maycombine(int two) { if (p_arshape && !p_tbidi) return two == a_ALEF_MADDA - || two == a_ALEF_HAMZA_ABOVE - || two == a_ALEF_HAMZA_BELOW - || two == a_ALEF; + || two == a_ALEF_HAMZA_ABOVE + || two == a_ALEF_HAMZA_BELOW + || two == a_ALEF; return FALSE; } @@ -1600,9 +1550,7 @@ int two; * comes after "p1". For Arabic sometimes "ab" is replaced with "c", which * behaves like a composing character. */ -int utf_composinglike(p1, p2) -char_u *p1; -char_u *p2; +int utf_composinglike(char_u *p1, char_u *p2) { int c2; @@ -1618,9 +1566,10 @@ char_u *p2; * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO * composing characters. */ -int utfc_ptr2char(p, pcc) -char_u *p; -int *pcc; /* return: composing chars, last one is 0 */ +int utfc_ptr2char( + char_u *p, + int *pcc /* return: composing chars, last one is 0 */ + ) { int len; int c; @@ -1655,10 +1604,11 @@ int *pcc; /* return: composing chars, last one is 0 */ * Convert a UTF-8 byte string to a wide character. Also get up to MAX_MCO * composing characters. Use no more than p[maxlen]. */ -int utfc_ptr2char_len(p, pcc, maxlen) -char_u *p; -int *pcc; /* return: composing chars, last one is 0 */ -int maxlen; +int utfc_ptr2char_len( + char_u *p, + int *pcc, /* return: composing chars, last one is 0 */ + int maxlen + ) { int len; int c; @@ -1698,9 +1648,7 @@ int maxlen; * Only to be used when ScreenLinesUC[off] != 0. * Returns the produced number of bytes. */ -int utfc_char2bytes(off, buf) -int off; -char_u *buf; +int utfc_char2bytes(int off, char_u *buf) { int len; int i; @@ -1720,8 +1668,7 @@ char_u *buf; * Returns 0 for "". * Returns 1 for an illegal byte sequence. */ -int utf_ptr2len(p) -char_u *p; +int utf_ptr2len(char_u *p) { int len; int i; @@ -1740,8 +1687,7 @@ char_u *p; * "b" must be between 0 and 255! * Returns 1 for an invalid first byte value. */ -int utf_byte2len(b) -int b; +int utf_byte2len(int b) { return utf8len_tab[b]; } @@ -1754,9 +1700,7 @@ int b; * Returns number > "size" for an incomplete byte sequence. * Never returns zero. */ -int utf_ptr2len_len(p, size) -char_u *p; -int size; +int utf_ptr2len_len(char_u *p, int size) { int len; int i; @@ -1779,8 +1723,7 @@ int size; * Return the number of bytes the UTF-8 encoding of the character at "p" takes. * This includes following composing characters. */ -int utfc_ptr2len(p) -char_u *p; +int utfc_ptr2len(char_u *p) { int len; int b0 = *p; @@ -1819,9 +1762,7 @@ char_u *p; * Returns 0 for an empty string. * Returns 1 for an illegal char or an incomplete byte sequence. */ -int utfc_ptr2len_len(p, size) -char_u *p; -int size; +int utfc_ptr2len_len(char_u *p, int size) { int len; int prevlen; @@ -1871,8 +1812,7 @@ int size; * Return the number of bytes the UTF-8 encoding of character "c" takes. * This does not include composing characters. */ -int utf_char2len(c) -int c; +int utf_char2len(int c) { if (c < 0x80) return 1; @@ -1892,9 +1832,7 @@ int c; * Returns the number of bytes. * This does not include composing characters. */ -int utf_char2bytes(c, buf) -int c; -char_u *buf; +int utf_char2bytes(int c, char_u *buf) { if (c < 0x80) { /* 7 bits */ buf[0] = c; @@ -1941,8 +1879,7 @@ char_u *buf; * drawn on top of the preceding character. * Based on code from Markus Kuhn. */ -int utf_iscomposing(c) -int c; +int utf_iscomposing(int c) { /* Sorted list of non-overlapping intervals. * Generated by ../runtime/tools/unicode.vim. */ @@ -2145,8 +2082,7 @@ int c; * Return TRUE for characters that can be displayed in a normal way. * Only for characters of 0x100 and above! */ -int utf_printable(c) -int c; +int utf_printable(int c) { #ifdef USE_WCHAR_FUNCTIONS /* @@ -2173,8 +2109,7 @@ int c; * 1: punctuation * 2 or bigger: some class of word character. */ -int utf_class(c) -int c; +int utf_class(int c) { /* sorted list of non-overlapping intervals */ static struct clinterval { @@ -2467,10 +2402,7 @@ static int utf_strnicmp __ARGS((char_u *s1, char_u *s2, size_t n1, size_t n2)); * Return the converted equivalent of "a", which is a UCS-4 character. Use * the given conversion "table". Uses binary search on "table". */ -static int utf_convert(a, table, tableSize) -int a; -convertStruct table[]; -int tableSize; +static int utf_convert(int a, convertStruct *table, int tableSize) { int start, mid, end; /* indices into table */ int entries = tableSize / sizeof(convertStruct); @@ -2498,8 +2430,7 @@ int tableSize; * Return the folded-case equivalent of "a", which is a UCS-4 character. Uses * simple case folding. */ -int utf_fold(a) -int a; +int utf_fold(int a) { return utf_convert(a, foldCase, (int)sizeof(foldCase)); } @@ -2810,8 +2741,7 @@ static convertStruct toUpper[] = * Return the upper-case equivalent of "a", which is a UCS-4 character. Use * simple case folding. */ -int utf_toupper(a) -int a; +int utf_toupper(int a) { /* If 'casemap' contains "keepascii" use ASCII style toupper(). */ if (a < 128 && (cmp_flags & CMP_KEEPASCII)) @@ -2831,8 +2761,7 @@ int a; return utf_convert(a, toUpper, (int)sizeof(toUpper)); } -int utf_islower(a) -int a; +int utf_islower(int a) { /* German sharp s is lower case but has no upper case equivalent. */ return (utf_toupper(a) != a) || a == 0xdf; @@ -2842,8 +2771,7 @@ int a; * Return the lower-case equivalent of "a", which is a UCS-4 character. Use * simple case folding. */ -int utf_tolower(a) -int a; +int utf_tolower(int a) { /* If 'casemap' contains "keepascii" use ASCII style tolower(). */ if (a < 128 && (cmp_flags & CMP_KEEPASCII)) @@ -2863,15 +2791,12 @@ int a; return utf_convert(a, toLower, (int)sizeof(toLower)); } -int utf_isupper(a) -int a; +int utf_isupper(int a) { return utf_tolower(a) != a; } -static int utf_strnicmp(s1, s2, n1, n2) -char_u *s1, *s2; -size_t n1, n2; +static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2) { int c1, c2, cdiff; char_u buffer[6]; @@ -2944,9 +2869,7 @@ size_t n1, n2; * Returns zero if s1 and s2 are equal (ignoring case), the difference between * two characters otherwise. */ -int mb_strnicmp(s1, s2, nn) -char_u *s1, *s2; -size_t nn; +int mb_strnicmp(char_u *s1, char_u *s2, size_t nn) { int i, l; int cdiff; @@ -3027,16 +2950,12 @@ void show_utf8() { * If "p" points to the NUL at the end of the string return 0. * Returns 0 when already at the first byte of a character. */ -int latin_head_off(base, p) -char_u *base UNUSED; -char_u *p UNUSED; +int latin_head_off(char_u *base, char_u *p) { return 0; } -int dbcs_head_off(base, p) -char_u *base; -char_u *p; +int dbcs_head_off(char_u *base, char_u *p) { char_u *q; @@ -3057,9 +2976,7 @@ char_u *p; * Special version of dbcs_head_off() that works for ScreenLines[], where * single-width DBCS_JPNU characters are stored separately. */ -int dbcs_screen_head_off(base, p) -char_u *base; -char_u *p; +int dbcs_screen_head_off(char_u *base, char_u *p) { char_u *q; @@ -3087,9 +3004,7 @@ char_u *p; return (q == p) ? 0 : 1; } -int utf_head_off(base, p) -char_u *base; -char_u *p; +int utf_head_off(char_u *base, char_u *p) { char_u *q; char_u *s; @@ -3141,9 +3056,7 @@ char_u *p; /* * Copy a character from "*fp" to "*tp" and advance the pointers. */ -void mb_copy_char(fp, tp) -char_u **fp; -char_u **tp; +void mb_copy_char(char_u **fp, char_u **tp) { int l = (*mb_ptr2len)(*fp); @@ -3157,9 +3070,7 @@ char_u **tp; * at the start of a character 0 is returned, otherwise the offset to the next * character. Can start anywhere in a stream of bytes. */ -int mb_off_next(base, p) -char_u *base; -char_u *p; +int mb_off_next(char_u *base, char_u *p) { int i; int j; @@ -3191,9 +3102,7 @@ char_u *p; * Return the offset from "p" to the last byte of the character it points * into. Can start anywhere in a stream of bytes. */ -int mb_tail_off(base, p) -char_u *base; -char_u *p; +int mb_tail_off(char_u *base, char_u *p) { int i; int j; @@ -3257,7 +3166,7 @@ void utf_find_illegal() { * utf_ptr2len()) or too many of them (overlong sequence). */ len = utf_ptr2len(p); if (*p >= 0x80 && (len == 1 - || utf_char2len(utf_ptr2char(p)) != len)) { + || utf_char2len(utf_ptr2char(p)) != len)) { if (vimconv.vc_type == CONV_NONE) curwin->w_cursor.col += (colnr_T)(p - ml_get_cursor()); else { @@ -3301,15 +3210,13 @@ void mb_adjust_cursor() { * Adjust position "*lp" to point to the first byte of a multi-byte character. * If it points to a tail byte it's moved backwards to the head byte. */ -void mb_adjustpos(buf, lp) -buf_T *buf; -pos_T *lp; +void mb_adjustpos(buf_T *buf, pos_T *lp) { char_u *p; if (lp->col > 0 || lp->coladd > 1 - ) { + ) { p = ml_get_buf(buf, lp->lnum, FALSE); lp->col -= (*mb_head_off)(p, p + lp->col); /* Reset "coladd" when the cursor would be on the right half of a @@ -3325,9 +3232,10 @@ pos_T *lp; /* * Return a pointer to the character before "*p", if there is one. */ -char_u * mb_prevptr(line, p) -char_u *line; /* start of the string */ -char_u *p; +char_u * mb_prevptr( + char_u *line, /* start of the string */ + char_u *p + ) { if (p > line) mb_ptr_back(line, p); @@ -3338,8 +3246,7 @@ char_u *p; * Return the character length of "str". Each multi-byte character (with * following composing characters) counts as one. */ -int mb_charlen(str) -char_u *str; +int mb_charlen(char_u *str) { char_u *p = str; int count; @@ -3356,9 +3263,7 @@ char_u *str; /* * Like mb_charlen() but for a string with specified length. */ -int mb_charlen_len(str, len) -char_u *str; -int len; +int mb_charlen_len(char_u *str, int len) { char_u *p = str; int count; @@ -3376,8 +3281,7 @@ int len; * "pp" to just after the bytes that formed it. * Return NULL if no multi-byte char was found. */ -char_u * mb_unescape(pp) -char_u **pp; +char_u * mb_unescape(char_u **pp) { static char_u buf[6]; int n; @@ -3394,13 +3298,13 @@ char_u **pp; buf[m++] = K_SPECIAL; n += 2; } else if ((str[n] == K_SPECIAL - ) - && str[n + 1] == KS_EXTRA - && str[n + 2] == (int)KE_CSI) { + ) + && str[n + 1] == KS_EXTRA + && str[n + 2] == (int)KE_CSI) { buf[m++] = CSI; n += 2; } else if (str[n] == K_SPECIAL - ) + ) break; /* a special key can't be a multibyte char */ else buf[m++] = str[n]; @@ -3425,32 +3329,28 @@ char_u **pp; * of a double-width character. * Caller must make sure "row" and "col" are not invalid! */ -int mb_lefthalve(row, col) -int row; -int col; +int mb_lefthalve(int row, int col) { if (composing_hangul) return TRUE; return (*mb_off2cells)(LineOffset[row] + col, - LineOffset[row] + screen_Columns) > 1; + LineOffset[row] + screen_Columns) > 1; } /* * Correct a position on the screen, if it's the right half of a double-wide * char move it to the left half. Returns the corrected column. */ -int mb_fix_col(col, row) -int col; -int row; +int mb_fix_col(int col, int row) { col = check_col(col); row = check_row(row); if (has_mbyte && ScreenLines != NULL && col > 0 && ((enc_dbcs - && ScreenLines[LineOffset[row] + col] != NUL - && dbcs_screen_head_off(ScreenLines + LineOffset[row], - ScreenLines + LineOffset[row] + col)) - || (enc_utf8 && ScreenLines[LineOffset[row] + col] == 0))) + && ScreenLines[LineOffset[row] + col] != NUL + && dbcs_screen_head_off(ScreenLines + LineOffset[row], + ScreenLines + LineOffset[row] + col)) + || (enc_utf8 && ScreenLines[LineOffset[row] + col] == 0))) return col - 1; return col; } @@ -3460,8 +3360,7 @@ static int enc_alias_search __ARGS((char_u *name)); /* * Skip the Vim specific head of a 'encoding' name. */ -char_u * enc_skip(p) -char_u *p; +char_u * enc_skip(char_u *p) { if (STRNCMP(p, "2byte-", 6) == 0) return p + 6; @@ -3476,8 +3375,7 @@ char_u *p; * case characters and '_' replaced with '-'. * Returns an allocated string. NULL for out-of-memory. */ -char_u * enc_canonize(enc) -char_u *enc; +char_u * enc_canonize(char_u *enc) { char_u *r; char_u *p, *s; @@ -3544,8 +3442,7 @@ char_u *enc; * Search for an encoding alias of "name". * Returns -1 when not found. */ -static int enc_alias_search(name) -char_u *name; +static int enc_alias_search(char_u *name) { int i; @@ -3573,11 +3470,11 @@ char_u * enc_locale() { if ((s = nl_langinfo(CODESET)) == NULL || *s == NUL) # endif # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) - if ((s = setlocale(LC_CTYPE, NULL)) == NULL || *s == NUL) + if ((s = setlocale(LC_CTYPE, NULL)) == NULL || *s == NUL) # endif - if ((s = getenv("LC_ALL")) == NULL || *s == NUL) - if ((s = getenv("LC_CTYPE")) == NULL || *s == NUL) - s = getenv("LANG"); + if ((s = getenv("LC_ALL")) == NULL || *s == NUL) + if ((s = getenv("LC_CTYPE")) == NULL || *s == NUL) + s = getenv("LANG"); if (s == NULL || *s == NUL) return FAIL; @@ -3619,7 +3516,7 @@ char_u * enc_locale() { static char_u * iconv_string __ARGS((vimconv_T *vcp, char_u *str, int slen, int *unconvlenp, - int *resultlenp)); + int *resultlenp)); /* * Call iconv_open() with a check if iconv() works properly (there are broken @@ -3627,9 +3524,7 @@ iconv_string __ARGS((vimconv_T *vcp, char_u *str, int slen, int *unconvlenp, * Returns (void *)-1 if failed. * (should return iconv_t, but that causes problems with prototypes). */ -void * my_iconv_open(to, from) -char_u *to; -char_u *from; +void * my_iconv_open(char_u *to, char_u *from) { iconv_t fd; #define ICONV_TESTLEN 400 @@ -3678,12 +3573,7 @@ char_u *from; * Returns the converted string in allocated memory. NULL for an error. * If resultlenp is not NULL, sets it to the result length in bytes. */ -static char_u * iconv_string(vcp, str, slen, unconvlenp, resultlenp) -vimconv_T *vcp; -char_u *str; -int slen; -int *unconvlenp; -int *resultlenp; +static char_u * iconv_string(vimconv_T *vcp, char_u *str, int slen, int *unconvlenp, int *resultlenp) { const char *from; size_t fromlen; @@ -3734,8 +3624,8 @@ int *resultlenp; /* Check both ICONV_EILSEQ and EILSEQ, because the dynamically loaded * iconv library may use one of them. */ else if (!vcp->vc_fail - && (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ - || ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL)) { + && (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ + || ICONV_ERRNO == ICONV_EINVAL || ICONV_ERRNO == EINVAL)) { /* Can't convert: insert a '?' and skip a character. This assumes * conversion from 'encoding' to something else. In other * situations we don't know what to skip anyway. */ @@ -3804,9 +3694,9 @@ static void * get_iconv_import_func(HINSTANCE hInst, if (pPE->Signature != IMAGE_NT_SIGNATURE) return NULL; pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage - + pPE->OptionalHeader.DataDirectory[ - IMAGE_DIRECTORY_ENTRY_IMPORT] - .VirtualAddress); + + pPE->OptionalHeader.DataDirectory[ + IMAGE_DIRECTORY_ENTRY_IMPORT] + .VirtualAddress); for (; pImpDesc->FirstThunk; ++pImpDesc) { if (!pImpDesc->OriginalFirstThunk) continue; @@ -3816,7 +3706,7 @@ static void * get_iconv_import_func(HINSTANCE hInst, if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal)) continue; pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage - + (UINT_PTR)(pINT->u1.AddressOfData)); + + (UINT_PTR)(pINT->u1.AddressOfData)); if (strcmp(pImpName->Name, funcname) == 0) return (void *)pIAT->u1.Function; } @@ -3827,8 +3717,7 @@ static void * get_iconv_import_func(HINSTANCE hInst, /* * Try opening the iconv.dll and return TRUE if iconv() can be used. */ -int iconv_enabled(verbose) -int verbose; +int iconv_enabled(int verbose) { if (hIconvDLL != 0 && hMsvcrtDLL != 0) return TRUE; @@ -3901,9 +3790,9 @@ void iconv_end() { * Return FAIL when conversion is not supported, OK otherwise. */ int convert_setup(vcp, from, to) -vimconv_T *vcp; -char_u *from; -char_u *to; + vimconv_T *vcp; + char_u *from; + char_u *to; { return convert_setup_ext(vcp, from, TRUE, to, TRUE); } @@ -3913,11 +3802,11 @@ char_u *to; * "from" unicode charsets be considered utf-8. Same for "to". */ int convert_setup_ext(vcp, from, from_unicode_is_utf8, to, to_unicode_is_utf8) -vimconv_T *vcp; -char_u *from; -int from_unicode_is_utf8; -char_u *to; -int to_unicode_is_utf8; + vimconv_T *vcp; + char_u *from; + int from_unicode_is_utf8; + char_u *to; + int to_unicode_is_utf8; { int from_prop; int to_prop; @@ -3990,9 +3879,9 @@ int to_unicode_is_utf8; * Returns the length after conversion. */ int convert_input(ptr, len, maxlen) -char_u *ptr; -int len; -int maxlen; + char_u *ptr; + int len; + int maxlen; { return convert_input_safe(ptr, len, maxlen, NULL, NULL); } @@ -4004,11 +3893,11 @@ int maxlen; * the length. If "restp" is NULL it is not used. */ int convert_input_safe(ptr, len, maxlen, restp, restlenp) -char_u *ptr; -int len; -int maxlen; -char_u **restp; -int *restlenp; + char_u *ptr; + int len; + int maxlen; + char_u **restp; + int *restlenp; { char_u *d; int dlen = len; @@ -4043,9 +3932,9 @@ int *restlenp; * When something goes wrong, NULL is returned and "*lenp" is unchanged. */ char_u * string_convert(vcp, ptr, lenp) -vimconv_T *vcp; -char_u *ptr; -int *lenp; + vimconv_T *vcp; + char_u *ptr; + int *lenp; { return string_convert_ext(vcp, ptr, lenp, NULL); } @@ -4056,10 +3945,10 @@ int *lenp; * set to the number of remaining bytes. */ char_u * string_convert_ext(vcp, ptr, lenp, unconvlenp) -vimconv_T *vcp; -char_u *ptr; -int *lenp; -int *unconvlenp; + vimconv_T *vcp; + char_u *ptr; + int *lenp; + int *unconvlenp; { char_u *retval = NULL; char_u *d; @@ -4076,140 +3965,140 @@ int *unconvlenp; return vim_strsave((char_u *)""); switch (vcp->vc_type) { - case CONV_TO_UTF8: /* latin1 to utf-8 conversion */ - retval = alloc(len * 2 + 1); - if (retval == NULL) - break; - d = retval; - for (i = 0; i < len; ++i) { - c = ptr[i]; - if (c < 0x80) - *d++ = c; - else { - *d++ = 0xc0 + ((unsigned)c >> 6); - *d++ = 0x80 + (c & 0x3f); + case CONV_TO_UTF8: /* latin1 to utf-8 conversion */ + retval = alloc(len * 2 + 1); + if (retval == NULL) + break; + d = retval; + for (i = 0; i < len; ++i) { + c = ptr[i]; + if (c < 0x80) + *d++ = c; + else { + *d++ = 0xc0 + ((unsigned)c >> 6); + *d++ = 0x80 + (c & 0x3f); + } } - } - *d = NUL; - if (lenp != NULL) - *lenp = (int)(d - retval); - break; - - case CONV_9_TO_UTF8: /* latin9 to utf-8 conversion */ - retval = alloc(len * 3 + 1); - if (retval == NULL) + *d = NUL; + if (lenp != NULL) + *lenp = (int)(d - retval); break; - d = retval; - for (i = 0; i < len; ++i) { - c = ptr[i]; - switch (c) { - case 0xa4: c = 0x20ac; break; /* euro */ - case 0xa6: c = 0x0160; break; /* S hat */ - case 0xa8: c = 0x0161; break; /* S -hat */ - case 0xb4: c = 0x017d; break; /* Z hat */ - case 0xb8: c = 0x017e; break; /* Z -hat */ - case 0xbc: c = 0x0152; break; /* OE */ - case 0xbd: c = 0x0153; break; /* oe */ - case 0xbe: c = 0x0178; break; /* Y */ - } - d += utf_char2bytes(c, d); - } - *d = NUL; - if (lenp != NULL) - *lenp = (int)(d - retval); - break; - case CONV_TO_LATIN1: /* utf-8 to latin1 conversion */ - case CONV_TO_LATIN9: /* utf-8 to latin9 conversion */ - retval = alloc(len + 1); - if (retval == NULL) - break; - d = retval; - for (i = 0; i < len; ++i) { - l = utf_ptr2len_len(ptr + i, len - i); - if (l == 0) - *d++ = NUL; - else if (l == 1) { - int l_w = utf8len_tab_zero[ptr[i]]; - - if (l_w == 0) { - /* Illegal utf-8 byte cannot be converted */ - vim_free(retval); - return NULL; - } - if (unconvlenp != NULL && l_w > len - i) { - /* Incomplete sequence at the end. */ - *unconvlenp = len - i; - break; + case CONV_9_TO_UTF8: /* latin9 to utf-8 conversion */ + retval = alloc(len * 3 + 1); + if (retval == NULL) + break; + d = retval; + for (i = 0; i < len; ++i) { + c = ptr[i]; + switch (c) { + case 0xa4: c = 0x20ac; break; /* euro */ + case 0xa6: c = 0x0160; break; /* S hat */ + case 0xa8: c = 0x0161; break; /* S -hat */ + case 0xb4: c = 0x017d; break; /* Z hat */ + case 0xb8: c = 0x017e; break; /* Z -hat */ + case 0xbc: c = 0x0152; break; /* OE */ + case 0xbd: c = 0x0153; break; /* oe */ + case 0xbe: c = 0x0178; break; /* Y */ } - *d++ = ptr[i]; - } else { - c = utf_ptr2char(ptr + i); - if (vcp->vc_type == CONV_TO_LATIN9) - switch (c) { - case 0x20ac: c = 0xa4; break; /* euro */ - case 0x0160: c = 0xa6; break; /* S hat */ - case 0x0161: c = 0xa8; break; /* S -hat */ - case 0x017d: c = 0xb4; break; /* Z hat */ - case 0x017e: c = 0xb8; break; /* Z -hat */ - case 0x0152: c = 0xbc; break; /* OE */ - case 0x0153: c = 0xbd; break; /* oe */ - case 0x0178: c = 0xbe; break; /* Y */ - case 0xa4: - case 0xa6: - case 0xa8: - case 0xb4: - case 0xb8: - case 0xbc: - case 0xbd: - case 0xbe: c = 0x100; break; /* not in latin9 */ - } - if (!utf_iscomposing(c)) { /* skip composing chars */ - if (c < 0x100) - *d++ = c; - else if (vcp->vc_fail) { + d += utf_char2bytes(c, d); + } + *d = NUL; + if (lenp != NULL) + *lenp = (int)(d - retval); + break; + + case CONV_TO_LATIN1: /* utf-8 to latin1 conversion */ + case CONV_TO_LATIN9: /* utf-8 to latin9 conversion */ + retval = alloc(len + 1); + if (retval == NULL) + break; + d = retval; + for (i = 0; i < len; ++i) { + l = utf_ptr2len_len(ptr + i, len - i); + if (l == 0) + *d++ = NUL; + else if (l == 1) { + int l_w = utf8len_tab_zero[ptr[i]]; + + if (l_w == 0) { + /* Illegal utf-8 byte cannot be converted */ vim_free(retval); return NULL; - } else { - *d++ = 0xbf; - if (utf_char2cells(c) > 1) - *d++ = '?'; } + if (unconvlenp != NULL && l_w > len - i) { + /* Incomplete sequence at the end. */ + *unconvlenp = len - i; + break; + } + *d++ = ptr[i]; + } else { + c = utf_ptr2char(ptr + i); + if (vcp->vc_type == CONV_TO_LATIN9) + switch (c) { + case 0x20ac: c = 0xa4; break; /* euro */ + case 0x0160: c = 0xa6; break; /* S hat */ + case 0x0161: c = 0xa8; break; /* S -hat */ + case 0x017d: c = 0xb4; break; /* Z hat */ + case 0x017e: c = 0xb8; break; /* Z -hat */ + case 0x0152: c = 0xbc; break; /* OE */ + case 0x0153: c = 0xbd; break; /* oe */ + case 0x0178: c = 0xbe; break; /* Y */ + case 0xa4: + case 0xa6: + case 0xa8: + case 0xb4: + case 0xb8: + case 0xbc: + case 0xbd: + case 0xbe: c = 0x100; break; /* not in latin9 */ + } + if (!utf_iscomposing(c)) { /* skip composing chars */ + if (c < 0x100) + *d++ = c; + else if (vcp->vc_fail) { + vim_free(retval); + return NULL; + } else { + *d++ = 0xbf; + if (utf_char2cells(c) > 1) + *d++ = '?'; + } + } + i += l - 1; } - i += l - 1; } - } - *d = NUL; - if (lenp != NULL) - *lenp = (int)(d - retval); - break; + *d = NUL; + if (lenp != NULL) + *lenp = (int)(d - retval); + break; # ifdef MACOS_CONVERT - case CONV_MAC_LATIN1: - retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, - 'm', 'l', unconvlenp); - break; + case CONV_MAC_LATIN1: + retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, + 'm', 'l', unconvlenp); + break; - case CONV_LATIN1_MAC: - retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, - 'l', 'm', unconvlenp); - break; + case CONV_LATIN1_MAC: + retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, + 'l', 'm', unconvlenp); + break; - case CONV_MAC_UTF8: - retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, - 'm', 'u', unconvlenp); - break; + case CONV_MAC_UTF8: + retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, + 'm', 'u', unconvlenp); + break; - case CONV_UTF8_MAC: - retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, - 'u', 'm', unconvlenp); - break; + case CONV_UTF8_MAC: + retval = mac_string_convert(ptr, len, lenp, vcp->vc_fail, + 'u', 'm', unconvlenp); + break; # endif # ifdef USE_ICONV - case CONV_ICONV: /* conversion with output_conv.vc_fd */ - retval = iconv_string(vcp, ptr, len, unconvlenp, lenp); - break; + case CONV_ICONV: /* conversion with output_conv.vc_fd */ + retval = iconv_string(vcp, ptr, len, unconvlenp, lenp); + break; # endif } diff --git a/src/memfile.c b/src/memfile.c index 2969a19795..f4a49b1cef 100644 --- a/src/memfile.c +++ b/src/memfile.c @@ -109,9 +109,7 @@ static int mf_hash_grow __ARGS((mf_hashtab_T *)); * * return value: identifier for this memory block file. */ -memfile_T * mf_open(fname, flags) -char_u *fname; -int flags; +memfile_T *mf_open(char_u *fname, int flags) { memfile_T *mfp; off_t size; @@ -203,9 +201,7 @@ int flags; * * return value: FAIL if file could not be opened, OK otherwise */ -int mf_open_file(mfp, fname) -memfile_T *mfp; -char_u *fname; +int mf_open_file(memfile_T *mfp, char_u *fname) { mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); /* try to open the file */ @@ -219,9 +215,7 @@ char_u *fname; /* * Close a memory file and delete the associated file if 'del_file' is TRUE. */ -void mf_close(mfp, del_file) -memfile_T *mfp; -int del_file; +void mf_close(memfile_T *mfp, int del_file) { bhdr_T *hp, *nextp; @@ -251,9 +245,11 @@ int del_file; /* * Close the swap file for a memfile. Used when 'swapfile' is reset. */ -void mf_close_file(buf, getlines) -buf_T *buf; -int getlines; /* get all lines into memory? */ +void +mf_close_file ( + buf_T *buf, + int getlines /* get all lines into memory? */ +) { memfile_T *mfp; linenr_T lnum; @@ -288,9 +284,7 @@ int getlines; /* get all lines into memory? */ * Set new size for a memfile. Used when block 0 of a swapfile has been read * and the size it indicates differs from what was guessed. */ -void mf_new_page_size(mfp, new_size) -memfile_T *mfp; -unsigned new_size; +void mf_new_page_size(memfile_T *mfp, unsigned new_size) { /* Correct the memory used for block 0 to the new size, because it will be * freed with that size later on. */ @@ -303,10 +297,7 @@ unsigned new_size; * * negative: TRUE if negative block number desired (data block) */ -bhdr_T * mf_new(mfp, negative, page_count) -memfile_T *mfp; -int negative; -int page_count; +bhdr_T *mf_new(memfile_T *mfp, int negative, int page_count) { bhdr_T *hp; /* new bhdr_T */ bhdr_T *freep; /* first block in free list */ @@ -384,10 +375,7 @@ int page_count; * * Note: The caller should first check a negative nr with mf_trans_del() */ -bhdr_T * mf_get(mfp, nr, page_count) -memfile_T *mfp; -blocknr_T nr; -int page_count; +bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, int page_count) { bhdr_T *hp; /* doesn't exist */ @@ -440,11 +428,7 @@ int page_count; * * no return value, function cannot fail */ -void mf_put(mfp, hp, dirty, infile) -memfile_T *mfp; -bhdr_T *hp; -int dirty; -int infile; +void mf_put(memfile_T *mfp, bhdr_T *hp, int dirty, int infile) { int flags; @@ -465,9 +449,7 @@ int infile; /* * block *hp is no longer in used, may put it in the free list of memfile *mfp */ -void mf_free(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +void mf_free(memfile_T *mfp, bhdr_T *hp) { vim_free(hp->bh_data); /* free the memory */ mf_rem_hash(mfp, hp); /* get *hp out of the hash list */ @@ -502,9 +484,7 @@ static unsigned long fdtofh(int filedescriptor) { * * Return FAIL for failure, OK otherwise */ -int mf_sync(mfp, flags) -memfile_T *mfp; -int flags; +int mf_sync(memfile_T *mfp, int flags) { int status; bhdr_T *hp; @@ -603,8 +583,7 @@ int flags; * the dirty flag. These are blocks that need to be written to a newly * created swapfile. */ -void mf_set_dirty(mfp) -memfile_T *mfp; +void mf_set_dirty(memfile_T *mfp) { bhdr_T *hp; @@ -617,9 +596,7 @@ memfile_T *mfp; /* * insert block *hp in front of hashlist of memfile *mfp */ -static void mf_ins_hash(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static void mf_ins_hash(memfile_T *mfp, bhdr_T *hp) { mf_hash_add_item(&mfp->mf_hash, (mf_hashitem_T *)hp); } @@ -627,9 +604,7 @@ bhdr_T *hp; /* * remove block *hp from hashlist of memfile list *mfp */ -static void mf_rem_hash(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static void mf_rem_hash(memfile_T *mfp, bhdr_T *hp) { mf_hash_rem_item(&mfp->mf_hash, (mf_hashitem_T *)hp); } @@ -637,9 +612,7 @@ bhdr_T *hp; /* * look in hash lists of memfile *mfp for block header with number 'nr' */ -static bhdr_T * mf_find_hash(mfp, nr) -memfile_T *mfp; -blocknr_T nr; +static bhdr_T *mf_find_hash(memfile_T *mfp, blocknr_T nr) { return (bhdr_T *)mf_hash_find(&mfp->mf_hash, nr); } @@ -647,9 +620,7 @@ blocknr_T nr; /* * insert block *hp in front of used list of memfile *mfp */ -static void mf_ins_used(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static void mf_ins_used(memfile_T *mfp, bhdr_T *hp) { hp->bh_next = mfp->mf_used_first; mfp->mf_used_first = hp; @@ -665,9 +636,7 @@ bhdr_T *hp; /* * remove block *hp from used list of memfile *mfp */ -static void mf_rem_used(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static void mf_rem_used(memfile_T *mfp, bhdr_T *hp) { if (hp->bh_next == NULL) /* last block in used list */ mfp->mf_used_last = hp->bh_prev; @@ -688,9 +657,7 @@ bhdr_T *hp; * Return the block header to the caller, including the memory block, so * it can be re-used. Make sure the page_count is right. */ -static bhdr_T * mf_release(mfp, page_count) -memfile_T *mfp; -int page_count; +static bhdr_T *mf_release(memfile_T *mfp, int page_count) { bhdr_T *hp; int need_release; @@ -768,7 +735,7 @@ int page_count; * * return TRUE if any memory was released */ -int mf_release_all() { +int mf_release_all(void) { buf_T *buf; memfile_T *mfp; bhdr_T *hp; @@ -804,9 +771,7 @@ int mf_release_all() { /* * Allocate a block header and a block of memory for it */ -static bhdr_T * mf_alloc_bhdr(mfp, page_count) -memfile_T *mfp; -int page_count; +static bhdr_T *mf_alloc_bhdr(memfile_T *mfp, int page_count) { bhdr_T *hp; @@ -824,8 +789,7 @@ int page_count; /* * Free a block header and the block of memory for it */ -static void mf_free_bhdr(hp) -bhdr_T *hp; +static void mf_free_bhdr(bhdr_T *hp) { vim_free(hp->bh_data); vim_free(hp); @@ -834,9 +798,7 @@ bhdr_T *hp; /* * insert entry *hp in the free list */ -static void mf_ins_free(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static void mf_ins_free(memfile_T *mfp, bhdr_T *hp) { hp->bh_next = mfp->mf_free_first; mfp->mf_free_first = hp; @@ -846,8 +808,7 @@ bhdr_T *hp; * remove the first entry from the free list and return a pointer to it * Note: caller must check that mfp->mf_free_first is not NULL! */ -static bhdr_T * mf_rem_free(mfp) -memfile_T *mfp; +static bhdr_T *mf_rem_free(memfile_T *mfp) { bhdr_T *hp; @@ -861,9 +822,7 @@ memfile_T *mfp; * * Return FAIL for failure, OK otherwise */ -static int mf_read(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static int mf_read(memfile_T *mfp, bhdr_T *hp) { off_t offset; unsigned page_size; @@ -896,9 +855,7 @@ bhdr_T *hp; * * Return FAIL for failure, OK otherwise */ -static int mf_write(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static int mf_write(memfile_T *mfp, bhdr_T *hp) { off_t offset; /* offset in the file */ blocknr_T nr; /* block nr which is being written */ @@ -969,11 +926,7 @@ bhdr_T *hp; * Takes care of encryption. * Return FAIL or OK. */ -static int mf_write_block(mfp, hp, offset, size) -memfile_T *mfp; -bhdr_T *hp; -off_t offset UNUSED; -unsigned size; +static int mf_write_block(memfile_T *mfp, bhdr_T *hp, off_t offset, unsigned size) { char_u *data = hp->bh_data; int result = OK; @@ -999,9 +952,7 @@ unsigned size; * * Return FAIL for failure, OK otherwise */ -static int mf_trans_add(mfp, hp) -memfile_T *mfp; -bhdr_T *hp; +static int mf_trans_add(memfile_T *mfp, bhdr_T *hp) { bhdr_T *freep; blocknr_T new_bnum; @@ -1057,9 +1008,7 @@ bhdr_T *hp; * * Return the positive new number when found, the old number when not found */ -blocknr_T mf_trans_del(mfp, old_nr) -memfile_T *mfp; -blocknr_T old_nr; +blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr) { NR_TRANS *np; blocknr_T new_bnum; @@ -1085,8 +1034,7 @@ blocknr_T old_nr; * Only called when creating or renaming the swapfile. Either way it's a new * name so we must work out the full path name. */ -void mf_set_ffname(mfp) -memfile_T *mfp; +void mf_set_ffname(memfile_T *mfp) { mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE); } @@ -1095,8 +1043,7 @@ memfile_T *mfp; * Make the name of the file used for the memfile a full path. * Used before doing a :cd */ -void mf_fullname(mfp) -memfile_T *mfp; +void mf_fullname(memfile_T *mfp) { if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL) { vim_free(mfp->mf_fname); @@ -1108,8 +1055,7 @@ memfile_T *mfp; /* * return TRUE if there are any translations pending for 'mfp' */ -int mf_need_trans(mfp) -memfile_T *mfp; +int mf_need_trans(memfile_T *mfp) { return mfp->mf_fname != NULL && mfp->mf_neg_count > 0; } @@ -1119,10 +1065,12 @@ memfile_T *mfp; * The "fname" must be in allocated memory, and is consumed (also when an * error occurs). */ -static void mf_do_open(mfp, fname, flags) -memfile_T *mfp; -char_u *fname; -int flags; /* flags for open() */ +static void +mf_do_open ( + memfile_T *mfp, + char_u *fname, + int flags /* flags for open() */ +) { #ifdef HAVE_LSTAT struct stat sb; @@ -1191,8 +1139,7 @@ int flags; /* flags for open() */ /* * Initialize an empty hash table. */ -static void mf_hash_init(mht) -mf_hashtab_T *mht; +static void mf_hash_init(mf_hashtab_T *mht) { vim_memset(mht, 0, sizeof(mf_hashtab_T)); mht->mht_buckets = mht->mht_small_buckets; @@ -1203,8 +1150,7 @@ mf_hashtab_T *mht; * Free the array of a hash table. Does not free the items it contains! * The hash table must not be used again without another mf_hash_init() call. */ -static void mf_hash_free(mht) -mf_hashtab_T *mht; +static void mf_hash_free(mf_hashtab_T *mht) { if (mht->mht_buckets != mht->mht_small_buckets) vim_free(mht->mht_buckets); @@ -1213,8 +1159,7 @@ mf_hashtab_T *mht; /* * Free the array of a hash table and all the items it contains. */ -static void mf_hash_free_all(mht) -mf_hashtab_T *mht; +static void mf_hash_free_all(mf_hashtab_T *mht) { long_u idx; mf_hashitem_T *mhi; @@ -1233,9 +1178,7 @@ mf_hashtab_T *mht; * Find "key" in hashtable "mht". * Returns a pointer to a mf_hashitem_T or NULL if the item was not found. */ -static mf_hashitem_T * mf_hash_find(mht, key) -mf_hashtab_T *mht; -blocknr_T key; +static mf_hashitem_T *mf_hash_find(mf_hashtab_T *mht, blocknr_T key) { mf_hashitem_T *mhi; @@ -1250,9 +1193,7 @@ blocknr_T key; * Add item "mhi" to hashtable "mht". * "mhi" must not be NULL. */ -static void mf_hash_add_item(mht, mhi) -mf_hashtab_T *mht; -mf_hashitem_T *mhi; +static void mf_hash_add_item(mf_hashtab_T *mht, mf_hashitem_T *mhi) { long_u idx; @@ -1282,9 +1223,7 @@ mf_hashitem_T *mhi; * Remove item "mhi" from hashtable "mht". * "mhi" must not be NULL and must have been inserted into "mht". */ -static void mf_hash_rem_item(mht, mhi) -mf_hashtab_T *mht; -mf_hashitem_T *mhi; +static void mf_hash_rem_item(mf_hashtab_T *mht, mf_hashitem_T *mhi) { if (mhi->mhi_prev == NULL) mht->mht_buckets[mhi->mhi_key & mht->mht_mask] = mhi->mhi_next; @@ -1305,8 +1244,7 @@ mf_hashitem_T *mhi; * rehash items. * Returns FAIL when out of memory. */ -static int mf_hash_grow(mht) -mf_hashtab_T *mht; +static int mf_hash_grow(mf_hashtab_T *mht) { long_u i, j; int shift; diff --git a/src/memline.c b/src/memline.c index 15d5416829..2f8fd69669 100644 --- a/src/memline.c +++ b/src/memline.c @@ -255,8 +255,7 @@ static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype) * * Return FAIL for failure, OK otherwise. */ -int ml_open(buf) -buf_T *buf; +int ml_open(buf_T *buf) { memfile_T *mfp; bhdr_T *hp = NULL; @@ -389,9 +388,7 @@ error: /* * Prepare encryption for "buf" with block 0 "b0p". */ -static void ml_set_b0_crypt(buf, b0p) -buf_T *buf; -ZERO_BL *b0p; +static void ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p) { if (*buf->b_p_key == NUL) b0p->b0_id[1] = BLOCK0_ID1; @@ -415,10 +412,7 @@ ZERO_BL *b0p; * "old_cm" is the previous 'cryptmethod'. It is equal to the current * 'cryptmethod' when 'key' is changed. */ -void ml_set_crypt_key(buf, old_key, old_cm) -buf_T *buf; -char_u *old_key; -int old_cm; +void ml_set_crypt_key(buf_T *buf, char_u *old_key, int old_cm) { memfile_T *mfp = buf->b_ml.ml_mfp; bhdr_T *hp; @@ -533,8 +527,7 @@ int old_cm; * ml_setname() is called when the file name of "buf" has been changed. * It may rename the swap file. */ -void ml_setname(buf) -buf_T *buf; +void ml_setname(buf_T *buf) { int success = FALSE; memfile_T *mfp; @@ -615,7 +608,7 @@ buf_T *buf; * been modified. * Used when 'updatecount' changes from zero to non-zero. */ -void ml_open_files() { +void ml_open_files(void) { buf_T *buf; for (buf = firstbuf; buf != NULL; buf = buf->b_next) @@ -628,8 +621,7 @@ void ml_open_files() { * If we are unable to find a file name, mf_fname will be NULL * and the memfile will be in memory only (no recovery possible). */ -void ml_open_file(buf) -buf_T *buf; +void ml_open_file(buf_T *buf) { memfile_T *mfp; char_u *fname; @@ -696,8 +688,10 @@ buf_T *buf; * If still need to create a swap file, and starting to edit a not-readonly * file, or reading into an existing buffer, create a swap file now. */ -void check_need_swap(newfile) -int newfile; /* reading file into new buffer */ +void +check_need_swap ( + int newfile /* reading file into new buffer */ +) { if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile)) ml_open_file(curbuf); @@ -707,9 +701,7 @@ int newfile; /* reading file into new buffer */ * Close memline for buffer 'buf'. * If 'del_file' is TRUE, delete the swap file */ -void ml_close(buf, del_file) -buf_T *buf; -int del_file; +void ml_close(buf_T *buf, int del_file) { if (buf->b_ml.ml_mfp == NULL) /* not open */ return; @@ -732,8 +724,7 @@ int del_file; * When 'del_file' is TRUE, delete the memfiles. * But don't delete files that were ":preserve"d when we are POSIX compatible. */ -void ml_close_all(del_file) -int del_file; +void ml_close_all(int del_file) { buf_T *buf; @@ -750,7 +741,7 @@ int del_file; * Close all memfiles for not modified buffers. * Only use just before exiting! */ -void ml_close_notmod() { +void ml_close_notmod(void) { buf_T *buf; for (buf = firstbuf; buf != NULL; buf = buf->b_next) @@ -762,8 +753,7 @@ void ml_close_notmod() { * Update the timestamp in the .swp file. * Used when the file has been written. */ -void ml_timestamp(buf) -buf_T *buf; +void ml_timestamp(buf_T *buf) { ml_upd_block0(buf, UB_FNAME); } @@ -771,8 +761,7 @@ buf_T *buf; /* * Return FAIL when the ID of "b0p" is wrong. */ -static int ml_check_b0_id(b0p) -ZERO_BL *b0p; +static int ml_check_b0_id(ZERO_BL *b0p) { if (b0p->b0_id[0] != BLOCK0_ID0 || (b0p->b0_id[1] != BLOCK0_ID1 @@ -786,9 +775,7 @@ ZERO_BL *b0p; /* * Update the timestamp or the B0_SAME_DIR flag of the .swp file. */ -static void ml_upd_block0(buf, what) -buf_T *buf; -upd_block0_T what; +static void ml_upd_block0(buf_T *buf, upd_block0_T what) { memfile_T *mfp; bhdr_T *hp; @@ -816,9 +803,7 @@ upd_block0_T what; * Also set buf->b_mtime. * Don't use NameBuff[]!!! */ -static void set_b0_fname(b0p, buf) -ZERO_BL *b0p; -buf_T *buf; +static void set_b0_fname(ZERO_BL *b0p, buf_T *buf) { struct stat st; @@ -878,9 +863,7 @@ buf_T *buf; * This is fail safe: if we are not sure the directories are equal the flag is * not set. */ -static void set_b0_dir_flag(b0p, buf) -ZERO_BL *b0p; -buf_T *buf; +static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf) { if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname)) b0p->b0_flags |= B0_SAME_DIR; @@ -891,9 +874,7 @@ buf_T *buf; /* * When there is room, add the 'fileencoding' to block zero. */ -static void add_b0_fenc(b0p, buf) -ZERO_BL *b0p; -buf_T *buf; +static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf) { int n; int size = B0_FNAME_SIZE_NOCRYPT; @@ -919,7 +900,7 @@ buf_T *buf; /* * Try to recover curbuf from the .swp file. */ -void ml_recover() { +void ml_recover(void) { buf_T *buf = NULL; memfile_T *mfp = NULL; char_u *fname; @@ -1490,11 +1471,13 @@ theend: * - list the swap files when recovering * - find the name of the n'th swap file when recovering */ -int recover_names(fname, list, nr, fname_out) -char_u *fname; /* base for swap file name */ -int list; /* when TRUE, list the swap file names */ -int nr; /* when non-zero, return nr'th swap file name */ -char_u **fname_out; /* result when "nr" > 0 */ +int +recover_names ( + char_u *fname, /* base for swap file name */ + int list, /* when TRUE, list the swap file names */ + int nr, /* when non-zero, return nr'th swap file name */ + char_u **fname_out /* result when "nr" > 0 */ +) { int num_names; char_u *(names[6]); @@ -1694,9 +1677,7 @@ char_u **fname_out; /* result when "nr" > 0 */ * Append the full path to name with path separators made into percent * signs, to dir. An unnamed buffer is handled as "" (/"") */ -static char_u * make_percent_swname(dir, name) -char_u *dir; -char_u *name; +static char_u *make_percent_swname(char_u *dir, char_u *name) { char_u *d, *s, *f; @@ -1727,8 +1708,7 @@ static int process_still_running; * Give information about an existing swap file. * Returns timestamp (0 when unknown). */ -static time_t swapfile_info(fname) -char_u *fname; +static time_t swapfile_info(char_u *fname) { struct stat st; int fd; @@ -1817,10 +1797,7 @@ char_u *fname; return x; } -static int recov_file_names(names, path, prepend_dot) -char_u **names; -char_u *path; -int prepend_dot; +static int recov_file_names(char_u **names, char_u *path, int prepend_dot) { int num_names; @@ -1909,9 +1886,7 @@ end: * If 'check_char' is TRUE, stop syncing when character becomes available, but * always sync at least one block. */ -void ml_sync_all(check_file, check_char) -int check_file; -int check_char; +void ml_sync_all(int check_file, int check_char) { buf_T *buf; struct stat st; @@ -1956,9 +1931,7 @@ int check_char; * * when message is TRUE the success of preserving is reported */ -void ml_preserve(buf, message) -buf_T *buf; -int message; +void ml_preserve(buf_T *buf, int message) { bhdr_T *hp; linenr_T lnum; @@ -2036,8 +2009,7 @@ theend: * On failure an error message is given and IObuff is returned (to avoid * having to check for error everywhere). */ -char_u * ml_get(lnum) -linenr_T lnum; +char_u *ml_get(linenr_T lnum) { return ml_get_buf(curbuf, lnum, FALSE); } @@ -2045,8 +2017,7 @@ linenr_T lnum; /* * Return pointer to position "pos". */ -char_u * ml_get_pos(pos) -pos_T *pos; +char_u *ml_get_pos(pos_T *pos) { return ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col; } @@ -2054,14 +2025,14 @@ pos_T *pos; /* * Return pointer to cursor line. */ -char_u * ml_get_curline() { +char_u *ml_get_curline(void) { return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE); } /* * Return pointer to cursor position. */ -char_u * ml_get_cursor() { +char_u *ml_get_cursor(void) { return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) + curwin->w_cursor.col; } @@ -2072,10 +2043,12 @@ char_u * ml_get_cursor() { * "will_change": if TRUE mark the buffer dirty (chars in the line will be * changed) */ -char_u * ml_get_buf(buf, lnum, will_change) -buf_T *buf; -linenr_T lnum; -int will_change; /* line will be changed */ +char_u * +ml_get_buf ( + buf_T *buf, + linenr_T lnum, + int will_change /* line will be changed */ +) { bhdr_T *hp; DATA_BL *dp; @@ -2143,7 +2116,7 @@ errorret: * Check if a line that was just obtained by a call to ml_get * is in allocated memory. */ -int ml_line_alloced() { +int ml_line_alloced(void) { return curbuf->b_ml.ml_flags & ML_LINE_DIRTY; } @@ -2159,11 +2132,13 @@ int ml_line_alloced() { * * return FAIL for failure, OK otherwise */ -int ml_append(lnum, line, len, newfile) -linenr_T lnum; /* append after this line (can be 0) */ -char_u *line; /* text of the new line */ -colnr_T len; /* length of new line, including NUL, or 0 */ -int newfile; /* flag, see above */ +int +ml_append ( + linenr_T lnum, /* append after this line (can be 0) */ + char_u *line, /* text of the new line */ + colnr_T len, /* length of new line, including NUL, or 0 */ + int newfile /* flag, see above */ +) { /* When starting up, we might still need to create the memfile */ if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) @@ -2178,12 +2153,14 @@ int newfile; /* flag, see above */ * Like ml_append() but for an arbitrary buffer. The buffer must already have * a memline. */ -int ml_append_buf(buf, lnum, line, len, newfile) -buf_T *buf; -linenr_T lnum; /* append after this line (can be 0) */ -char_u *line; /* text of the new line */ -colnr_T len; /* length of new line, including NUL, or 0 */ -int newfile; /* flag, see above */ +int +ml_append_buf ( + buf_T *buf, + linenr_T lnum, /* append after this line (can be 0) */ + char_u *line, /* text of the new line */ + colnr_T len, /* length of new line, including NUL, or 0 */ + int newfile /* flag, see above */ +) { if (buf->b_ml.ml_mfp == NULL) return FAIL; @@ -2193,13 +2170,15 @@ int newfile; /* flag, see above */ return ml_append_int(buf, lnum, line, len, newfile, FALSE); } -static int ml_append_int(buf, lnum, line, len, newfile, mark) -buf_T *buf; -linenr_T lnum; /* append after this line (can be 0) */ -char_u *line; /* text of the new line */ -colnr_T len; /* length of line, including NUL, or 0 */ -int newfile; /* flag, see above */ -int mark; /* mark the new line */ +static int +ml_append_int ( + buf_T *buf, + linenr_T lnum, /* append after this line (can be 0) */ + char_u *line, /* text of the new line */ + colnr_T len, /* length of line, including NUL, or 0 */ + int newfile, /* flag, see above */ + int mark /* mark the new line */ +) { int i; int line_count; /* number of indexes in current block */ @@ -2656,10 +2635,7 @@ int mark; /* mark the new line */ * * return FAIL for failure, OK otherwise */ -int ml_replace(lnum, line, copy) -linenr_T lnum; -char_u *line; -int copy; +int ml_replace(linenr_T lnum, char_u *line, int copy) { if (line == NULL) /* just checking... */ return FAIL; @@ -2689,18 +2665,13 @@ int copy; * * return FAIL for failure, OK otherwise */ -int ml_delete(lnum, message) -linenr_T lnum; -int message; +int ml_delete(linenr_T lnum, int message) { ml_flush_line(curbuf); return ml_delete_int(curbuf, lnum, message); } -static int ml_delete_int(buf, lnum, message) -buf_T *buf; -linenr_T lnum; -int message; +static int ml_delete_int(buf_T *buf, linenr_T lnum, int message) { bhdr_T *hp; memfile_T *mfp; @@ -2842,8 +2813,7 @@ int message; /* * set the B_MARKED flag for line 'lnum' */ -void ml_setmarked(lnum) -linenr_T lnum; +void ml_setmarked(linenr_T lnum) { bhdr_T *hp; DATA_BL *dp; @@ -2871,7 +2841,7 @@ linenr_T lnum; /* * find the first line with its B_MARKED flag set */ -linenr_T ml_firstmarked() { +linenr_T ml_firstmarked(void) { bhdr_T *hp; DATA_BL *dp; linenr_T lnum; @@ -2911,7 +2881,7 @@ linenr_T ml_firstmarked() { /* * clear all DB_MARKED flags */ -void ml_clearmarked() { +void ml_clearmarked(void) { bhdr_T *hp; DATA_BL *dp; linenr_T lnum; @@ -2949,8 +2919,7 @@ void ml_clearmarked() { /* * flush ml_line if necessary */ -static void ml_flush_line(buf) -buf_T *buf; +static void ml_flush_line(buf_T *buf) { bhdr_T *hp; DATA_BL *dp; @@ -3046,10 +3015,7 @@ buf_T *buf; /* * create a new, empty, data block */ -static bhdr_T * ml_new_data(mfp, negative, page_count) -memfile_T *mfp; -int negative; -int page_count; +static bhdr_T *ml_new_data(memfile_T *mfp, int negative, int page_count) { bhdr_T *hp; DATA_BL *dp; @@ -3069,8 +3035,7 @@ int page_count; /* * create a new, empty, pointer block */ -static bhdr_T * ml_new_ptr(mfp) -memfile_T *mfp; +static bhdr_T *ml_new_ptr(memfile_T *mfp) { bhdr_T *hp; PTR_BL *pp; @@ -3102,10 +3067,7 @@ memfile_T *mfp; * * return: NULL for failure, pointer to block header otherwise */ -static bhdr_T * ml_find_line(buf, lnum, action) -buf_T *buf; -linenr_T lnum; -int action; +static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action) { DATA_BL *dp; PTR_BL *pp; @@ -3286,8 +3248,7 @@ error_noblock: * * return -1 for failure, number of the new entry otherwise */ -static int ml_add_stack(buf) -buf_T *buf; +static int ml_add_stack(buf_T *buf) { int top; infoptr_T *newstack; @@ -3323,9 +3284,7 @@ buf_T *buf; * * Count is the number of lines added, negative if lines have been deleted. */ -static void ml_lineadd(buf, count) -buf_T *buf; -int count; +static void ml_lineadd(buf_T *buf, int count) { int idx; infoptr_T *ip; @@ -3357,9 +3316,7 @@ int count; * If it worked returns OK and the resolved link in "buf[MAXPATHL]". * Otherwise returns FAIL. */ -int resolve_symlink(fname, buf) -char_u *fname; -char_u *buf; +int resolve_symlink(char_u *fname, char_u *buf) { char_u tmp[MAXPATHL]; int ret; @@ -3427,11 +3384,7 @@ char_u *buf; * Make swap file name out of the file name and a directory name. * Returns pointer to allocated memory or NULL. */ -char_u * makeswapname(fname, ffname, buf, dir_name) -char_u *fname; -char_u *ffname UNUSED; -buf_T *buf; -char_u *dir_name; +char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name) { char_u *r, *s; char_u *fname_res = fname; @@ -3494,9 +3447,11 @@ char_u *dir_name; * * The return value is an allocated string and can be NULL. */ -char_u * get_file_in_dir(fname, dname) -char_u *fname; -char_u *dname; /* don't use "dirname", it is a global for Alpha */ +char_u * +get_file_in_dir ( + char_u *fname, + char_u *dname /* don't use "dirname", it is a global for Alpha */ +) { char_u *t; char_u *tail; @@ -3534,9 +3489,11 @@ static void attention_message __ARGS((buf_T *buf, char_u *fname)); /* * Print the ATTENTION message: info about an existing swap file. */ -static void attention_message(buf, fname) -buf_T *buf; /* buffer being edited */ -char_u *fname; /* swap file name */ +static void +attention_message ( + buf_T *buf, /* buffer being edited */ + char_u *fname /* swap file name */ +) { struct stat st; time_t x, sx; @@ -3591,9 +3548,7 @@ static int do_swapexists __ARGS((buf_T *buf, char_u *fname)); * 5: quit * 6: abort */ -static int do_swapexists(buf, fname) -buf_T *buf; -char_u *fname; +static int do_swapexists(buf_T *buf, char_u *fname) { set_vim_var_string(VV_SWAPNAME, fname, -1); set_vim_var_string(VV_SWAPCHOICE, NULL, -1); @@ -3629,10 +3584,12 @@ char_u *fname; * not being able to open the swap or undo file * Note: May trigger SwapExists autocmd, pointers may change! */ -static char_u * findswapname(buf, dirp, old_fname) -buf_T *buf; -char_u **dirp; /* pointer to list of directories */ -char_u *old_fname; /* don't give warning for this file name */ +static char_u * +findswapname ( + buf_T *buf, + char_u **dirp, /* pointer to list of directories */ + char_u *old_fname /* don't give warning for this file name */ +) { char_u *fname; int n; @@ -4030,8 +3987,7 @@ char_u *old_fname; /* don't give warning for this file name */ return fname; } -static int b0_magic_wrong(b0p) -ZERO_BL *b0p; +static int b0_magic_wrong(ZERO_BL *b0p) { return b0p->b0_magic_long != (long)B0_MAGIC_LONG || b0p->b0_magic_int != (int)B0_MAGIC_INT @@ -4089,10 +4045,12 @@ ZERO_BL *b0p; * versions. */ -static int fnamecmp_ino(fname_c, fname_s, ino_block0) -char_u *fname_c; /* current file name */ -char_u *fname_s; /* file name from swap file */ -long ino_block0; +static int +fnamecmp_ino ( + char_u *fname_c, /* current file name */ + char_u *fname_s, /* file name from swap file */ + long ino_block0 +) { struct stat st; ino_t ino_c = 0; /* ino of current file */ @@ -4141,9 +4099,7 @@ long ino_block0; * Move a long integer into a four byte character array. * Used for machine independency in block zero. */ -static void long_to_char(n, s) -long n; -char_u *s; +static void long_to_char(long n, char_u *s) { s[0] = (char_u)(n & 0xff); n = (unsigned)n >> 8; @@ -4154,8 +4110,7 @@ char_u *s; s[3] = (char_u)(n & 0xff); } -static long char_to_long(s) -char_u *s; +static long char_to_long(char_u *s) { long retval; @@ -4176,8 +4131,7 @@ char_u *s; * - 'fileformat' * - 'fileencoding' */ -void ml_setflags(buf) -buf_T *buf; +void ml_setflags(buf_T *buf) { bhdr_T *hp; ZERO_BL *b0p; @@ -4203,11 +4157,7 @@ buf_T *buf; * in allocated memory. Return NULL when out of memory. * Otherwise return "data". */ -char_u * ml_encrypt_data(mfp, data, offset, size) -memfile_T *mfp; -char_u *data; -off_t offset; -unsigned size; +char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_t offset, unsigned size) { DATA_BL *dp = (DATA_BL *)data; char_u *head_end; @@ -4244,11 +4194,7 @@ unsigned size; /* * Decrypt the text in "data" if it points to a data block. */ -void ml_decrypt_data(mfp, data, offset, size) -memfile_T *mfp; -char_u *data; -off_t offset; -unsigned size; +void ml_decrypt_data(memfile_T *mfp, char_u *data, off_t offset, unsigned size) { DATA_BL *dp = (DATA_BL *)data; char_u *head_end; @@ -4275,10 +4221,7 @@ unsigned size; /* * Prepare for encryption/decryption, using the key, seed and offset. */ -static void ml_crypt_prepare(mfp, offset, reading) -memfile_T *mfp; -off_t offset; -int reading; +static void ml_crypt_prepare(memfile_T *mfp, off_t offset, int reading) { buf_T *buf = mfp->mf_buffer; char_u salt[50]; @@ -4323,11 +4266,7 @@ int reading; * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity. */ -static void ml_updatechunk(buf, line, len, updtype) -buf_T *buf; -linenr_T line; -long len; -int updtype; +static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype) { static buf_T *ml_upd_lastbuf = NULL; static linenr_T ml_upd_lastline; @@ -4533,10 +4472,7 @@ int updtype; * Find offset of line if "lnum" > 0 * return -1 if information is not available */ -long ml_find_line_or_offset(buf, lnum, offp) -buf_T *buf; -linenr_T lnum; -long *offp; +long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp) { linenr_T curline; int curix; @@ -4652,8 +4588,7 @@ long *offp; /* * Goto byte in buffer with offset 'cnt'. */ -void goto_byte(cnt) -long cnt; +void goto_byte(long cnt) { long boff = cnt; linenr_T lnum; diff --git a/src/menu.c b/src/menu.c index 12e91b0ae6..bb62296a61 100644 --- a/src/menu.c +++ b/src/menu.c @@ -53,8 +53,10 @@ static char_u e_nomenu[] = N_("E329: No menu \"%s\""); /* * Do the :menu command and relatives. */ -void ex_menu(eap) -exarg_T *eap; /* Ex command arguments */ +void +ex_menu ( + exarg_T *eap /* Ex command arguments */ +) { char_u *menu_path; int modes; @@ -262,12 +264,14 @@ theend: /* * Add the menu with the given name to the menu hierarchy */ -static int add_menu_path(menu_path, menuarg, pri_tab, call_data) -char_u *menu_path; -vimmenu_T *menuarg; /* passes modes, iconfile, iconidx, +static int +add_menu_path ( + char_u *menu_path, + vimmenu_T *menuarg, /* passes modes, iconfile, iconidx, icon_builtin, silent[0], noremap[0] */ -int *pri_tab; -char_u *call_data; + int *pri_tab, + char_u *call_data +) { char_u *path_name; int modes = menuarg->modes; @@ -506,11 +510,7 @@ erret: * Set the (sub)menu with the given name to enabled or disabled. * Called recursively. */ -static int menu_nable_recurse(menu, name, modes, enable) -vimmenu_T *menu; -char_u *name; -int modes; -int enable; +static int menu_nable_recurse(vimmenu_T *menu, char_u *name, int modes, int enable) { char_u *p; @@ -559,11 +559,13 @@ int enable; * Remove the (sub)menu with the given name from the menu hierarchy * Called recursively. */ -static int remove_menu(menup, name, modes, silent) -vimmenu_T **menup; -char_u *name; -int modes; -int silent; /* don't give error messages */ +static int +remove_menu ( + vimmenu_T **menup, + char_u *name, + int modes, + int silent /* don't give error messages */ +) { vimmenu_T *menu; vimmenu_T *child; @@ -666,8 +668,7 @@ int silent; /* don't give error messages */ /* * Free the given menu structure and remove it from the linked list. */ -static void free_menu(menup) -vimmenu_T **menup; +static void free_menu(vimmenu_T **menup) { int i; vimmenu_T *menu; @@ -692,9 +693,7 @@ vimmenu_T **menup; /* * Free the menu->string with the given index. */ -static void free_menu_string(menu, idx) -vimmenu_T *menu; -int idx; +static void free_menu_string(vimmenu_T *menu, int idx) { int count = 0; int i; @@ -710,9 +709,7 @@ int idx; /* * Show the mapping associated with a menu item or hierarchy in a sub-menu. */ -static int show_menus(path_name, modes) -char_u *path_name; -int modes; +static int show_menus(char_u *path_name, int modes) { char_u *p; char_u *name; @@ -765,10 +762,7 @@ int modes; /* * Recursively show the mappings associated with the menus under the given one */ -static void show_menus_recursive(menu, modes, depth) -vimmenu_T *menu; -int modes; -int depth; +static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) { int i; int bit; @@ -844,11 +838,7 @@ static int expand_emenu; /* TRUE for ":emenu" command */ /* * Work out what to complete when doing command line completion of menu names. */ -char_u * set_context_in_menu_cmd(xp, cmd, arg, forceit) -expand_T *xp; -char_u *cmd; -char_u *arg; -int forceit; +char_u *set_context_in_menu_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit) { char_u *after_dot; char_u *p; @@ -952,9 +942,7 @@ int forceit; * Function given to ExpandGeneric() to obtain the list of (sub)menus (not * entries). */ -char_u * get_menu_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_menu_name(expand_T *xp, int idx) { static vimmenu_T *menu = NULL; char_u *str; @@ -999,9 +987,7 @@ int idx; * Function given to ExpandGeneric() to obtain the list of menus and menu * entries. */ -char_u * get_menu_names(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_menu_names(expand_T *xp, int idx) { static vimmenu_T *menu = NULL; #define TBUFFER_LEN 256 @@ -1065,8 +1051,7 @@ int idx; * element. Any \ and ^Vs are removed from the current element. * "name" may be modified. */ -char_u * menu_name_skip(name) -char_u *name; +char_u *menu_name_skip(char_u *name) { char_u *p; @@ -1086,9 +1071,7 @@ char_u *name; * Return TRUE when "name" matches with menu "menu". The name is compared in * two ways: raw menu name and menu name without '&'. ignore part after a TAB. */ -static int menu_name_equal(name, menu) -char_u *name; -vimmenu_T *menu; +static int menu_name_equal(char_u *name, vimmenu_T *menu) { if (menu->en_name != NULL && (menu_namecmp(name, menu->en_name) @@ -1097,9 +1080,7 @@ vimmenu_T *menu; return menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname); } -static int menu_namecmp(name, mname) -char_u *name; -char_u *mname; +static int menu_namecmp(char_u *name, char_u *mname) { int i; @@ -1118,11 +1099,13 @@ char_u *mname; * If "unmenu" is not NULL, then the flag it points to is set according to * whether the command is an "unmenu" command. */ -static int get_menu_cmd_modes(cmd, forceit, noremap, unmenu) -char_u *cmd; -int forceit; /* Was there a "!" after the command? */ -int *noremap; -int *unmenu; +static int +get_menu_cmd_modes ( + char_u *cmd, + int forceit, /* Was there a "!" after the command? */ + int *noremap, + int *unmenu +) { int modes; @@ -1179,9 +1162,7 @@ int *unmenu; * Modify a menu name starting with "PopUp" to include the mode character. * Returns the name in allocated memory (NULL for failure). */ -static char_u * popup_mode_name(name, idx) -char_u *name; -int idx; +static char_u *popup_mode_name(char_u *name, int idx) { char_u *p; int len = (int)STRLEN(name); @@ -1202,10 +1183,7 @@ int idx; * If mnemonic != NULL, *mnemonic is set to the character after the first '&'. * If actext != NULL, *actext is set to the text after the first TAB. */ -static char_u * menu_text(str, mnemonic, actext) -char_u *str; -int *mnemonic; -char_u **actext; +static char_u *menu_text(char_u *str, int *mnemonic, char_u **actext) { char_u *p; char_u *text; @@ -1251,8 +1229,7 @@ char_u **actext; /* * Return TRUE if "name" can be a menu in the MenuBar. */ -int menu_is_menubar(name) -char_u *name; +int menu_is_menubar(char_u *name) { return !menu_is_popup(name) && !menu_is_toolbar(name) @@ -1262,8 +1239,7 @@ char_u *name; /* * Return TRUE if "name" is a popup menu name. */ -int menu_is_popup(name) -char_u *name; +int menu_is_popup(char_u *name) { return STRNCMP(name, "PopUp", 5) == 0; } @@ -1272,8 +1248,7 @@ char_u *name; /* * Return TRUE if "name" is a toolbar menu name. */ -int menu_is_toolbar(name) -char_u *name; +int menu_is_toolbar(char_u *name) { return STRNCMP(name, "ToolBar", 7) == 0; } @@ -1282,8 +1257,7 @@ char_u *name; * Return TRUE if the name is a menu separator identifier: Starts and ends * with '-' */ -int menu_is_separator(name) -char_u *name; +int menu_is_separator(char_u *name) { return name[0] == '-' && name[STRLEN(name) - 1] == '-'; } @@ -1291,8 +1265,7 @@ char_u *name; /* * Return TRUE if the menu is hidden: Starts with ']' */ -static int menu_is_hidden(name) -char_u *name; +static int menu_is_hidden(char_u *name) { return (name[0] == ']') || (menu_is_popup(name) && name[5] != NUL); } @@ -1302,8 +1275,7 @@ char_u *name; /* * Return TRUE if the menu is the tearoff menu. */ -static int menu_is_tearoff(name) -char_u *name UNUSED; +static int menu_is_tearoff(char_u *name) { return FALSE; } @@ -1315,8 +1287,7 @@ char_u *name UNUSED; * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and * execute it. */ -void ex_emenu(eap) -exarg_T *eap; +void ex_emenu(exarg_T *eap) { vimmenu_T *menu; char_u *name; @@ -1430,8 +1401,7 @@ exarg_T *eap; /* * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy. */ -vimmenu_T * gui_find_menu(path_name) -char_u *path_name; +vimmenu_T *gui_find_menu(char_u *path_name) { vimmenu_T *menu = NULL; char_u *name; @@ -1499,8 +1469,7 @@ static garray_T menutrans_ga = {0, 0, 0, 0, NULL}; * This function is also defined without the +multi_lang feature, in which * case the commands are ignored. */ -void ex_menutranslate(eap) -exarg_T *eap UNUSED; +void ex_menutranslate(exarg_T *eap) { char_u *arg = eap->arg; menutrans_T *tp; @@ -1562,8 +1531,7 @@ exarg_T *eap UNUSED; /* * Find the character just after one part of a menu name. */ -static char_u * menu_skip_part(p) -char_u *p; +static char_u *menu_skip_part(char_u *p) { while (*p != NUL && *p != '.' && !vim_iswhite(*p)) { if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL) @@ -1577,9 +1545,7 @@ char_u *p; * Lookup part of a menu name in the translations. * Return a pointer to the translation or NULL if not found. */ -static char_u * menutrans_lookup(name, len) -char_u *name; -int len; +static char_u *menutrans_lookup(char_u *name, int len) { menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data; int i; @@ -1609,8 +1575,7 @@ int len; /* * Unescape the name in the translate dictionary table. */ -static void menu_unescape_name(name) -char_u *name; +static void menu_unescape_name(char_u *name) { char_u *p; @@ -1623,8 +1588,7 @@ char_u *name; * Isolate the menu name. * Skip the menu name, and translate into a real TAB. */ -static char_u * menu_translate_tab_and_shift(arg_start) -char_u *arg_start; +static char_u *menu_translate_tab_and_shift(char_u *arg_start) { char_u *arg = arg_start; diff --git a/src/message.c b/src/message.c index 9a9fd87f72..062a196636 100644 --- a/src/message.c +++ b/src/message.c @@ -100,8 +100,7 @@ static int verbose_did_open = FALSE; * When terminal not initialized (yet) mch_errmsg(..) is used. * return TRUE if wait_return not called */ -int msg(s) -char_u *s; +int msg(char_u *s) { return msg_attr_keep(s, 0, FALSE); } @@ -111,8 +110,7 @@ char_u *s; /* * Like msg() but keep it silent when 'verbosefile' is set. */ -int verb_msg(s) -char_u *s; +int verb_msg(char_u *s) { int n; @@ -124,17 +122,17 @@ char_u *s; } #endif -int msg_attr(s, attr) -char_u *s; -int attr; +int msg_attr(char_u *s, int attr) { return msg_attr_keep(s, attr, FALSE); } -int msg_attr_keep(s, attr, keep) -char_u *s; -int attr; -int keep; /* TRUE: set keep_msg if it doesn't scroll */ +int +msg_attr_keep ( + char_u *s, + int attr, + int keep /* TRUE: set keep_msg if it doesn't scroll */ +) { static int entered = 0; int retval; @@ -189,9 +187,11 @@ int keep; /* TRUE: set keep_msg if it doesn't scroll */ * Truncate a string such that it can be printed without causing a scroll. * Returns an allocated string or NULL when no truncating is done. */ -char_u * msg_strtrunc(s, force) -char_u *s; -int force; /* always truncate */ +char_u * +msg_strtrunc ( + char_u *s, + int force /* always truncate */ +) { char_u *buf = NULL; int len; @@ -229,11 +229,7 @@ int force; /* always truncate */ * Truncate a string "s" to "buf" with cell width "room". * "s" and "buf" may be equal. */ -void trunc_string(s, buf, room, buflen) -char_u *s; -char_u *buf; -int room; -int buflen; +void trunc_string(char_u *s, char_u *buf, int room, int buflen) { int half; int len; @@ -331,18 +327,13 @@ int vim_snprintf __ARGS((char *, size_t, char *, long, long, long, */ /* VARARGS */ -int smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) -char_u *s; -long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; +int smsg(char_u *s, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) { return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } /* VARARGS */ -int smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) -int attr; -char_u *s; -long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; +int smsg_attr(int attr, char_u *s, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) { vim_snprintf((char *)IObuff, IOSIZE, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); @@ -384,7 +375,7 @@ static char_u *last_sourcing_name = NULL; * Reset the last used sourcing name/lnum. Makes sure it is displayed again * for the next error message; */ -void reset_last_sourcing() { +void reset_last_sourcing(void) { vim_free(last_sourcing_name); last_sourcing_name = NULL; last_sourcing_lnum = 0; @@ -393,7 +384,7 @@ void reset_last_sourcing() { /* * Return TRUE if "sourcing_name" differs from "last_sourcing_name". */ -static int other_sourcing_name() { +static int other_sourcing_name(void) { if (sourcing_name != NULL) { if (last_sourcing_name != NULL) return STRCMP(sourcing_name, last_sourcing_name) != 0; @@ -407,7 +398,7 @@ static int other_sourcing_name() { * Returns an allocated string with room for one more character. * Returns NULL when no message is to be given. */ -static char_u * get_emsg_source() { +static char_u *get_emsg_source(void) { char_u *Buf, *p; if (sourcing_name != NULL && other_sourcing_name()) { @@ -425,7 +416,7 @@ static char_u * get_emsg_source() { * Returns an allocated string with room for one more character. * Returns NULL when no message is to be given. */ -static char_u * get_emsg_lnum() { +static char_u *get_emsg_lnum(void) { char_u *Buf, *p; /* lnum is 0 when executing a command from the command line @@ -447,8 +438,7 @@ static char_u * get_emsg_lnum() { * Remember the file name and line number, so that for the next error the info * is only displayed if it changed. */ -void msg_source(attr) -int attr; +void msg_source(int attr) { char_u *p; @@ -482,7 +472,7 @@ int attr; * If "msg" is in 'debug': do error message but without side effects. * If "emsg_skip" is set: never do error messages. */ -int emsg_not_now() { +int emsg_not_now(void) { if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL && vim_strchr(p_debug, 't') == NULL) || emsg_skip > 0 @@ -499,8 +489,7 @@ int emsg_not_now() { * * return TRUE if wait_return not called */ -int emsg(s) -char_u *s; +int emsg(char_u *s) { int attr; char_u *p; @@ -598,16 +587,14 @@ char_u *s; /* * Print an error message with one "%s" and one string argument. */ -int emsg2(s, a1) -char_u *s, *a1; +int emsg2(char_u *s, char_u *a1) { return emsg3(s, a1, NULL); } /* emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. */ -void emsg_invreg(name) -int name; +void emsg_invreg(int name) { EMSG2(_("E354: Invalid register name: '%s'"), transchar(name)); } @@ -618,10 +605,7 @@ int name; * Careful: The string may be changed by msg_may_trunc()! * Returns a pointer to the printed message, if wait_return() not called. */ -char_u * msg_trunc_attr(s, force, attr) -char_u *s; -int force; -int attr; +char_u *msg_trunc_attr(char_u *s, int force, int attr) { int n; @@ -644,9 +628,7 @@ int attr; * Return a pointer to where the truncated message starts. * Note: May change the message by replacing a character with '<'. */ -char_u * msg_may_trunc(force, s) -int force; -char_u *s; +char_u *msg_may_trunc(int force, char_u *s) { int n; int room; @@ -673,10 +655,12 @@ char_u *s; return s; } -static void add_msg_hist(s, len, attr) -char_u *s; -int len; /* -1 for undetermined length */ -int attr; +static void +add_msg_hist ( + char_u *s, + int len, /* -1 for undetermined length */ + int attr +) { struct msg_hist *p; @@ -715,7 +699,7 @@ int attr; * Delete the first (oldest) message from the history. * Returns FAIL if there are no messages. */ -int delete_first_msg() { +int delete_first_msg(void) { struct msg_hist *p; if (msg_hist_len <= 0) @@ -733,8 +717,7 @@ int delete_first_msg() { /* * ":messages" command. */ -void ex_messages(eap) -exarg_T *eap UNUSED; +void ex_messages(exarg_T *eap) { struct msg_hist *p; char_u *s; @@ -758,7 +741,7 @@ exarg_T *eap UNUSED; * Call this after prompting the user. This will avoid a hit-return message * and a delay. */ -void msg_end_prompt() { +void msg_end_prompt(void) { need_wait_return = FALSE; emsg_on_display = FALSE; cmdline_row = msg_row; @@ -773,8 +756,7 @@ void msg_end_prompt() { * if 'redraw' is FALSE, just redraw the screen * if 'redraw' is -1, don't redraw at all */ -void wait_return(redraw) -int redraw; +void wait_return(int redraw) { int c; int oldState; @@ -977,7 +959,7 @@ int redraw; /* * Write the hit-return prompt. */ -static void hit_return_msg() { +static void hit_return_msg(void) { int save_p_more = p_more; p_more = FALSE; /* don't want see this message when scrolling back */ @@ -995,9 +977,7 @@ static void hit_return_msg() { /* * Set "keep_msg" to "s". Free the old value and check for NULL pointer. */ -void set_keep_msg(s, attr) -char_u *s; -int attr; +void set_keep_msg(char_u *s, int attr) { vim_free(keep_msg); if (s != NULL && msg_silent == 0) @@ -1012,7 +992,7 @@ int attr; * If there currently is a message being displayed, set "keep_msg" to it, so * that it will be displayed again after redraw. */ -void set_keep_msg_from_hist() { +void set_keep_msg_from_hist(void) { if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0 && (State & NORMAL)) set_keep_msg(last_msg_hist->msg, last_msg_hist->attr); @@ -1021,7 +1001,7 @@ void set_keep_msg_from_hist() { /* * Prepare for outputting characters in the command line. */ -void msg_start() { +void msg_start(void) { int did_return = FALSE; if (!msg_silent) { @@ -1062,20 +1042,17 @@ void msg_start() { /* * Note that the current msg position is where messages start. */ -void msg_starthere() { +void msg_starthere(void) { lines_left = cmdline_row; msg_didany = FALSE; } -void msg_putchar(c) -int c; +void msg_putchar(int c) { msg_putchar_attr(c, 0); } -void msg_putchar_attr(c, attr) -int c; -int attr; +void msg_putchar_attr(int c, int attr) { char_u buf[MB_MAXBYTES + 1]; @@ -1090,8 +1067,7 @@ int attr; msg_puts_attr(buf, attr); } -void msg_outnum(n) -long n; +void msg_outnum(long n) { char_u buf[20]; @@ -1099,21 +1075,17 @@ long n; msg_puts(buf); } -void msg_home_replace(fname) -char_u *fname; +void msg_home_replace(char_u *fname) { msg_home_replace_attr(fname, 0); } -void msg_home_replace_hl(fname) -char_u *fname; +void msg_home_replace_hl(char_u *fname) { msg_home_replace_attr(fname, hl_attr(HLF_D)); } -static void msg_home_replace_attr(fname, attr) -char_u *fname; -int attr; +static void msg_home_replace_attr(char_u *fname, int attr) { char_u *name; @@ -1129,22 +1101,17 @@ int attr; * Use attributes 'attr'. * Return the number of characters it takes on the screen. */ -int msg_outtrans(str) -char_u *str; +int msg_outtrans(char_u *str) { return msg_outtrans_attr(str, 0); } -int msg_outtrans_attr(str, attr) -char_u *str; -int attr; +int msg_outtrans_attr(char_u *str, int attr) { return msg_outtrans_len_attr(str, (int)STRLEN(str), attr); } -int msg_outtrans_len(str, len) -char_u *str; -int len; +int msg_outtrans_len(char_u *str, int len) { return msg_outtrans_len_attr(str, len, 0); } @@ -1153,9 +1120,7 @@ int len; * Output one character at "p". Return pointer to the next character. * Handles multi-byte characters. */ -char_u * msg_outtrans_one(p, attr) -char_u *p; -int attr; +char_u *msg_outtrans_one(char_u *p, int attr) { int l; @@ -1167,10 +1132,7 @@ int attr; return p + 1; } -int msg_outtrans_len_attr(msgstr, len, attr) -char_u *msgstr; -int len; -int attr; +int msg_outtrans_len_attr(char_u *msgstr, int len, int attr) { int retval = 0; char_u *str = msgstr; @@ -1243,8 +1205,7 @@ int attr; return retval; } -void msg_make(arg) -char_u *arg; +void msg_make(char_u *arg) { int i; static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB"; @@ -1274,9 +1235,11 @@ char_u *arg; * This function is used to show mappings, where we want to see how to type * the character/string -- webb */ -int msg_outtrans_special(strstart, from) -char_u *strstart; -int from; /* TRUE for lhs of a mapping */ +int +msg_outtrans_special ( + char_u *strstart, + int from /* TRUE for lhs of a mapping */ +) { char_u *str = strstart; int retval = 0; @@ -1306,9 +1269,11 @@ int from; /* TRUE for lhs of a mapping */ * Return the lhs or rhs of a mapping, with the key codes turned into printable * strings, in an allocated string. */ -char_u * str2special_save(str, is_lhs) -char_u *str; -int is_lhs; /* TRUE for lhs, FALSE for rhs */ +char_u * +str2special_save ( + char_u *str, + int is_lhs /* TRUE for lhs, FALSE for rhs */ +) { garray_T ga; char_u *p = str; @@ -1325,9 +1290,11 @@ int is_lhs; /* TRUE for lhs, FALSE for rhs */ * Used for translating the lhs or rhs of a mapping to printable chars. * Advances "sp" to the next code. */ -char_u * str2special(sp, from) -char_u **sp; -int from; /* TRUE for lhs of mapping */ +char_u * +str2special ( + char_u **sp, + int from /* TRUE for lhs of mapping */ +) { int c; static char_u buf[7]; @@ -1390,10 +1357,7 @@ int from; /* TRUE for lhs of mapping */ /* * Translate a key sequence into special key names. */ -void str2specialbuf(sp, buf, len) -char_u *sp; -char_u *buf; -int len; +void str2specialbuf(char_u *sp, char_u *buf, int len) { char_u *s; @@ -1408,9 +1372,7 @@ int len; /* * print line for :print or :list command */ -void msg_prt_line(s, list) -char_u *s; -int list; +void msg_prt_line(char_u *s, int list) { int c; int col = 0; @@ -1508,10 +1470,7 @@ int list; * Use screen_puts() to output one multi-byte character. * Return the pointer "s" advanced to the next character. */ -static char_u * screen_puts_mbyte(s, l, attr) -char_u *s; -int l; -int attr; +static char_u *screen_puts_mbyte(char_u *s, int l, int attr) { int cw; @@ -1546,14 +1505,12 @@ int attr; * Output a string to the screen at position msg_row, msg_col. * Update msg_row and msg_col for the next message. */ -void msg_puts(s) -char_u *s; +void msg_puts(char_u *s) { msg_puts_attr(s, 0); } -void msg_puts_title(s) -char_u *s; +void msg_puts_title(char_u *s) { msg_puts_attr(s, hl_attr(HLF_T)); } @@ -1563,17 +1520,12 @@ char_u *s; * part in the middle and replace it with "..." when necessary. * Does not handle multi-byte characters! */ -void msg_puts_long_attr(longstr, attr) -char_u *longstr; -int attr; +void msg_puts_long_attr(char_u *longstr, int attr) { msg_puts_long_len_attr(longstr, (int)STRLEN(longstr), attr); } -void msg_puts_long_len_attr(longstr, len, attr) -char_u *longstr; -int len; -int attr; +void msg_puts_long_len_attr(char_u *longstr, int len, int attr) { int slen = len; int room; @@ -1590,9 +1542,7 @@ int attr; /* * Basic function for writing a message with highlight attributes. */ -void msg_puts_attr(s, attr) -char_u *s; -int attr; +void msg_puts_attr(char_u *s, int attr) { msg_puts_attr_len(s, -1, attr); } @@ -1602,10 +1552,7 @@ int attr; * When "maxlen" is -1 there is no maximum length. * When "maxlen" is >= 0 the message is not put in the history. */ -static void msg_puts_attr_len(str, maxlen, attr) -char_u *str; -int maxlen; -int attr; +static void msg_puts_attr_len(char_u *str, int maxlen, int attr) { /* * If redirection is on, also write to the redirection file. @@ -1651,11 +1598,7 @@ int attr; * The display part of msg_puts_attr_len(). * May be called recursively to display scroll-back text. */ -static void msg_puts_display(str, maxlen, attr, recurse) -char_u *str; -int maxlen; -int attr; -int recurse; +static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse) { char_u *s = str; char_u *t_s = str; /* string from "t_s" to "s" is still todo */ @@ -1841,7 +1784,7 @@ int recurse; /* * Scroll the screen up one line for displaying the next message line. */ -static void msg_scroll_up() { +static void msg_scroll_up(void) { /* scrolling up always works */ screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL); @@ -1862,7 +1805,7 @@ static void msg_scroll_up() { /* * Increment "msg_scrolled". */ -static void inc_msg_scrolled() { +static void inc_msg_scrolled(void) { if (*get_vim_var_str(VV_SCROLLSTART) == NUL) { char_u *p = sourcing_name; char_u *tofree = NULL; @@ -1911,12 +1854,14 @@ static int do_clear_sb_text = FALSE; /* clear text on next msg */ /* * Store part of a printed message for displaying when scrolling back. */ -static void store_sb_text(sb_str, s, attr, sb_col, finish) -char_u **sb_str; /* start of string */ -char_u *s; /* just after string */ -int attr; -int *sb_col; -int finish; /* line ends */ +static void +store_sb_text ( + char_u **sb_str, /* start of string */ + char_u *s, /* just after string */ + int attr, + int *sb_col, + int finish /* line ends */ +) { msgchunk_T *mp; @@ -1953,7 +1898,7 @@ int finish; /* line ends */ /* * Finished showing messages, clear the scroll-back text on the next message. */ -void may_clear_sb_text() { +void may_clear_sb_text(void) { do_clear_sb_text = TRUE; } @@ -1961,7 +1906,7 @@ void may_clear_sb_text() { * Clear any text remembered for scrolling back. * Called when redrawing the screen. */ -void clear_sb_text() { +void clear_sb_text(void) { msgchunk_T *mp; while (last_msgchunk != NULL) { @@ -1974,7 +1919,7 @@ void clear_sb_text() { /* * "g<" command. */ -void show_sb_text() { +void show_sb_text(void) { msgchunk_T *mp; /* Only show something if there is more than one line, otherwise it looks @@ -1991,8 +1936,7 @@ void show_sb_text() { /* * Move to the start of screen line in already displayed text. */ -static msgchunk_T * msg_sb_start(mps) -msgchunk_T *mps; +static msgchunk_T *msg_sb_start(msgchunk_T *mps) { msgchunk_T *mp = mps; @@ -2004,7 +1948,7 @@ msgchunk_T *mps; /* * Mark the last message chunk as finishing the line. */ -void msg_sb_eol() { +void msg_sb_eol(void) { if (last_msgchunk != NULL) last_msgchunk->sb_eol = TRUE; } @@ -2013,9 +1957,7 @@ void msg_sb_eol() { * Display a screen line from previously displayed text at row "row". * Returns a pointer to the text for the next line (can be NULL). */ -static msgchunk_T * disp_sb_line(row, smp) -int row; -msgchunk_T *smp; +static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp) { msgchunk_T *mp = smp; char_u *p; @@ -2037,11 +1979,7 @@ msgchunk_T *smp; /* * Output any postponed text for msg_puts_attr_len(). */ -static void t_puts(t_col, t_s, s, attr) -int *t_col; -char_u *t_s; -char_u *s; -int attr; +static void t_puts(int *t_col, char_u *t_s, char_u *s, int attr) { /* output postponed text */ msg_didout = TRUE; /* remember that line is not empty */ @@ -2066,7 +2004,7 @@ int attr; * different, e.g. for Win32 console) or we just don't know where the * cursor is. */ -int msg_use_printf() { +int msg_use_printf(void) { return !msg_check_screen() || (swapping_screen() && !termcap_active) ; @@ -2075,9 +2013,7 @@ int msg_use_printf() { /* * Print a message when there is no valid screen. */ -static void msg_puts_printf(str, maxlen) -char_u *str; -int maxlen; +static void msg_puts_printf(char_u *str, int maxlen) { char_u *s = str; char_u buf[4]; @@ -2126,8 +2062,7 @@ int maxlen; * otherwise it's NUL. * Returns TRUE when jumping ahead to "confirm_msg_tail". */ -static int do_more_prompt(typed_char) -int typed_char; +static int do_more_prompt(int typed_char) { int used_typed_char = typed_char; int oldState = State; @@ -2332,8 +2267,7 @@ int typed_char; * yet. When stderr can't be used, collect error messages until the GUI has * started and they can be displayed in a message box. */ -void mch_errmsg(str) -char *str; +void mch_errmsg(char *str) { int len; @@ -2386,8 +2320,7 @@ char *str; * When there is no tty, collect messages until the GUI has started and they * can be displayed in a message box. */ -void mch_msg(str) -char *str; +void mch_msg(char *str) { #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) /* On Unix use stdout if we have a tty. This allows "vim -h | more" and @@ -2411,9 +2344,7 @@ char *str; * Put a character on the screen at the current message position and advance * to the next position. Only for printable ASCII! */ -static void msg_screen_putchar(c, attr) -int c; -int attr; +static void msg_screen_putchar(int c, int attr) { msg_didout = TRUE; /* remember that line is not empty */ screen_putchar(c, msg_row, msg_col, attr); @@ -2430,8 +2361,7 @@ int attr; } } -void msg_moremsg(full) -int full; +void msg_moremsg(int full) { int attr; char_u *s = (char_u *)_("-- More --"); @@ -2448,7 +2378,7 @@ int full; * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or * exmode_active. */ -void repeat_message() { +void repeat_message(void) { if (State == ASKMORE) { msg_moremsg(TRUE); /* display --more-- message again */ msg_row = Rows - 1; @@ -2477,7 +2407,7 @@ void repeat_message() { * While starting the GUI the terminal codes will be set for the GUI, but the * output goes to the terminal. Don't use the terminal codes then. */ -static int msg_check_screen() { +static int msg_check_screen(void) { if (!full_screen || !screen_valid(FALSE)) return FALSE; @@ -2492,7 +2422,7 @@ static int msg_check_screen() { * Clear from current message position to end of screen. * Skip this when ":silent" was used, no need to clear for redirection. */ -void msg_clr_eos() { +void msg_clr_eos(void) { if (msg_silent == 0) msg_clr_eos_force(); } @@ -2502,7 +2432,7 @@ void msg_clr_eos() { * Note: msg_col is not updated, so we remember the end of the message * for msg_check(). */ -void msg_clr_eos_force() { +void msg_clr_eos_force(void) { if (msg_use_printf()) { if (full_screen) { /* only when termcap codes are valid */ if (*T_CD) @@ -2525,7 +2455,7 @@ void msg_clr_eos_force() { /* * Clear the command line. */ -void msg_clr_cmdline() { +void msg_clr_cmdline(void) { msg_row = cmdline_row; msg_col = 0; msg_clr_eos_force(); @@ -2536,7 +2466,7 @@ void msg_clr_cmdline() { * call wait_return if the message does not fit in the available space * return TRUE if wait_return not called. */ -int msg_end() { +int msg_end(void) { /* * If the string is larger than the window, * or the ruler option is set and we run into it, @@ -2555,7 +2485,7 @@ int msg_end() { * If the written message runs into the shown command or ruler, we have to * wait for hit-return and redraw the window later. */ -void msg_check() { +void msg_check(void) { if (msg_row == Rows - 1 && msg_col >= sc_col) { need_wait_return = TRUE; redraw_cmdline = TRUE; @@ -2566,9 +2496,7 @@ void msg_check() { * May write a string to the redirection file. * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes. */ -static void redir_write(str, maxlen) -char_u *str; -int maxlen; +static void redir_write(char_u *str, int maxlen) { char_u *s = str; static int cur_col = 0; @@ -2623,7 +2551,7 @@ int maxlen; } } -int redirecting() { +int redirecting(void) { return redir_fd != NULL || *p_vfile != NUL || redir_reg || redir_vname ; @@ -2633,7 +2561,7 @@ int redirecting() { * Before giving verbose message. * Must always be called paired with verbose_leave()! */ -void verbose_enter() { +void verbose_enter(void) { if (*p_vfile != NUL) ++msg_silent; } @@ -2642,7 +2570,7 @@ void verbose_enter() { * After giving verbose message. * Must always be called paired with verbose_enter()! */ -void verbose_leave() { +void verbose_leave(void) { if (*p_vfile != NUL) if (--msg_silent < 0) msg_silent = 0; @@ -2651,7 +2579,7 @@ void verbose_leave() { /* * Like verbose_enter() and set msg_scroll when displaying the message. */ -void verbose_enter_scroll() { +void verbose_enter_scroll(void) { if (*p_vfile != NUL) ++msg_silent; else @@ -2662,7 +2590,7 @@ void verbose_enter_scroll() { /* * Like verbose_leave() and set cmdline_row when displaying the message. */ -void verbose_leave_scroll() { +void verbose_leave_scroll(void) { if (*p_vfile != NUL) { if (--msg_silent < 0) msg_silent = 0; @@ -2673,7 +2601,7 @@ void verbose_leave_scroll() { /* * Called when 'verbosefile' is set: stop writing to the file. */ -void verbose_stop() { +void verbose_stop(void) { if (verbose_fd != NULL) { fclose(verbose_fd); verbose_fd = NULL; @@ -2685,7 +2613,7 @@ void verbose_stop() { * Open the file 'verbosefile'. * Return FAIL or OK. */ -int verbose_open() { +int verbose_open(void) { if (verbose_fd == NULL && !verbose_did_open) { /* Only give the error message once. */ verbose_did_open = TRUE; @@ -2703,9 +2631,7 @@ int verbose_open() { * Give a warning message (for searching). * Use 'w' highlighting and may repeat the message after redrawing */ -void give_warning(message, hl) -char_u *message; -int hl; +void give_warning(char_u *message, int hl) { /* Don't do this for ":silent". */ if (msg_silent != 0) @@ -2733,8 +2659,7 @@ int hl; /* * Advance msg cursor to column "col". */ -void msg_advance(col) -int col; +void msg_advance(int col) { if (msg_silent != 0) { /* nothing to advance to */ msg_col = col; /* for redirection, may fill it up later */ @@ -2768,16 +2693,18 @@ int col; * A '&' in a button name becomes a shortcut, so each '&' should be before a * different letter. */ -int do_dialog(type, title, message, buttons, dfltbutton, textfield, ex_cmd) -int type UNUSED; -char_u *title UNUSED; -char_u *message; -char_u *buttons; -int dfltbutton; -char_u *textfield UNUSED; /* IObuff for inputdialog(), NULL +int +do_dialog ( + int type, + char_u *title, + char_u *message, + char_u *buttons, + int dfltbutton, + char_u *textfield, /* IObuff for inputdialog(), NULL otherwise */ -int ex_cmd; /* when TRUE pressing : accepts default and starts + int ex_cmd /* when TRUE pressing : accepts default and starts Ex command */ +) { int oldState; int retval = 0; @@ -2862,10 +2789,12 @@ static int copy_char __ARGS((char_u *from, char_u *to, int lowercase)); * Copy one character from "*from" to "*to", taking care of multi-byte * characters. Return the length of the character in bytes. */ -static int copy_char(from, to, lowercase) -char_u *from; -char_u *to; -int lowercase; /* make character lower case */ +static int +copy_char ( + char_u *from, + char_u *to, + int lowercase /* make character lower case */ +) { int len; int c; @@ -2897,10 +2826,7 @@ int lowercase; /* make character lower case */ * * Returns an allocated string with hotkeys, or NULL for error. */ -static char_u * msg_show_console_dialog(message, buttons, dfltbutton) -char_u *message; -char_u *buttons; -int dfltbutton; +static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton) { int len = 0; # define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1) @@ -3032,7 +2958,7 @@ int dfltbutton; /* * Display the ":confirm" message. Also called when screen resized. */ -void display_confirm_msg() { +void display_confirm_msg(void) { /* avoid that 'q' at the more prompt truncates the message here */ ++confirm_msg_used; if (confirm_msg != NULL) @@ -3040,11 +2966,7 @@ void display_confirm_msg() { --confirm_msg_used; } -int vim_dialog_yesno(type, title, message, dflt) -int type; -char_u *title; -char_u *message; -int dflt; +int vim_dialog_yesno(int type, char_u *title, char_u *message, int dflt) { if (do_dialog(type, title == NULL ? (char_u *)_("Question") : title, @@ -3054,11 +2976,7 @@ int dflt; return VIM_NO; } -int vim_dialog_yesnocancel(type, title, message, dflt) -int type; -char_u *title; -char_u *message; -int dflt; +int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt) { switch (do_dialog(type, title == NULL ? (char_u *)_("Question") : title, @@ -3070,11 +2988,7 @@ int dflt; return VIM_CANCEL; } -int vim_dialog_yesnoallcancel(type, title, message, dflt) -int type; -char_u *title; -char_u *message; -int dflt; +int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message, int dflt) { switch (do_dialog(type, title == NULL ? (char_u *)"Question" : title, @@ -3101,9 +3015,7 @@ static double tv_float __ARGS((typval_T *tvs, int *idxp)); /* * Get number argument from "idxp" entry in "tvs". First entry is 1. */ -static long tv_nr(tvs, idxp) -typval_T *tvs; -int *idxp; +static long tv_nr(typval_T *tvs, int *idxp) { int idx = *idxp - 1; long n = 0; @@ -3124,9 +3036,7 @@ int *idxp; * Get string argument from "idxp" entry in "tvs". First entry is 1. * Returns NULL for an error. */ -static char * tv_str(tvs, idxp) -typval_T *tvs; -int *idxp; +static char *tv_str(typval_T *tvs, int *idxp) { int idx = *idxp - 1; char *s = NULL; @@ -3143,9 +3053,7 @@ int *idxp; /* * Get float argument from "idxp" entry in "tvs". First entry is 1. */ -static double tv_float(tvs, idxp) -typval_T *tvs; -int *idxp; +static double tv_float(typval_T *tvs, int *idxp) { int idx = *idxp - 1; double f = 0; @@ -3230,11 +3138,7 @@ int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...) { # else /* Like vim_vsnprintf() but append to the string. */ -int vim_snprintf_add(str, str_m, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) -char *str; -size_t str_m; -char *fmt; -long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; +int vim_snprintf_add(char *str, size_t str_m, char *fmt, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) { size_t len = STRLEN(str); size_t space; diff --git a/src/misc1.c b/src/misc1.c index 92fc47189b..3f1e32bc69 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -25,15 +25,14 @@ static garray_T ga_users; /* * Count the size (in window cells) of the indent in the current line. */ -int get_indent() { +int get_indent(void) { return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts); } /* * Count the size (in window cells) of the indent in line "lnum". */ -int get_indent_lnum(lnum) -linenr_T lnum; +int get_indent_lnum(linenr_T lnum) { return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts); } @@ -42,9 +41,7 @@ linenr_T lnum; * Count the size (in window cells) of the indent in line "lnum" of buffer * "buf". */ -int get_indent_buf(buf, lnum) -buf_T *buf; -linenr_T lnum; +int get_indent_buf(buf_T *buf, linenr_T lnum) { return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts); } @@ -53,9 +50,7 @@ linenr_T lnum; * count the size (in window cells) of the indent in line "ptr", with * 'tabstop' at "ts" */ -int get_indent_str(ptr, ts) -char_u *ptr; -int ts; +int get_indent_str(char_u *ptr, int ts) { int count = 0; @@ -80,9 +75,11 @@ int ts; * SIN_UNDO: save line for undo before changing it. * Returns TRUE if the line was changed. */ -int set_indent(size, flags) -int size; /* measured in spaces */ -int flags; +int +set_indent ( + int size, /* measured in spaces */ + int flags +) { char_u *p; char_u *newline; @@ -291,9 +288,7 @@ int flags; * Leaves the cursor on the first non-blank in the line. * Returns TRUE if the line was changed. */ -static int copy_indent(size, src) -int size; -char_u *src; +static int copy_indent(int size, char_u *src) { char_u *p = NULL; char_u *line = NULL; @@ -385,8 +380,7 @@ char_u *src; * number was found. Used for 'n' in 'formatoptions': numbered list. * Since a pattern is used it can actually handle more than numbers. */ -int get_number_indent(lnum) -linenr_T lnum; +int get_number_indent(linenr_T lnum) { colnr_T col; pos_T pos; @@ -427,8 +421,7 @@ static int cin_is_cinword __ARGS((char_u *line)); /* * Return TRUE if the string "line" starts with a word from 'cinwords'. */ -static int cin_is_cinword(line) -char_u *line; +static int cin_is_cinword(char_u *line) { char_u *cinw; char_u *cinw_buf; @@ -473,10 +466,12 @@ char_u *line; * * Return TRUE for success, FALSE for failure */ -int open_line(dir, flags, second_line_indent) -int dir; /* FORWARD or BACKWARD */ -int flags; -int second_line_indent; +int +open_line ( + int dir, /* FORWARD or BACKWARD */ + int flags, + int second_line_indent +) { char_u *saved_line; /* copy of the original line */ char_u *next_line = NULL; /* copy of the next line */ @@ -1348,11 +1343,7 @@ theend: * If "include_space" is set, include trailing whitespace while calculating the * length. */ -int get_leader_len(line, flags, backward, include_space) -char_u *line; -char_u **flags; -int backward; -int include_space; +int get_leader_len(char_u *line, char_u **flags, int backward, int include_space) { int i, j; int result; @@ -1486,9 +1477,7 @@ int include_space; * When "flags" is not null, it is set to point to the flags describing the * recognized comment leader. */ -int get_last_leader_offset(line, flags) -char_u *line; -char_u **flags; +int get_last_leader_offset(char_u *line, char_u **flags) { int result = -1; int i, j; @@ -1618,32 +1607,34 @@ char_u **flags; /* * Return the number of window lines occupied by buffer line "lnum". */ -int plines(lnum) -linenr_T lnum; +int plines(linenr_T lnum) { return plines_win(curwin, lnum, TRUE); } -int plines_win(wp, lnum, winheight) -win_T *wp; -linenr_T lnum; -int winheight; /* when TRUE limit to window height */ +int +plines_win ( + win_T *wp, + linenr_T lnum, + int winheight /* when TRUE limit to window height */ +) { /* Check for filler lines above this buffer line. When folded the result * is one line anyway. */ return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum); } -int plines_nofill(lnum) -linenr_T lnum; +int plines_nofill(linenr_T lnum) { return plines_win_nofill(curwin, lnum, TRUE); } -int plines_win_nofill(wp, lnum, winheight) -win_T *wp; -linenr_T lnum; -int winheight; /* when TRUE limit to window height */ +int +plines_win_nofill ( + win_T *wp, + linenr_T lnum, + int winheight /* when TRUE limit to window height */ +) { int lines; @@ -1668,9 +1659,7 @@ int winheight; /* when TRUE limit to window height */ * Return number of window lines physical line "lnum" will occupy in window * "wp". Does not care about folding, 'wrap' or 'diff'. */ -int plines_win_nofold(wp, lnum) -win_T *wp; -linenr_T lnum; +int plines_win_nofold(win_T *wp, linenr_T lnum) { char_u *s; long col; @@ -1705,10 +1694,7 @@ linenr_T lnum; * Like plines_win(), but only reports the number of physical screen lines * used from the start of the line to the given column number. */ -int plines_win_col(wp, lnum, column) -win_T *wp; -linenr_T lnum; -long column; +int plines_win_col(win_T *wp, linenr_T lnum, long column) { long col; char_u *s; @@ -1756,9 +1742,7 @@ long column; return lines; } -int plines_m_win(wp, first, last) -win_T *wp; -linenr_T first, last; +int plines_m_win(win_T *wp, linenr_T first, linenr_T last) { int count = 0; @@ -1786,8 +1770,7 @@ linenr_T first, last; * Insert string "p" at the cursor position. Stops at a NUL byte. * Handles Replace mode and multi-byte characters. */ -void ins_bytes(p) -char_u *p; +void ins_bytes(char_u *p) { ins_bytes_len(p, (int)STRLEN(p)); } @@ -1798,9 +1781,7 @@ char_u *p; * Insert string "p" with length "len" at the cursor position. * Handles Replace mode and multi-byte characters. */ -void ins_bytes_len(p, len) -char_u *p; -int len; +void ins_bytes_len(char_u *p, int len) { int i; int n; @@ -1827,8 +1808,7 @@ int len; * For multi-byte characters we get the whole character, the caller must * convert bytes to a character. */ -void ins_char(c) -int c; +void ins_char(int c) { char_u buf[MB_MAXBYTES + 1]; int n; @@ -1843,9 +1823,7 @@ int c; ins_char_bytes(buf, n); } -void ins_char_bytes(buf, charlen) -char_u *buf; -int charlen; +void ins_char_bytes(char_u *buf, int charlen) { int c = buf[0]; int newlen; /* nr of bytes inserted */ @@ -1979,8 +1957,7 @@ int charlen; * Note: Does NOT handle Replace mode. * Caller must have prepared for undo. */ -void ins_str(s) -char_u *s; +void ins_str(char_u *s) { char_u *oldp, *newp; int newlen = (int)STRLEN(s); @@ -2014,8 +1991,7 @@ char_u *s; * * return FAIL for failure, OK otherwise */ -int del_char(fixpos) -int fixpos; +int del_char(int fixpos) { if (has_mbyte) { /* Make sure the cursor is at the start of a character. */ @@ -2030,9 +2006,7 @@ int fixpos; /* * Like del_bytes(), but delete characters instead of bytes. */ -int del_chars(count, fixpos) -long count; -int fixpos; +int del_chars(long count, int fixpos) { long bytes = 0; long i; @@ -2055,10 +2029,12 @@ int fixpos; * * return FAIL for failure, OK otherwise */ -int del_bytes(count, fixpos_arg, use_delcombine) -long count; -int fixpos_arg; -int use_delcombine UNUSED; /* 'delcombine' option applies */ +int +del_bytes ( + long count, + int fixpos_arg, + int use_delcombine /* 'delcombine' option applies */ +) { char_u *oldp, *newp; colnr_T oldlen; @@ -2152,8 +2128,10 @@ int use_delcombine UNUSED; /* 'delcombine' option applies */ * * return FAIL for failure, OK otherwise */ -int truncate_line(fixpos) -int fixpos; /* if TRUE fix the cursor position when done */ +int +truncate_line ( + int fixpos /* if TRUE fix the cursor position when done */ +) { char_u *newp; linenr_T lnum = curwin->w_cursor.lnum; @@ -2185,9 +2163,11 @@ int fixpos; /* if TRUE fix the cursor position when done */ * Delete "nlines" lines at the cursor. * Saves the lines for undo first if "undo" is TRUE. */ -void del_lines(nlines, undo) -long nlines; /* number of lines to delete */ -int undo; /* if TRUE, prepare for undo */ +void +del_lines ( + long nlines, /* number of lines to delete */ + int undo /* if TRUE, prepare for undo */ +) { long n; linenr_T first = curwin->w_cursor.lnum; @@ -2220,8 +2200,7 @@ int undo; /* if TRUE, prepare for undo */ deleted_lines_mark(first, n); } -int gchar_pos(pos) -pos_T *pos; +int gchar_pos(pos_T *pos) { char_u *ptr = ml_get_pos(pos); @@ -2230,7 +2209,7 @@ pos_T *pos; return (int)*ptr; } -int gchar_cursor() { +int gchar_cursor(void) { if (has_mbyte) return (*mb_ptr2char)(ml_get_cursor()); return (int)*ml_get_cursor(); @@ -2240,8 +2219,7 @@ int gchar_cursor() { * Write a character at the current cursor position. * It is directly written into the block. */ -void pchar_cursor(c) -int c; +void pchar_cursor(int c) { *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) + curwin->w_cursor.col) = c; @@ -2253,8 +2231,7 @@ int c; * When extra == 1: Return TRUE if the cursor is before the first non-blank in * the line. */ -int inindent(extra) -int extra; +int inindent(int extra) { char_u *ptr; colnr_T col; @@ -2270,8 +2247,7 @@ int extra; /* * Skip to next part of an option argument: Skip space and comma. */ -char_u * skip_to_option_part(p) -char_u *p; +char_u *skip_to_option_part(char_u *p) { if (*p == ',') ++p; @@ -2288,7 +2264,7 @@ char_u *p; * * Careful: may trigger autocommands that reload the buffer. */ -void changed() { +void changed(void) { if (!curbuf->b_changed) { int save_msg_scroll = msg_scroll; @@ -2323,7 +2299,7 @@ void changed() { /* * Internal part of changed(), no user interaction. */ -void changed_int() { +void changed_int(void) { curbuf->b_changed = TRUE; ml_setflags(curbuf); check_status(curbuf); @@ -2344,9 +2320,7 @@ static void changed_common __ARGS((linenr_T lnum, colnr_T col, linenr_T lnume, * - invalidates cached values * Careful: may trigger autocommands that reload the buffer. */ -void changed_bytes(lnum, col) -linenr_T lnum; -colnr_T col; +void changed_bytes(linenr_T lnum, colnr_T col) { changedOneline(curbuf, lnum); changed_common(lnum, col, lnum + 1, 0L); @@ -2366,9 +2340,7 @@ colnr_T col; } } -static void changedOneline(buf, lnum) -buf_T *buf; -linenr_T lnum; +static void changedOneline(buf_T *buf, linenr_T lnum) { if (buf->b_mod_set) { /* find the maximum area that must be redisplayed */ @@ -2390,9 +2362,7 @@ linenr_T lnum; * Must be called AFTER the change and after mark_adjust(). * Takes care of marking the buffer to be redrawn and sets the changed flag. */ -void appended_lines(lnum, count) -linenr_T lnum; -long count; +void appended_lines(linenr_T lnum, long count) { changed_lines(lnum + 1, 0, lnum + 1, count); } @@ -2400,9 +2370,7 @@ long count; /* * Like appended_lines(), but adjust marks first. */ -void appended_lines_mark(lnum, count) -linenr_T lnum; -long count; +void appended_lines_mark(linenr_T lnum, long count) { mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L); changed_lines(lnum + 1, 0, lnum + 1, count); @@ -2413,9 +2381,7 @@ long count; * Must be called AFTER the change and after mark_adjust(). * Takes care of marking the buffer to be redrawn and sets the changed flag. */ -void deleted_lines(lnum, count) -linenr_T lnum; -long count; +void deleted_lines(linenr_T lnum, long count) { changed_lines(lnum, 0, lnum + count, -count); } @@ -2425,9 +2391,7 @@ long count; * Make sure the cursor is on a valid line before calling, a GUI callback may * be triggered to display the cursor. */ -void deleted_lines_mark(lnum, count) -linenr_T lnum; -long count; +void deleted_lines_mark(linenr_T lnum, long count) { mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count); changed_lines(lnum, 0, lnum + count, -count); @@ -2445,11 +2409,13 @@ long count; * Takes care of calling changed() and updating b_mod_*. * Careful: may trigger autocommands that reload the buffer. */ -void changed_lines(lnum, col, lnume, xtra) -linenr_T lnum; /* first line with change */ -colnr_T col; /* column in first line with change */ -linenr_T lnume; /* line below last changed line */ -long xtra; /* number of extra lines (negative when deleting) */ +void +changed_lines ( + linenr_T lnum, /* first line with change */ + colnr_T col, /* column in first line with change */ + linenr_T lnume, /* line below last changed line */ + long xtra /* number of extra lines (negative when deleting) */ +) { changed_lines_buf(curbuf, lnum, lnume, xtra); @@ -2473,11 +2439,13 @@ long xtra; /* number of extra lines (negative when deleting) */ changed_common(lnum, col, lnume, xtra); } -static void changed_lines_buf(buf, lnum, lnume, xtra) -buf_T *buf; -linenr_T lnum; /* first line with change */ -linenr_T lnume; /* line below last changed line */ -long xtra; /* number of extra lines (negative when deleting) */ +static void +changed_lines_buf ( + buf_T *buf, + linenr_T lnum, /* first line with change */ + linenr_T lnume, /* line below last changed line */ + long xtra /* number of extra lines (negative when deleting) */ +) { if (buf->b_mod_set) { /* find the maximum area that must be redisplayed */ @@ -2506,11 +2474,7 @@ long xtra; /* number of extra lines (negative when deleting) */ * See changed_lines() for the arguments. * Careful: may trigger autocommands that reload the buffer. */ -static void changed_common(lnum, col, lnume, xtra) -linenr_T lnum; -colnr_T col; -linenr_T lnume; -long xtra; +static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra) { win_T *wp; tabpage_T *tp; @@ -2671,9 +2635,11 @@ long xtra; /* * unchanged() is called when the changed flag must be reset for buffer 'buf' */ -void unchanged(buf, ff) -buf_T *buf; -int ff; /* also reset 'fileformat' */ +void +unchanged ( + buf_T *buf, + int ff /* also reset 'fileformat' */ +) { if (buf->b_changed || (ff && file_ff_differs(buf, FALSE))) { buf->b_changed = 0; @@ -2691,8 +2657,7 @@ int ff; /* also reset 'fileformat' */ * check_status: called when the status bars for the buffer 'buf' * need to be updated */ -void check_status(buf) -buf_T *buf; +void check_status(buf_T *buf) { win_T *wp; @@ -2712,9 +2677,11 @@ buf_T *buf; * will be TRUE. * Careful: may trigger autocommands that reload the buffer. */ -void change_warning(col) -int col; /* column for message; non-zero when in insert +void +change_warning ( + int col /* column for message; non-zero when in insert mode and 'showmode' is on */ +) { static char *w_readonly = N_("W10: Warning: Changing a readonly file"); @@ -2759,9 +2726,7 @@ int col; /* column for message; non-zero when in insert * * return the 'y' or 'n' */ -int ask_yesno(str, direct) -char_u *str; -int direct; +int ask_yesno(char_u *str, int direct) { int r = ' '; int save_State = State; @@ -2801,8 +2766,7 @@ int direct; /* * Return TRUE if "c" is a mouse key. */ -int is_mouse_key(c) -int c; +int is_mouse_key(int c) { return c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM @@ -2835,7 +2799,7 @@ int c; * Disadvantage: typeahead is ignored. * Translates the interrupt character for unix to ESC. */ -int get_keystroke() { +int get_keystroke(void) { char_u *buf = NULL; int buflen = 150; int maxlen; @@ -2935,9 +2899,11 @@ int get_keystroke() { * Get a number from the user. * When "mouse_used" is not NULL allow using the mouse. */ -int get_number(colon, mouse_used) -int colon; /* allow colon to abort */ -int *mouse_used; +int +get_number ( + int colon, /* allow colon to abort */ + int *mouse_used +) { int n = 0; int c; @@ -2993,8 +2959,7 @@ int *mouse_used; * When "mouse_used" is not NULL allow using the mouse and in that case return * the line number. */ -int prompt_for_number(mouse_used) -int *mouse_used; +int prompt_for_number(int *mouse_used) { int i; int save_cmdline_row; @@ -3028,8 +2993,7 @@ int *mouse_used; return i; } -void msgmore(n) -long n; +void msgmore(long n) { long pn; @@ -3076,7 +3040,7 @@ long n; /* * flush map and typeahead buffers and give a warning for an error */ -void beep_flush() { +void beep_flush(void) { if (emsg_silent == 0) { flush_buffers(FALSE); vim_beep(); @@ -3086,7 +3050,7 @@ void beep_flush() { /* * give a warning for an error */ -void vim_beep() { +void vim_beep(void) { if (emsg_silent == 0) { if (p_vb ) { @@ -3115,7 +3079,7 @@ void vim_beep() { */ static char_u *homedir = NULL; -void init_homedir() { +void init_homedir(void) { char_u *var; /* In case we are called a second time (when 'encoding' changes). */ @@ -3147,11 +3111,11 @@ void init_homedir() { } #if defined(EXITFREE) || defined(PROTO) -void free_homedir() { +void free_homedir(void) { vim_free(homedir); } -void free_users() { +void free_users(void) { ga_clear_strings(&ga_users); } @@ -3162,8 +3126,7 @@ void free_users() { * This is not very memory efficient, this expects the result to be freed * again soon. */ -char_u * expand_env_save(src) -char_u *src; +char_u *expand_env_save(char_u *src) { return expand_env_save_opt(src, FALSE); } @@ -3172,9 +3135,7 @@ char_u *src; * Idem, but when "one" is TRUE handle the string as one file name, only * expand "~" at the start. */ -char_u * expand_env_save_opt(src, one) -char_u *src; -int one; +char_u *expand_env_save_opt(char_u *src, int one) { char_u *p; @@ -3190,21 +3151,25 @@ int one; * Skips over "\ ", "\~" and "\$" (not for Win32 though). * If anything fails no expansion is done and dst equals src. */ -void expand_env(src, dst, dstlen) -char_u *src; /* input string e.g. "$HOME/vim.hlp" */ -char_u *dst; /* where to put the result */ -int dstlen; /* maximum length of the result */ +void +expand_env ( + char_u *src, /* input string e.g. "$HOME/vim.hlp" */ + char_u *dst, /* where to put the result */ + int dstlen /* maximum length of the result */ +) { expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL); } -void expand_env_esc(srcp, dst, dstlen, esc, one, startstr) -char_u *srcp; /* input string e.g. "$HOME/vim.hlp" */ -char_u *dst; /* where to put the result */ -int dstlen; /* maximum length of the result */ -int esc; /* escape spaces in expanded variables */ -int one; /* "srcp" is one file name */ -char_u *startstr; /* start again after this (can be NULL) */ +void +expand_env_esc ( + char_u *srcp, /* input string e.g. "$HOME/vim.hlp" */ + char_u *dst, /* where to put the result */ + int dstlen, /* maximum length of the result */ + int esc, /* escape spaces in expanded variables */ + int one, /* "srcp" is one file name */ + char_u *startstr /* start again after this (can be NULL) */ +) { char_u *src; char_u *tail; @@ -3439,9 +3404,7 @@ char_u *startstr; /* start again after this (can be NULL) */ * "mustfree" is set to TRUE when returned is allocated, it must be * initialized to FALSE by the caller. */ -char_u * vim_getenv(name, mustfree) -char_u *name; -int *mustfree; +char_u *vim_getenv(char_u *name, int *mustfree) { char_u *p; char_u *pend; @@ -3581,8 +3544,7 @@ int *mustfree; * Check if the directory "vimdir/" or "vimdir/runtime" exists. * Return NULL if not, return its name in allocated memory otherwise. */ -static char_u * vim_version_dir(vimdir) -char_u *vimdir; +static char_u *vim_version_dir(char_u *vimdir) { char_u *p; @@ -3603,10 +3565,7 @@ char_u *vimdir; * If the string between "p" and "pend" ends in "name/", return "pend" minus * the length of "name/". Otherwise return "pend". */ -static char_u * remove_tail(p, pend, name) -char_u *p; -char_u *pend; -char_u *name; +static char_u *remove_tail(char_u *p, char_u *pend, char_u *name) { int len = (int)STRLEN(name) + 1; char_u *newend = pend - len; @@ -3621,9 +3580,7 @@ char_u *name; /* * Our portable version of setenv. */ -void vim_setenv(name, val) -char_u *name; -char_u *val; +void vim_setenv(char_u *name, char_u *val) { #ifdef HAVE_SETENV mch_setenv((char *)name, (char *)val, 1); @@ -3657,9 +3614,7 @@ char_u *val; /* * Function given to ExpandGeneric() to obtain an environment variable name. */ -char_u * get_env_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_env_name(expand_T *xp, int idx) { # if defined(AMIGA) || defined(__MRC__) || defined(__SC__) /* @@ -3694,7 +3649,7 @@ int idx; * Find all user names for user completion. * Done only once and then cached. */ -static void init_users() { +static void init_users(void) { static int lazy_init_done = FALSE; if (lazy_init_done) @@ -3727,9 +3682,7 @@ static void init_users() { /* * Function given to ExpandGeneric() to obtain an user names. */ -char_u* get_users(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_users(expand_T *xp, int idx) { init_users(); if (idx < ga_users.ga_len) @@ -3743,8 +3696,7 @@ int idx; * 1 if name partially matches the beginning of a user name. * 2 is name fully matches a user name. */ -int match_user(name) -char_u* name; +int match_user(char_u *name) { int i; int n = (int)STRLEN(name); @@ -3765,13 +3717,15 @@ char_u* name; * 'src'. * If anything fails (except when out of space) dst equals src. */ -void home_replace(buf, src, dst, dstlen, one) -buf_T *buf; /* when not NULL, check for help files */ -char_u *src; /* input file name */ -char_u *dst; /* where to put the result */ -int dstlen; /* maximum length of the result */ -int one; /* if TRUE, only replace one file name, include +void +home_replace ( + buf_T *buf, /* when not NULL, check for help files */ + char_u *src, /* input file name */ + char_u *dst, /* where to put the result */ + int dstlen, /* maximum length of the result */ + int one /* if TRUE, only replace one file name, include spaces and commas in the file name. */ +) { size_t dirlen = 0, envlen = 0; size_t len; @@ -3876,9 +3830,11 @@ int one; /* if TRUE, only replace one file name, include * Like home_replace, store the replaced string in allocated memory. * When something fails, NULL is returned. */ -char_u * home_replace_save(buf, src) -buf_T *buf; /* when not NULL, check for help files */ -char_u *src; /* input file name */ +char_u * +home_replace_save ( + buf_T *buf, /* when not NULL, check for help files */ + char_u *src /* input file name */ +) { char_u *dst; unsigned len; @@ -3901,9 +3857,12 @@ char_u *src; /* input file name */ * FPC_DIFFX if one of them doesn't exist. * For the first name environment variables are expanded */ -int fullpathcmp(s1, s2, checkname) -char_u *s1, *s2; -int checkname; /* when both don't exist, check file names */ +int +fullpathcmp ( + char_u *s1, + char_u *s2, + int checkname /* when both don't exist, check file names */ +) { #ifdef UNIX char_u exp1[MAXPATHL]; @@ -3971,8 +3930,7 @@ int checkname; /* when both don't exist, check file names */ * When the path ends in a path separator the tail is the NUL after it. * Fail safe: never returns NULL. */ -char_u * gettail(fname) -char_u *fname; +char_u *gettail(char_u *fname) { char_u *p1, *p2; @@ -3994,8 +3952,7 @@ static char_u *gettail_dir __ARGS((char_u *fname)); * "/path/file", "/path/dir/", "/path//dir", "/file" * ^ ^ ^ ^ */ -static char_u * gettail_dir(fname) -char_u *fname; +static char_u *gettail_dir(char_u *fname) { char_u *dir_end = fname; char_u *next_dir_end = fname; @@ -4023,8 +3980,7 @@ char_u *fname; * here leaves the directory name. Takes care of "c:/" and "//". * Always returns a valid pointer. */ -char_u * gettail_sep(fname) -char_u *fname; +char_u *gettail_sep(char_u *fname) { char_u *p; char_u *t; @@ -4039,8 +3995,7 @@ char_u *fname; /* * get the next path component (just after the next path separator). */ -char_u * getnextcomp(fname) -char_u *fname; +char_u *getnextcomp(char_u *fname) { while (*fname && !vim_ispathsep(*fname)) mb_ptr_adv(fname); @@ -4054,8 +4009,7 @@ char_u *fname; * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head. * If there is no head, path is returned. */ -char_u * get_past_head(path) -char_u *path; +char_u *get_past_head(char_u *path) { char_u *retval; @@ -4071,8 +4025,7 @@ char_u *path; * Return TRUE if 'c' is a path separator. * Note that for MS-Windows this includes the colon. */ -int vim_ispathsep(c) -int c; +int vim_ispathsep(int c) { #ifdef UNIX return c == '/'; /* UNIX has ':' inside file names */ @@ -4088,8 +4041,7 @@ int c; /* * Like vim_ispathsep(c), but exclude the colon for MS-Windows. */ -int vim_ispathsep_nocolon(c) -int c; +int vim_ispathsep_nocolon(int c) { return vim_ispathsep(c) #ifdef BACKSLASH_IN_FILENAME @@ -4101,8 +4053,7 @@ int c; /* * return TRUE if 'c' is a path list separator. */ -int vim_ispathlistsep(c) -int c; +int vim_ispathlistsep(int c) { #ifdef UNIX return c == ':'; @@ -4117,8 +4068,7 @@ int c; * Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" * It's done in-place. */ -void shorten_dir(str) -char_u *str; +void shorten_dir(char_u *str) { char_u *tail, *s, *d; int skip = FALSE; @@ -4153,8 +4103,7 @@ char_u *str; * Also returns TRUE if there is no directory name. * "fname" must be writable!. */ -int dir_of_file_exists(fname) -char_u *fname; +int dir_of_file_exists(char_u *fname) { char_u *p; int c; @@ -4174,8 +4123,7 @@ char_u *fname; * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally * and deal with 'fileignorecase'. */ -int vim_fnamecmp(x, y) -char_u *x, *y; +int vim_fnamecmp(char_u *x, char_u *y) { #ifdef BACKSLASH_IN_FILENAME return vim_fnamencmp(x, y, MAXPATHL); @@ -4186,9 +4134,7 @@ char_u *x, *y; #endif } -int vim_fnamencmp(x, y, len) -char_u *x, *y; -size_t len; +int vim_fnamencmp(char_u *x, char_u *y, size_t len) { #ifdef BACKSLASH_IN_FILENAME char_u *px = x; @@ -4222,10 +4168,7 @@ size_t len; * Concatenate file names fname1 and fname2 into allocated memory. * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary. */ -char_u * concat_fnames(fname1, fname2, sep) -char_u *fname1; -char_u *fname2; -int sep; +char_u *concat_fnames(char_u *fname1, char_u *fname2, int sep) { char_u *dest; @@ -4243,9 +4186,7 @@ int sep; * Concatenate two strings and return the result in allocated memory. * Returns NULL when out of memory. */ -char_u * concat_str(str1, str2) -char_u *str1; -char_u *str2; +char_u *concat_str(char_u *str1, char_u *str2) { char_u *dest; size_t l = STRLEN(str1); @@ -4262,8 +4203,7 @@ char_u *str2; * Add a path separator to a file name, unless it already ends in a path * separator. */ -void add_pathsep(p) -char_u *p; +void add_pathsep(char_u *p) { if (*p != NUL && !after_pathsep(p, p + STRLEN(p))) STRCAT(p, PATHSEPSTR); @@ -4273,10 +4213,12 @@ char_u *p; * FullName_save - Make an allocated copy of a full file name. * Returns NULL when out of memory. */ -char_u * FullName_save(fname, force) -char_u *fname; -int force; /* force expansion, even when it already looks +char_u * +FullName_save ( + char_u *fname, + int force /* force expansion, even when it already looks * like a full path name */ +) { char_u *buf; char_u *new_fname = NULL; @@ -4303,12 +4245,14 @@ static pos_T *ind_find_start_comment __ARGS((void)); * Find the start of a comment, not knowing if we are in a comment right now. * Search starts at w_cursor.lnum and goes backwards. */ -static pos_T * ind_find_start_comment() { /* XXX */ +static pos_T *ind_find_start_comment(void) { /* XXX */ return find_start_comment(curbuf->b_ind_maxcomment); } -pos_T * find_start_comment(ind_maxcomment) /* XXX */ -int ind_maxcomment; +pos_T * +find_start_comment ( /* XXX */ + int ind_maxcomment +) { pos_T *pos; char_u *line; @@ -4342,8 +4286,7 @@ int ind_maxcomment; * Skip to the end of a "string" and a 'c' character. * If there is no string or character, return argument unmodified. */ -static char_u * skip_string(p) -char_u *p; +static char_u *skip_string(char_u *p) { int i; @@ -4385,7 +4328,7 @@ char_u *p; /* * Do C or expression indenting on the current line. */ -void do_c_expr_indent() { +void do_c_expr_indent(void) { if (*curbuf->b_p_inde != NUL) fixthisline(get_expr_indent); else @@ -4440,8 +4383,7 @@ static int cin_is_cpp_namespace __ARGS((char_u *)); * Skip over white space and C comments within the line. * Also skip over Perl/shell comments if desired. */ -static char_u * cin_skipcomment(s) -char_u *s; +static char_u *cin_skipcomment(char_u *s) { while (*s) { char_u *prev_s = s; @@ -4476,8 +4418,7 @@ char_u *s; * Return TRUE if there is no code at *s. White space and comments are * not considered code. */ -static int cin_nocode(s) -char_u *s; +static int cin_nocode(char_u *s) { return *cin_skipcomment(s) == NUL; } @@ -4485,7 +4426,7 @@ char_u *s; /* * Check previous lines for a "//" line comment, skipping over blank lines. */ -static pos_T * find_line_comment() { /* XXX */ +static pos_T *find_line_comment(void) { /* XXX */ static pos_T pos; char_u *line; char_u *p; @@ -4507,8 +4448,7 @@ static pos_T * find_line_comment() { /* XXX */ /* * Check if string matches "label:"; move to character after ':' if true. */ -static int cin_islabel_skip(s) -char_u **s; +static int cin_islabel_skip(char_u **s) { if (!vim_isIDc(**s)) /* need at least one ID character */ return FALSE; @@ -4526,7 +4466,7 @@ char_u **s; * Recognize a label: "label:". * Note: curwin->w_cursor must be where we are looking for the label. */ -int cin_islabel() { /* XXX */ +int cin_islabel(void) { /* XXX */ char_u *s; s = cin_skipcomment(ml_get_curline()); @@ -4621,9 +4561,11 @@ static int cin_isinit(void) { /* * Recognize a switch label: "case .*:" or "default:". */ -int cin_iscase(s, strict) -char_u *s; -int strict; /* Allow relaxed check of case statement for JS */ +int +cin_iscase ( + char_u *s, + int strict /* Allow relaxed check of case statement for JS */ +) { s = cin_skipcomment(s); if (cin_starts_with(s, "case")) { @@ -4658,8 +4600,7 @@ int strict; /* Allow relaxed check of case statement for JS */ /* * Recognize a "default" switch label. */ -static int cin_isdefault(s) -char_u *s; +static int cin_isdefault(char_u *s) { return STRNCMP(s, "default", 7) == 0 && *(s = cin_skipcomment(s + 7)) == ':' @@ -4669,8 +4610,7 @@ char_u *s; /* * Recognize a "public/private/protected" scope declaration label. */ -int cin_isscopedecl(s) -char_u *s; +int cin_isscopedecl(char_u *s) { int i; @@ -4692,8 +4632,7 @@ char_u *s; /* * Recognize a "namespace" scope declaration. */ -static int cin_is_cpp_namespace(s) -char_u *s; +static int cin_is_cpp_namespace(char_u *s) { char_u *p; int has_name = FALSE; @@ -4726,8 +4665,7 @@ char_u *s; * case 234: a = b; * ^ */ -static char_u * after_label(l) -char_u *l; +static char_u *after_label(char_u *l) { for (; *l; ++l) { if (*l == ':') { @@ -4750,8 +4688,10 @@ char_u *l; * Get indent of line "lnum", skipping a label. * Return 0 if there is nothing after the label. */ -static int get_indent_nolabel(lnum) /* XXX */ -linenr_T lnum; +static int +get_indent_nolabel ( /* XXX */ + linenr_T lnum +) { char_u *l; pos_T fp; @@ -4775,9 +4715,7 @@ linenr_T lnum; * label: if (asdf && asdfasdf) * ^ */ -static int skip_label(lnum, pp) -linenr_T lnum; -char_u **pp; +static int skip_label(linenr_T lnum, char_u **pp) { char_u *l; int amount; @@ -4809,7 +4747,7 @@ char_u **pp; * enum bla c, indent of "c" * Returns zero when it doesn't look like a declaration. */ -static int cin_first_id_amount() { +static int cin_first_id_amount(void) { char_u *line, *p, *s; int len; pos_T fp; @@ -4856,8 +4794,7 @@ static int cin_first_id_amount() { * asdf\ * here"; */ -static int cin_get_equal_amount(lnum) -linenr_T lnum; +static int cin_get_equal_amount(linenr_T lnum) { char_u *line; char_u *s; @@ -4896,8 +4833,7 @@ linenr_T lnum; /* * Recognize a preprocessor statement: Any line that starts with '#'. */ -static int cin_ispreproc(s) -char_u *s; +static int cin_ispreproc(char_u *s) { if (*skipwhite(s) == '#') return TRUE; @@ -4909,9 +4845,7 @@ char_u *s; * continuation line of a preprocessor statement. Decrease "*lnump" to the * start and return the line in "*pp". */ -static int cin_ispreproc_cont(pp, lnump) -char_u **pp; -linenr_T *lnump; +static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump) { char_u *line = *pp; linenr_T lnum = *lnump; @@ -4938,8 +4872,7 @@ linenr_T *lnump; /* * Recognize the start of a C or C++ comment. */ -static int cin_iscomment(p) -char_u *p; +static int cin_iscomment(char_u *p) { return p[0] == '/' && (p[1] == '*' || p[1] == '/'); } @@ -4947,8 +4880,7 @@ char_u *p; /* * Recognize the start of a "//" comment. */ -static int cin_islinecomment(p) -char_u *p; +static int cin_islinecomment(char_u *p) { return p[0] == '/' && p[1] == '/'; } @@ -4962,10 +4894,12 @@ char_u *p; * Return the character terminating the line (ending char's have precedence if * both apply in order to determine initializations). */ -static int cin_isterminated(s, incl_open, incl_comma) -char_u *s; -int incl_open; /* include '{' at the end as terminator */ -int incl_comma; /* recognize a trailing comma */ +static int +cin_isterminated ( + char_u *s, + int incl_open, /* include '{' at the end as terminator */ + int incl_comma /* recognize a trailing comma */ +) { char_u found_start = 0; unsigned n_open = 0; @@ -5011,10 +4945,7 @@ int incl_comma; /* recognize a trailing comma */ * "lnum" is where we start looking. * "min_lnum" is the line before which we will not be looking. */ -static int cin_isfuncdecl(sp, first_lnum, min_lnum) -char_u **sp; -linenr_T first_lnum; -linenr_T min_lnum; +static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum) { char_u *s; linenr_T lnum = first_lnum; @@ -5099,22 +5030,19 @@ done: return retval; } -static int cin_isif(p) -char_u *p; +static int cin_isif(char_u *p) { return STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]); } -static int cin_iselse(p) -char_u *p; +static int cin_iselse(char_u *p) { if (*p == '}') /* accept "} else" */ p = cin_skipcomment(p + 1); return STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]); } -static int cin_isdo(p) -char_u *p; +static int cin_isdo(char_u *p) { return STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]); } @@ -5124,9 +5052,11 @@ char_u *p; * We only accept a "while (condition) ;", with only white space between the * ')' and ';'. The condition may be spread over several lines. */ -static int cin_iswhileofdo(p, lnum) /* XXX */ -char_u *p; -linenr_T lnum; +static int +cin_iswhileofdo ( /* XXX */ + char_u *p, + linenr_T lnum +) { pos_T cursor_save; pos_T *trypos; @@ -5159,9 +5089,7 @@ linenr_T lnum; * Otherwise return !0 and update "*poffset" to point to the place where the * string was found. */ -static int cin_is_if_for_while_before_offset(line, poffset) -char_u *line; -int *poffset; +static int cin_is_if_for_while_before_offset(char_u *line, int *poffset) { int offset = *poffset; @@ -5203,8 +5131,7 @@ probablyFound: * && bar); <-- here * Adjust the cursor to the line with "while". */ -static int cin_iswhileofdo_end(terminated) -int terminated; +static int cin_iswhileofdo_end(int terminated) { char_u *line; char_u *p; @@ -5247,8 +5174,7 @@ int terminated; return FALSE; } -static int cin_isbreak(p) -char_u *p; +static int cin_isbreak(char_u *p) { return STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]); } @@ -5266,8 +5192,10 @@ char_u *p; * * This is a lot of guessing. Watch out for "cond ? func() : foo". */ -static int cin_is_cpp_baseclass(col) -colnr_T *col; /* return: column to align with */ +static int +cin_is_cpp_baseclass ( + colnr_T *col /* return: column to align with */ +) { char_u *s; int class_or_struct, lookfor_ctor_init, cpp_base_class; @@ -5390,8 +5318,7 @@ colnr_T *col; /* return: column to align with */ return cpp_base_class; } -static int get_baseclass_amount(col) -int col; +static int get_baseclass_amount(int col) { int amount; colnr_T vcol; @@ -5419,10 +5346,7 @@ int col; * white space and comments. Skip strings and comments. * Ignore "ignore" after "find" if it's not NULL. */ -static int cin_ends_in(s, find, ignore) -char_u *s; -char_u *find; -char_u *ignore; +static int cin_ends_in(char_u *s, char_u *find, char_u *ignore) { char_u *p = s; char_u *r; @@ -5446,9 +5370,7 @@ char_u *ignore; /* * Return TRUE when "s" starts with "word" and then a non-ID character. */ -static int cin_starts_with(s, word) -char_u *s; -char *word; +static int cin_starts_with(char_u *s, char *word) { int l = (int)STRLEN(word); @@ -5459,8 +5381,7 @@ char *word; * Skip strings, chars and comments until at or past "trypos". * Return the column found. */ -static int cin_skip2pos(trypos) -pos_T *trypos; +static int cin_skip2pos(pos_T *trypos) { char_u *line; char_u *p; @@ -5486,7 +5407,7 @@ pos_T *trypos; /* { */ /* } */ -static pos_T * find_start_brace() { /* XXX */ +static pos_T *find_start_brace(void) { /* XXX */ pos_T cursor_save; pos_T *trypos; pos_T *pos; @@ -5513,8 +5434,10 @@ static pos_T * find_start_brace() { /* XXX */ * Find the matching '(', failing if it is in a comment. * Return NULL if no match found. */ -static pos_T * find_match_paren(ind_maxparen) /* XXX */ -int ind_maxparen; +static pos_T * +find_match_paren ( /* XXX */ + int ind_maxparen +) { pos_T cursor_save; pos_T *trypos; @@ -5543,8 +5466,7 @@ int ind_maxparen; * matching paren above the cursor line doesn't find a match because of * looking a few lines further. */ -static int corr_ind_maxparen(startpos) -pos_T *startpos; +static int corr_ind_maxparen(pos_T *startpos) { long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; @@ -5557,9 +5479,7 @@ pos_T *startpos; * Set w_cursor.col to the column number of the last unmatched ')' or '{' in * line "l". "l" must point to the start of the line. */ -static int find_last_paren(l, start, end) -char_u *l; -int start, end; +static int find_last_paren(char_u *l, int start, int end) { int i; int retval = FALSE; @@ -5588,8 +5508,7 @@ int start, end; * Parse 'cinoptions' and set the values in "curbuf". * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. */ -void parse_cino(buf) -buf_T *buf; +void parse_cino(buf_T *buf) { char_u *p; char_u *l; @@ -5797,7 +5716,7 @@ buf_T *buf; } } -int get_c_indent() { +int get_c_indent(void) { pos_T cur_curpos; int amount; int scope_amount; @@ -7483,9 +7402,7 @@ theend: return amount; } -static int find_match(lookfor, ourscope) -int lookfor; -linenr_T ourscope; +static int find_match(int lookfor, linenr_T ourscope) { char_u *look; pos_T *theirscope; @@ -7590,7 +7507,7 @@ linenr_T ourscope; /* * Get indent level from 'indentexpr'. */ -int get_expr_indent() { +int get_expr_indent(void) { int indent; pos_T save_pos; colnr_T save_curswant; @@ -7633,8 +7550,7 @@ int get_expr_indent() { static int lisp_match __ARGS((char_u *p)); -static int lisp_match(p) -char_u *p; +static int lisp_match(char_u *p) { char_u buf[LSIZE]; int len; @@ -7665,7 +7581,7 @@ char_u *p; * Update from Sergey Khorev: * I tried to fix the first two issues. */ -int get_lisp_indent() { +int get_lisp_indent(void) { pos_T *pos, realpos, paren; int amount; char_u *that; @@ -7824,7 +7740,7 @@ int get_lisp_indent() { return amount; } -void prepare_to_exit() { +void prepare_to_exit(void) { #if defined(SIGHUP) && defined(SIG_IGN) /* Ignore SIGHUP, because a dropped connection causes a read error, which * makes Vim exit and then handling SIGHUP causes various reentrance @@ -7851,7 +7767,7 @@ void prepare_to_exit() { * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe * functions, such as allocating memory. */ -void preserve_exit() { +void preserve_exit(void) { buf_T *buf; prepare_to_exit(); @@ -7886,8 +7802,7 @@ void preserve_exit() { /* * return TRUE if "fname" exists. */ -int vim_fexists(fname) -char_u *fname; +int vim_fexists(char_u *fname) { struct stat st; @@ -7909,7 +7824,7 @@ char_u *fname; static int breakcheck_count = 0; -void line_breakcheck() { +void line_breakcheck(void) { if (++breakcheck_count >= BREAKCHECK_SKIP) { breakcheck_count = 0; ui_breakcheck(); @@ -7919,7 +7834,7 @@ void line_breakcheck() { /* * Like line_breakcheck() but check 10 times less often. */ -void fast_breakcheck() { +void fast_breakcheck(void) { if (++breakcheck_count >= BREAKCHECK_SKIP * 10) { breakcheck_count = 0; ui_breakcheck(); @@ -7931,11 +7846,13 @@ void fast_breakcheck() { * Expand items like "%:h" before the expansion. * Returns OK or FAIL. */ -int expand_wildcards_eval(pat, num_file, file, flags) -char_u **pat; /* pointer to input pattern */ -int *num_file; /* resulting number of files */ -char_u ***file; /* array of resulting files */ -int flags; /* EW_DIR, etc. */ +int +expand_wildcards_eval ( + char_u **pat, /* pointer to input pattern */ + int *num_file, /* resulting number of files */ + char_u ***file, /* array of resulting files */ + int flags /* EW_DIR, etc. */ +) { int ret = FAIL; char_u *eval_pat = NULL; @@ -7968,12 +7885,14 @@ int flags; /* EW_DIR, etc. */ * 'wildignore'. * Returns OK or FAIL. When FAIL then "num_file" won't be set. */ -int expand_wildcards(num_pat, pat, num_file, file, flags) -int num_pat; /* number of input patterns */ -char_u **pat; /* array of input patterns */ -int *num_file; /* resulting number of files */ -char_u ***file; /* array of resulting files */ -int flags; /* EW_DIR, etc. */ +int +expand_wildcards ( + int num_pat, /* number of input patterns */ + char_u **pat, /* array of input patterns */ + int *num_file, /* resulting number of files */ + char_u ***file, /* array of resulting files */ + int flags /* EW_DIR, etc. */ +) { int retval; int i, j; @@ -8034,8 +7953,7 @@ int flags; /* EW_DIR, etc. */ /* * Return TRUE if "fname" matches with an entry in 'suffixes'. */ -int match_suffix(fname) -char_u *fname; +int match_suffix(char_u *fname) { int fnamelen, setsuflen; char_u *setsuf; @@ -8079,8 +7997,7 @@ static int expand_backtick __ARGS((garray_T *gap, char_u *pat, int flags)); */ static int pstrcmp __ARGS((const void *, const void *)); -static int pstrcmp(a, b) -const void *a, *b; +static int pstrcmp(const void *a, const void *b) { return pathcmp(*(char **)a, *(char **)b, -1); } @@ -8093,12 +8010,14 @@ const void *a, *b; * Return the number of matches found. * NOTE: much of this is identical to dos_expandpath(), keep in sync! */ -int unix_expandpath(gap, path, wildoff, flags, didstar) -garray_T *gap; -char_u *path; -int wildoff; -int flags; /* EW_* flags */ -int didstar; /* expanded "**" once already */ +int +unix_expandpath ( + garray_T *gap, + char_u *path, + int wildoff, + int flags, /* EW_* flags */ + int didstar /* expanded "**" once already */ +) { char_u *buf; char_u *path_end; @@ -8291,9 +8210,7 @@ static int expand_in_path __ARGS((garray_T *gap, char_u *pattern, int flags)); * Moves "*psep" back to the previous path separator in "path". * Returns FAIL is "*psep" ends up at the beginning of "path". */ -static int find_previous_pathsep(path, psep) -char_u *path; -char_u **psep; +static int find_previous_pathsep(char_u *path, char_u **psep) { /* skip the current separator */ if (*psep > path && vim_ispathsep(**psep)) @@ -8313,10 +8230,7 @@ char_u **psep; * Returns TRUE if "maybe_unique" is unique wrt other_paths in "gap". * "maybe_unique" is the end portion of "((char_u **)gap->ga_data)[i]". */ -static int is_unique(maybe_unique, gap, i) -char_u *maybe_unique; -garray_T *gap; -int i; +static int is_unique(char_u *maybe_unique, garray_T *gap, int i) { int j; int candidate_len; @@ -8351,9 +8265,7 @@ int i; * TODO: handle upward search (;) and path limiter (**N) notations by * expanding each into their equivalent path(s). */ -static void expand_path_option(curdir, gap) -char_u *curdir; -garray_T *gap; +static void expand_path_option(char_u *curdir, garray_T *gap) { char_u *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; @@ -8421,9 +8333,7 @@ garray_T *gap; * fname: /foo/bar/baz/quux.txt * returns: ^this */ -static char_u * get_path_cutoff(fname, gap) -char_u *fname; -garray_T *gap; +static char_u *get_path_cutoff(char_u *fname, garray_T *gap) { int i; int maxlen = 0; @@ -8455,9 +8365,7 @@ garray_T *gap; * that they are unique with respect to each other while conserving the part * that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". */ -static void uniquefy_paths(gap, pattern) -garray_T *gap; -char_u *pattern; +static void uniquefy_paths(garray_T *gap, char_u *pattern) { int i; int len; @@ -8608,10 +8516,12 @@ theend: * result in "gap". * Returns the total number of matches. */ -static int expand_in_path(gap, pattern, flags) -garray_T *gap; -char_u *pattern; -int flags; /* EW_* flags */ +static int +expand_in_path ( + garray_T *gap, + char_u *pattern, + int flags /* EW_* flags */ +) { char_u *curdir; garray_T path_ga; @@ -8665,8 +8575,7 @@ int flags; /* EW_* flags */ * Sort "gap" and remove duplicate entries. "gap" is expected to contain a * list of file names in allocated memory. */ -void remove_duplicates(gap) -garray_T *gap; +void remove_duplicates(garray_T *gap) { int i; int j; @@ -8688,8 +8597,7 @@ static int has_env_var __ARGS((char_u *p)); * Return TRUE if "p" contains what looks like an environment variable. * Allowing for escaping. */ -static int has_env_var(p) -char_u *p; +static int has_env_var(char_u *p) { for (; *p; mb_ptr_adv(p)) { if (*p == '\\' && p[1] != NUL) @@ -8709,8 +8617,7 @@ static int has_special_wildchar __ARGS((char_u *p)); * Return TRUE if "p" contains a special wildcard character. * Allowing for escaping. */ -static int has_special_wildchar(p) -char_u *p; +static int has_special_wildchar(char_u *p) { for (; *p; mb_ptr_adv(p)) { if (*p == '\\' && p[1] != NUL) @@ -8733,12 +8640,14 @@ char_u *p; * Return OK when some files found. "num_file" is set to the number of * matches, "file" to the array of matches. Call FreeWild() later. */ -int gen_expand_wildcards(num_pat, pat, num_file, file, flags) -int num_pat; /* number of input patterns */ -char_u **pat; /* array of input patterns */ -int *num_file; /* resulting number of files */ -char_u ***file; /* array of resulting files */ -int flags; /* EW_* flags */ +int +gen_expand_wildcards ( + int num_pat, /* number of input patterns */ + char_u **pat, /* array of input patterns */ + int *num_file, /* resulting number of files */ + char_u ***file, /* array of resulting files */ + int flags /* EW_* flags */ +) { int i; garray_T ga; @@ -8868,8 +8777,7 @@ int flags; /* EW_* flags */ /* * Return TRUE if we can expand this backtick thing here. */ -static int vim_backtick(p) -char_u *p; +static int vim_backtick(char_u *p) { return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'; } @@ -8879,10 +8787,12 @@ char_u *p; * Currently only works when pat[] starts and ends with a `. * Returns number of file names found. */ -static int expand_backtick(gap, pat, flags) -garray_T *gap; -char_u *pat; -int flags; /* EW_* flags */ +static int +expand_backtick ( + garray_T *gap, + char_u *pat, + int flags /* EW_* flags */ +) { char_u *p; char_u *cmd; @@ -8935,10 +8845,12 @@ int flags; /* EW_* flags */ * EW_NOTFOUND add even when it doesn't exist * EW_ADDSLASH add slash after directory name */ -void addfile(gap, f, flags) -garray_T *gap; -char_u *f; /* filename */ -int flags; +void +addfile ( + garray_T *gap, + char_u *f, /* filename */ + int flags +) { char_u *p; int isdir; @@ -8996,10 +8908,12 @@ int flags; * Get the stdout of an external command. * Returns an allocated string, or NULL for error. */ -char_u * get_cmd_output(cmd, infile, flags) -char_u *cmd; -char_u *infile; /* optional input file name */ -int flags; /* can be SHELL_SILENT */ +char_u * +get_cmd_output ( + char_u *cmd, + char_u *infile, /* optional input file name */ + int flags /* can be SHELL_SILENT */ +) { char_u *tempname; char_u *command; @@ -9075,9 +8989,7 @@ done: * Free the list of files returned by expand_wildcards() or other expansion * functions. */ -void FreeWild(count, files) -int count; -char_u **files; +void FreeWild(int count, char_u **files) { if (count <= 0 || files == NULL) return; @@ -9091,7 +9003,7 @@ char_u **files; * Don't do this when still processing a command or a mapping. * Don't do this when inside a ":normal" command. */ -int goto_im() { +int goto_im(void) { return p_im && stuff_empty() && typebuf_typed(); } diff --git a/src/misc2.c b/src/misc2.c index e18de18258..e59ccf6626 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -22,7 +22,7 @@ static int coladvance2 __ARGS((pos_T *pos, int addspaces, int finetune, /* * Return TRUE if in the current mode we need to use virtual. */ -int virtual_active() { +int virtual_active(void) { /* While an operator is being executed we return "virtual_op", because * VIsual_active has already been reset, thus we can't check for "block" * being used. */ @@ -36,7 +36,7 @@ int virtual_active() { /* * Get the screen position of the cursor. */ -int getviscol() { +int getviscol(void) { colnr_T x; getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL); @@ -46,9 +46,7 @@ int getviscol() { /* * Get the screen position of character col with a coladd in the cursor line. */ -int getviscol2(col, coladd) -colnr_T col; -colnr_T coladd; +int getviscol2(colnr_T col, colnr_T coladd) { colnr_T x; pos_T pos; @@ -65,8 +63,7 @@ colnr_T coladd; * cursor in that column. * The caller must have saved the cursor line for undo! */ -int coladvance_force(wcol) -colnr_T wcol; +int coladvance_force(colnr_T wcol) { int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol); @@ -89,8 +86,7 @@ colnr_T wcol; * * return OK if desired column is reached, FAIL if not */ -int coladvance(wcol) -colnr_T wcol; +int coladvance(colnr_T wcol) { int rc = getvpos(&curwin->w_cursor, wcol); @@ -108,18 +104,18 @@ colnr_T wcol; * Return in "pos" the position of the cursor advanced to screen column "wcol". * return OK if desired column is reached, FAIL if not */ -int getvpos(pos, wcol) -pos_T *pos; -colnr_T wcol; +int getvpos(pos_T *pos, colnr_T wcol) { return coladvance2(pos, FALSE, virtual_active(), wcol); } -static int coladvance2(pos, addspaces, finetune, wcol) -pos_T *pos; -int addspaces; /* change the text to achieve our goal? */ -int finetune; /* change char offset for the exact column */ -colnr_T wcol; /* column to move to */ +static int +coladvance2 ( + pos_T *pos, + int addspaces, /* change the text to achieve our goal? */ + int finetune, /* change char offset for the exact column */ + colnr_T wcol /* column to move to */ +) { int idx; char_u *ptr; @@ -286,7 +282,7 @@ colnr_T wcol; /* column to move to */ /* * Increment the cursor position. See inc() for return values. */ -int inc_cursor() { +int inc_cursor(void) { return inc(&curwin->w_cursor); } @@ -297,8 +293,7 @@ int inc_cursor() { * Return -1 when at the end of file. * Return 0 otherwise. */ -int inc(lp) -pos_T *lp; +int inc(pos_T *lp) { char_u *p = ml_get_pos(lp); @@ -325,8 +320,7 @@ pos_T *lp; /* * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines */ -int incl(lp) -pos_T *lp; +int incl(pos_T *lp) { int r; @@ -341,12 +335,11 @@ pos_T *lp; * Decrement the line pointer 'p' crossing line boundaries as necessary. * Return 1 when crossing a line, -1 when at start of file, 0 otherwise. */ -int dec_cursor() { +int dec_cursor(void) { return dec(&curwin->w_cursor); } -int dec(lp) -pos_T *lp; +int dec(pos_T *lp) { char_u *p; @@ -373,8 +366,7 @@ pos_T *lp; /* * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines */ -int decl(lp) -pos_T *lp; +int decl(pos_T *lp) { int r; @@ -388,9 +380,11 @@ pos_T *lp; * difference between line number and cursor position. Only look for lines that * can be visible, folded lines don't count. */ -linenr_T get_cursor_rel_lnum(wp, lnum) -win_T *wp; -linenr_T lnum; /* line number to get the result for */ +linenr_T +get_cursor_rel_lnum ( + win_T *wp, + linenr_T lnum /* line number to get the result for */ +) { linenr_T cursor = wp->w_cursor.lnum; linenr_T retval = 0; @@ -427,7 +421,7 @@ linenr_T lnum; /* line number to get the result for */ /* * Make sure curwin->w_cursor.lnum is valid. */ -void check_cursor_lnum() { +void check_cursor_lnum(void) { if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { /* If there is a closed fold at the end of the file, put the cursor in * its first line. Otherwise in the last line. */ @@ -442,15 +436,14 @@ void check_cursor_lnum() { /* * Make sure curwin->w_cursor.col is valid. */ -void check_cursor_col() { +void check_cursor_col(void) { check_cursor_col_win(curwin); } /* * Make sure win->w_cursor.col is valid. */ -void check_cursor_col_win(win) -win_T *win; +void check_cursor_col_win(win_T *win) { colnr_T len; colnr_T oldcol = win->w_cursor.col; @@ -495,7 +488,7 @@ win_T *win; /* * make sure curwin->w_cursor in on a valid character */ -void check_cursor() { +void check_cursor(void) { check_cursor_lnum(); check_cursor_col(); } @@ -504,7 +497,7 @@ void check_cursor() { * Make sure curwin->w_cursor is not on the NUL at the end of the line. * Allow it when in Visual mode and 'selection' is not "old". */ -void adjust_cursor_col() { +void adjust_cursor_col(void) { if (curwin->w_cursor.col > 0 && (!VIsual_active || *p_sel == 'o') && gchar_cursor() == NUL) @@ -515,7 +508,7 @@ void adjust_cursor_col() { * When curwin->w_leftcol has changed, adjust the cursor position. * Return TRUE if the cursor was moved. */ -int leftcol_changed() { +int leftcol_changed(void) { long lastcol; colnr_T s, e; int retval = FALSE; @@ -579,21 +572,17 @@ static void mem_pre_alloc_l __ARGS((long_u *sizep)); static void mem_post_alloc __ARGS((void **pp, size_t size)); static void mem_pre_free __ARGS((void **pp)); -static void mem_pre_alloc_s(sizep) -size_t *sizep; +static void mem_pre_alloc_s(size_t *sizep) { *sizep += sizeof(size_t); } -static void mem_pre_alloc_l(sizep) -long_u *sizep; +static void mem_pre_alloc_l(long_u *sizep) { *sizep += sizeof(size_t); } -static void mem_post_alloc(pp, size) -void **pp; -size_t size; +static void mem_post_alloc(void **pp, size_t size) { if (*pp == NULL) return; @@ -610,8 +599,7 @@ size_t size; *pp = (void *)((char *)*pp + sizeof(size_t)); } -static void mem_pre_free(pp) -void **pp; +static void mem_pre_free(void **pp) { long_u size; @@ -628,7 +616,7 @@ void **pp; /* * called on exit via atexit() */ -void vim_mem_profile_dump() { +void vim_mem_profile_dump(void) { int i, j; printf("\r\n"); @@ -673,8 +661,7 @@ void vim_mem_profile_dump() { * Note: if unsigned is 16 bits we can only allocate up to 64K with alloc(). * Use lalloc for larger blocks. */ -char_u * alloc(size) -unsigned size; +char_u *alloc(unsigned size) { return lalloc((long_u)size, TRUE); } @@ -682,8 +669,7 @@ unsigned size; /* * Allocate memory and set all bytes to zero. */ -char_u * alloc_clear(size) -unsigned size; +char_u *alloc_clear(unsigned size) { char_u *p; @@ -696,8 +682,7 @@ unsigned size; /* * alloc() with check for maximum line length */ -char_u * alloc_check(size) -unsigned size; +char_u *alloc_check(unsigned size) { #if !defined(UNIX) && !defined(__EMX__) if (sizeof(int) == 2 && size > 0x7fff) { @@ -713,9 +698,7 @@ unsigned size; /* * Allocate memory like lalloc() and set all bytes to zero. */ -char_u * lalloc_clear(size, message) -long_u size; -int message; +char_u *lalloc_clear(long_u size, int message) { char_u *p; @@ -729,9 +712,7 @@ int message; * Low level memory allocation function. * This is used often, KEEP IT FAST! */ -char_u * lalloc(size, message) -long_u size; -int message; +char_u *lalloc(long_u size, int message) { char_u *p; /* pointer to new storage space */ static int releasing = FALSE; /* don't do mf_release_all() recursive */ @@ -817,9 +798,7 @@ theend: /* * realloc() with memory profiling. */ -void * mem_realloc(ptr, size) -void *ptr; -size_t size; +void *mem_realloc(void *ptr, size_t size) { void *p; @@ -838,8 +817,7 @@ size_t size; * Avoid repeating the error message many times (they take 1 second each). * Did_outofmem_msg is reset when a character is read. */ -void do_outofmem_msg(size) -long_u size; +void do_outofmem_msg(long_u size) { if (!did_outofmem_msg) { /* Don't hide this message */ @@ -864,7 +842,7 @@ static void free_findfile __ARGS((void)); * surprised if Vim crashes... * Some things can't be freed, esp. things local to a library function. */ -void free_all_mem() { +void free_all_mem(void) { buf_T *buf, *nextbuf; static int entered = FALSE; @@ -1008,8 +986,7 @@ void free_all_mem() { /* * Copy "string" into newly allocated memory. */ -char_u * vim_strsave(string) -char_u *string; +char_u *vim_strsave(char_u *string) { char_u *p; unsigned len; @@ -1027,9 +1004,7 @@ char_u *string; * The allocated memory always has size "len + 1", also when "string" is * shorter. */ -char_u * vim_strnsave(string, len) -char_u *string; -int len; +char_u *vim_strnsave(char_u *string, int len) { char_u *p; @@ -1045,9 +1020,7 @@ int len; * Same as vim_strsave(), but any characters found in esc_chars are preceded * by a backslash. */ -char_u * vim_strsave_escaped(string, esc_chars) -char_u *string; -char_u *esc_chars; +char_u *vim_strsave_escaped(char_u *string, char_u *esc_chars) { return vim_strsave_escaped_ext(string, esc_chars, '\\', FALSE); } @@ -1057,11 +1030,7 @@ char_u *esc_chars; * characters where rem_backslash() would remove the backslash. * Escape the characters with "cc". */ -char_u * vim_strsave_escaped_ext(string, esc_chars, cc, bsl) -char_u *string; -char_u *esc_chars; -int cc; -int bsl; +char_u *vim_strsave_escaped_ext(char_u *string, char_u *esc_chars, int cc, int bsl) { char_u *p; char_u *p2; @@ -1106,7 +1075,7 @@ int bsl; /* * Return TRUE when 'shell' has "csh" in the tail. */ -int csh_like_shell() { +int csh_like_shell(void) { return strstr((char *)gettail(p_sh), "csh") != NULL; } @@ -1119,9 +1088,7 @@ int csh_like_shell() { * with "<" like "". * Returns the result in allocated memory, NULL if we have run out. */ -char_u * vim_strsave_shellescape(string, do_special) -char_u *string; -int do_special; +char_u *vim_strsave_shellescape(char_u *string, int do_special) { unsigned length; char_u *p; @@ -1198,8 +1165,7 @@ int do_special; * Like vim_strsave(), but make all characters uppercase. * This uses ASCII lower-to-upper case translation, language independent. */ -char_u * vim_strsave_up(string) -char_u *string; +char_u *vim_strsave_up(char_u *string) { char_u *p1; @@ -1212,9 +1178,7 @@ char_u *string; * Like vim_strnsave(), but make all characters uppercase. * This uses ASCII lower-to-upper case translation, language independent. */ -char_u * vim_strnsave_up(string, len) -char_u *string; -int len; +char_u *vim_strnsave_up(char_u *string, int len) { char_u *p1; @@ -1226,8 +1190,7 @@ int len; /* * ASCII lower-to-upper case translation, language independent. */ -void vim_strup(p) -char_u *p; +void vim_strup(char_u *p) { char_u *p2; int c; @@ -1244,8 +1207,7 @@ char_u *p; * Handles multi-byte characters as well as possible. * Returns NULL when out of memory. */ -char_u * strup_save(orig) -char_u *orig; +char_u *strup_save(char_u *orig) { char_u *p; char_u *res; @@ -1295,9 +1257,7 @@ char_u *orig; /* * copy a space a number of times */ -void copy_spaces(ptr, count) -char_u *ptr; -size_t count; +void copy_spaces(char_u *ptr, size_t count) { size_t i = count; char_u *p = ptr; @@ -1310,10 +1270,7 @@ size_t count; * Copy a character a number of times. * Does not work for multi-byte characters! */ -void copy_chars(ptr, count, c) -char_u *ptr; -size_t count; -int c; +void copy_chars(char_u *ptr, size_t count, int c) { size_t i = count; char_u *p = ptr; @@ -1325,8 +1282,7 @@ int c; /* * delete spaces at the end of a string */ -void del_trailing_spaces(ptr) -char_u *ptr; +void del_trailing_spaces(char_u *ptr) { char_u *q; @@ -1339,10 +1295,7 @@ char_u *ptr; * Like strncpy(), but always terminate the result with one NUL. * "to" must be "len + 1" long! */ -void vim_strncpy(to, from, len) -char_u *to; -char_u *from; -size_t len; +void vim_strncpy(char_u *to, char_u *from, size_t len) { STRNCPY(to, from, len); to[len] = NUL; @@ -1352,10 +1305,7 @@ size_t len; * Like strcat(), but make sure the result fits in "tosize" bytes and is * always NUL terminated. */ -void vim_strcat(to, from, tosize) -char_u *to; -char_u *from; -size_t tosize; +void vim_strcat(char_u *to, char_u *from, size_t tosize) { size_t tolen = STRLEN(to); size_t fromlen = STRLEN(from); @@ -1374,11 +1324,7 @@ size_t tosize; * "*option" is advanced to the next part. * The length is returned. */ -int copy_option_part(option, buf, maxlen, sep_chars) -char_u **option; -char_u *buf; -int maxlen; -char *sep_chars; +int copy_option_part(char_u **option, char_u *buf, int maxlen, char *sep_chars) { int len = 0; char_u *p = *option; @@ -1411,8 +1357,7 @@ char *sep_chars; * Also skip free() when exiting for sure, this helps when we caught a deadly * signal that was caused by a crash in free(). */ -void vim_free(x) -void *x; +void vim_free(void *x) { if (x != NULL && !really_exiting) { #ifdef MEM_PROFILE @@ -1490,9 +1435,7 @@ size_t len; * Doesn't work for multi-byte characters. * return 0 for match, < 0 for smaller, > 0 for bigger */ -int vim_stricmp(s1, s2) -char *s1; -char *s2; +int vim_stricmp(char *s1, char *s2) { int i; @@ -1515,10 +1458,7 @@ char *s2; * Doesn't work for multi-byte characters. * return 0 for match, < 0 for smaller, > 0 for bigger */ -int vim_strnicmp(s1, s2, len) -char *s1; -char *s2; -size_t len; +int vim_strnicmp(char *s1, char *s2, size_t len) { int i; @@ -1541,9 +1481,7 @@ size_t len; * with characters from 128 to 255 correctly. It also doesn't return a * pointer to the NUL at the end of the string. */ -char_u * vim_strchr(string, c) -char_u *string; -int c; +char_u *vim_strchr(char_u *string, int c) { char_u *p; int b; @@ -1589,9 +1527,7 @@ int c; * strings with characters above 128 correctly. It also doesn't return a * pointer to the NUL at the end of the string. */ -char_u * vim_strbyte(string, c) -char_u *string; -int c; +char_u *vim_strbyte(char_u *string, int c) { char_u *p = string; @@ -1608,9 +1544,7 @@ int c; * Return NULL if not found. * Does not handle multi-byte char for "c"! */ -char_u * vim_strrchr(string, c) -char_u *string; -int c; +char_u *vim_strrchr(char_u *string, int c) { char_u *retval = NULL; char_u *p = string; @@ -1631,9 +1565,7 @@ int c; # ifdef vim_strpbrk # undef vim_strpbrk # endif -char_u * vim_strpbrk(s, charset) -char_u *s; -char_u *charset; +char_u *vim_strpbrk(char_u *s, char_u *charset) { while (*s) { if (vim_strchr(charset, *s) != NULL) @@ -1648,8 +1580,7 @@ char_u *charset; * Vim has its own isspace() function, because on some machines isspace() * can't handle characters above 128. */ -int vim_isspace(x) -int x; +int vim_isspace(int x) { return (x >= 9 && x <= 13) || x == ' '; } @@ -1661,8 +1592,7 @@ int x; /* * Clear an allocated growing array. */ -void ga_clear(gap) -garray_T *gap; +void ga_clear(garray_T *gap) { vim_free(gap->ga_data); ga_init(gap); @@ -1671,8 +1601,7 @@ garray_T *gap; /* * Clear a growing array that contains a list of strings. */ -void ga_clear_strings(gap) -garray_T *gap; +void ga_clear_strings(garray_T *gap) { int i; @@ -1685,18 +1614,14 @@ garray_T *gap; * Initialize a growing array. Don't forget to set ga_itemsize and * ga_growsize! Or use ga_init2(). */ -void ga_init(gap) -garray_T *gap; +void ga_init(garray_T *gap) { gap->ga_data = NULL; gap->ga_maxlen = 0; gap->ga_len = 0; } -void ga_init2(gap, itemsize, growsize) -garray_T *gap; -int itemsize; -int growsize; +void ga_init2(garray_T *gap, int itemsize, int growsize) { ga_init(gap); gap->ga_itemsize = itemsize; @@ -1707,9 +1632,7 @@ int growsize; * Make room in growing array "gap" for at least "n" items. * Return FAIL for failure, OK otherwise. */ -int ga_grow(gap, n) -garray_T *gap; -int n; +int ga_grow(garray_T *gap, int n) { size_t old_len; size_t new_len; @@ -1736,8 +1659,7 @@ int n; * strings with a separating comma. * Returns NULL when out of memory. */ -char_u * ga_concat_strings(gap) -garray_T *gap; +char_u *ga_concat_strings(garray_T *gap) { int i; int len = 0; @@ -1762,9 +1684,7 @@ garray_T *gap; * Concatenate a string to a growarray which contains characters. * Note: Does NOT copy the NUL at the end! */ -void ga_concat(gap, s) -garray_T *gap; -char_u *s; +void ga_concat(garray_T *gap, char_u *s) { int len = (int)STRLEN(s); @@ -1777,9 +1697,7 @@ char_u *s; /* * Append one byte to a growarray which contains bytes. */ -void ga_append(gap, c) -garray_T *gap; -int c; +void ga_append(garray_T *gap, int c) { if (ga_grow(gap, 1) == OK) { *((char *)gap->ga_data + gap->ga_len) = c; @@ -1791,8 +1709,7 @@ int c; /* * Append the text in "gap" below the cursor line and clear "gap". */ -void append_ga_line(gap) -garray_T *gap; +void append_ga_line(garray_T *gap) { /* Remove trailing CR. */ if (gap->ga_len > 0 @@ -2120,8 +2037,7 @@ static struct mousetable { * Return the modifier mask bit (MOD_MASK_*) which corresponds to the given * modifier name ('S' for Shift, 'C' for Ctrl etc). */ -int name_to_mod_mask(c) -int c; +int name_to_mod_mask(int c) { int i; @@ -2136,9 +2052,7 @@ int c; * Check if if there is a special key code for "key" that includes the * modifiers specified. */ -int simplify_key(key, modifiers) -int key; -int *modifiers; +int simplify_key(int key, int *modifiers) { int i; int key0; @@ -2167,8 +2081,7 @@ int *modifiers; /* * Change to , to , etc. */ -int handle_x_keys(key) -int key; +int handle_x_keys(int key) { switch (key) { case K_XUP: return K_UP; @@ -2195,9 +2108,7 @@ int key; * Return a string which contains the name of the given key when the given * modifiers are down. */ -char_u * get_special_key_name(c, modifiers) -int c; -int modifiers; +char_u *get_special_key_name(int c, int modifiers) { static char_u string[MAX_KEY_NAME_LEN + 1]; @@ -2293,10 +2204,12 @@ int modifiers; * If there is a match, srcp is advanced to after the <> name. * dst[] must be big enough to hold the result (up to six characters)! */ -int trans_special(srcp, dst, keycode) -char_u **srcp; -char_u *dst; -int keycode; /* prefer key code, e.g. K_DEL instead of DEL */ +int +trans_special ( + char_u **srcp, + char_u *dst, + int keycode /* prefer key code, e.g. K_DEL instead of DEL */ +) { int modifiers = 0; int key; @@ -2332,11 +2245,13 @@ int keycode; /* prefer key code, e.g. K_DEL instead of DEL */ * srcp is advanced to after the <> name. * returns 0 if there is no match. */ -int find_special_key(srcp, modp, keycode, keep_x_key) -char_u **srcp; -int *modp; -int keycode; /* prefer key code, e.g. K_DEL instead of DEL */ -int keep_x_key; /* don't translate xHome to Home key */ +int +find_special_key ( + char_u **srcp, + int *modp, + int keycode, /* prefer key code, e.g. K_DEL instead of DEL */ + int keep_x_key /* don't translate xHome to Home key */ +) { char_u *last_dash; char_u *end_of_name; @@ -2453,9 +2368,7 @@ int keep_x_key; /* don't translate xHome to Home key */ * Try to include modifiers in the key. * Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc. */ -int extract_modifiers(key, modp) -int key; -int *modp; +int extract_modifiers(int key, int *modp) { int modifiers = *modp; @@ -2487,8 +2400,7 @@ int *modp; * Try to find key "c" in the special key table. * Return the index when found, -1 when not found. */ -int find_special_key_in_table(c) -int c; +int find_special_key_in_table(int c) { int i; @@ -2507,8 +2419,7 @@ int c; * termcap name. * Return the key code, or 0 if not found. */ -int get_special_key_code(name) -char_u *name; +int get_special_key_code(char_u *name) { char_u *table_name; char_u string[3]; @@ -2535,8 +2446,7 @@ char_u *name; return 0; } -char_u * get_key_name(i) -int i; +char_u *get_key_name(int i) { if (i >= (int)KEY_NAMES_TABLE_LEN) return NULL; @@ -2547,10 +2457,7 @@ int i; * Look up the given mouse code to return the relevant information in the other * arguments. Return which button is down or was released. */ -int get_mouse_button(code, is_click, is_drag) -int code; -int *is_click; -int *is_drag; +int get_mouse_button(int code, int *is_click, int *is_drag) { int i; @@ -2568,10 +2475,12 @@ int *is_drag; * the given information about which mouse button is down, and whether the * mouse was clicked, dragged or released. */ -int get_pseudo_mouse_code(button, is_click, is_drag) -int button; /* eg MOUSE_LEFT */ -int is_click; -int is_drag; +int +get_pseudo_mouse_code ( + int button, /* eg MOUSE_LEFT */ + int is_click, + int is_drag +) { int i; @@ -2587,8 +2496,7 @@ int is_drag; /* * Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. */ -int get_fileformat(buf) -buf_T *buf; +int get_fileformat(buf_T *buf) { int c = *buf->b_p_ff; @@ -2603,9 +2511,11 @@ buf_T *buf; * Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val" * argument. */ -int get_fileformat_force(buf, eap) -buf_T *buf; -exarg_T *eap; /* can be NULL! */ +int +get_fileformat_force ( + buf_T *buf, + exarg_T *eap /* can be NULL! */ +) { int c; @@ -2629,9 +2539,11 @@ exarg_T *eap; /* can be NULL! */ * Sets both 'textmode' and 'fileformat'. * Note: Does _not_ set global value of 'textmode'! */ -void set_fileformat(t, opt_flags) -int t; -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +void +set_fileformat ( + int t, + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { char *p = NULL; @@ -2662,7 +2574,7 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ /* * Return the default fileformat from 'fileformats'. */ -int default_fileformat() { +int default_fileformat(void) { switch (*p_ffs) { case 'm': return EOL_MAC; case 'd': return EOL_DOS; @@ -2673,9 +2585,7 @@ int default_fileformat() { /* * Call shell. Calls mch_call_shell, with 'shellxquote' added. */ -int call_shell(cmd, opt) -char_u *cmd; -int opt; +int call_shell(char_u *cmd, int opt) { char_u *ncmd; int retval; @@ -2744,7 +2654,7 @@ int opt; * VISUAL, SELECTMODE and OP_PENDING State are never set, they are equal to * NORMAL State with a condition. This function returns the real State. */ -int get_real_state() { +int get_real_state(void) { if (State & NORMAL) { if (VIsual_active) { if (VIsual_select) @@ -2761,9 +2671,7 @@ int get_real_state() { * Takes care of multi-byte characters. * "b" must point to the start of the file name */ -int after_pathsep(b, p) -char_u *b; -char_u *p; +int after_pathsep(char_u *b, char_u *p) { return p > b && vim_ispathsep(p[-1]) && (!has_mbyte || (*mb_head_off)(b, p - 1) == 0); @@ -2773,9 +2681,7 @@ char_u *p; * Return TRUE if file names "f1" and "f2" are in the same directory. * "f1" may be a short name, "f2" must be a full path. */ -int same_directory(f1, f2) -char_u *f1; -char_u *f2; +int same_directory(char_u *f1, char_u *f2) { char_u ffname[MAXPATHL]; char_u *t1; @@ -2802,8 +2708,7 @@ char_u *f2; * Caller must call shorten_fnames()! * Return OK or FAIL. */ -int vim_chdirfile(fname) -char_u *fname; +int vim_chdirfile(char_u *fname) { char_u dir[MAXPATHL]; @@ -2819,8 +2724,7 @@ char_u *fname; * Used for systems where stat() ignores a trailing slash on a file name. * The Vim code assumes a trailing slash is only ignored for a directory. */ -int illegal_slash(name) -char *name; +int illegal_slash(char *name) { if (name[0] == NUL) return FALSE; /* no file name is not illegal */ @@ -2868,8 +2772,7 @@ cursorentry_T shape_table[SHAPE_IDX_COUNT] = * ("what" is SHAPE_MOUSE). * Returns error message for an illegal option, NULL otherwise. */ -char_u * parse_shape_opt(what) -int what; +char_u *parse_shape_opt(int what) { char_u *modep; char_u *colonp; @@ -3045,8 +2948,7 @@ int what; * Return the index into shape_table[] for the current mode. * When "mouse" is TRUE, consider indexes valid for the mouse pointer. */ -int get_shape_idx(mouse) -int mouse; +int get_shape_idx(int mouse) { if (!mouse && State == SHOWMATCH) return SHAPE_IDX_SM; @@ -3106,7 +3008,7 @@ static ulg crc_32_tab[256]; /* * Fill the CRC table. */ -static void make_crc_tab() { +static void make_crc_tab(void) { ulg s,t,v; static int done = FALSE; @@ -3154,8 +3056,7 @@ static int saved_crypt_method; * 0 for "zip", the old method. Also for any non-valid value. * 1 for "blowfish". */ -int crypt_method_from_string(s) -char_u *s; +int crypt_method_from_string(char_u *s) { return *s == 'b' ? 1 : 0; } @@ -3163,8 +3064,7 @@ char_u *s; /* * Get the crypt method for buffer "buf" as a number. */ -int get_crypt_method(buf) -buf_T *buf; +int get_crypt_method(buf_T *buf) { return crypt_method_from_string(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm); } @@ -3173,9 +3073,7 @@ buf_T *buf; * Set the crypt method for buffer "buf" to "method" using the int value as * returned by crypt_method_from_string(). */ -void set_crypt_method(buf, method) -buf_T *buf; -int method; +void set_crypt_method(buf_T *buf, int method) { free_string_option(buf->b_p_cm); buf->b_p_cm = vim_strsave((char_u *)(method == 0 ? "zip" : "blowfish")); @@ -3186,7 +3084,7 @@ int method; * the state. * Must always be called symmetrically with crypt_pop_state(). */ -void crypt_push_state() { +void crypt_push_state(void) { if (crypt_busy == 1) { /* save the state */ if (use_crypt_method == 0) { @@ -3206,7 +3104,7 @@ void crypt_push_state() { * the saved state. * Must always be called symmetrically with crypt_push_state(). */ -void crypt_pop_state() { +void crypt_pop_state(void) { --crypt_busy; if (crypt_busy == 1) { use_crypt_method = saved_crypt_method; @@ -3223,10 +3121,7 @@ void crypt_pop_state() { * Encrypt "from[len]" into "to[len]". * "from" and "to" can be equal to encrypt in place. */ -void crypt_encode(from, len, to) -char_u *from; -size_t len; -char_u *to; +void crypt_encode(char_u *from, size_t len, char_u *to) { size_t i; int ztemp, t; @@ -3245,9 +3140,7 @@ char_u *to; /* * Decrypt "ptr[len]" in place. */ -void crypt_decode(ptr, len) -char_u *ptr; -long len; +void crypt_decode(char_u *ptr, long len) { char_u *p; @@ -3268,8 +3161,10 @@ long len; * the given password. * If "passwd" is NULL or empty, don't do anything. */ -void crypt_init_keys(passwd) -char_u *passwd; /* password string with which to modify keys */ +void +crypt_init_keys ( + char_u *passwd /* password string with which to modify keys */ +) { if (passwd != NULL && *passwd != NUL) { if (use_crypt_method == 0) { @@ -3291,8 +3186,7 @@ char_u *passwd; /* password string with which to modify keys */ * Free an allocated crypt key. Clear the text to make sure it doesn't stay * in memory anywhere. */ -void free_crypt_key(key) -char_u *key; +void free_crypt_key(char_u *key) { char_u *p; @@ -3310,9 +3204,11 @@ char_u *key; * When "store" is FALSE, the typed key is returned in allocated memory. * Returns NULL on failure. */ -char_u * get_crypt_key(store, twice) -int store; -int twice; /* Ask for the key twice. */ +char_u * +get_crypt_key ( + int store, + int twice /* Ask for the key twice. */ +) { char_u *p1, *p2 = NULL; int round; @@ -3599,19 +3495,18 @@ static char_u e_pathtoolong[] = N_("E854: path too long for completion"); * This function silently ignores a few errors, vim_findfile() will have * limited functionality then. */ -void * vim_findfile_init(path, filename, stopdirs, level, free_visited, - find_what, - search_ctx_arg, tagfile, - rel_fname) -char_u *path; -char_u *filename; -char_u *stopdirs UNUSED; -int level; -int free_visited; -int find_what; -void *search_ctx_arg; -int tagfile; /* expanding names of tags files */ -char_u *rel_fname; /* file name to use for "." */ +void * +vim_findfile_init ( + char_u *path, + char_u *filename, + char_u *stopdirs, + int level, + int free_visited, + int find_what, + void *search_ctx_arg, + int tagfile, /* expanding names of tags files */ + char_u *rel_fname /* file name to use for "." */ +) { char_u *wc_part; ff_stack_T *sptr; @@ -3911,8 +3806,7 @@ error_return: /* * Get the stopdir string. Check that ';' is not escaped. */ -char_u * vim_findfile_stopdir(buf) -char_u *buf; +char_u *vim_findfile_stopdir(char_u *buf) { char_u *r_ptr = buf; @@ -3936,8 +3830,7 @@ char_u *buf; /* * Clean up the given search context. Can handle a NULL pointer. */ -void vim_findfile_cleanup(ctx) -void *ctx; +void vim_findfile_cleanup(void *ctx) { if (ctx == NULL) return; @@ -3959,8 +3852,7 @@ void *ctx; * stack with a list (don't forget to leave partly searched directories on the * top of the list). */ -char_u * vim_findfile(search_ctx_arg) -void *search_ctx_arg; +char_u *vim_findfile(void *search_ctx_arg) { char_u *file_path; char_u *rest_of_wildcards; @@ -4344,8 +4236,7 @@ void *search_ctx_arg; * Free the list of lists of visited files and directories * Can handle it if the passed search_context is NULL; */ -void vim_findfile_free_visited(search_ctx_arg) -void *search_ctx_arg; +void vim_findfile_free_visited(void *search_ctx_arg) { ff_search_ctx_T *search_ctx; @@ -4357,8 +4248,7 @@ void *search_ctx_arg; vim_findfile_free_visited_list(&search_ctx->ffsc_dir_visited_lists_list); } -static void vim_findfile_free_visited_list(list_headp) -ff_visited_list_hdr_T **list_headp; +static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp) { ff_visited_list_hdr_T *vp; @@ -4373,8 +4263,7 @@ ff_visited_list_hdr_T **list_headp; *list_headp = NULL; } -static void ff_free_visited_list(vl) -ff_visited_T *vl; +static void ff_free_visited_list(ff_visited_T *vl) { ff_visited_T *vp; @@ -4391,9 +4280,7 @@ ff_visited_T *vl; * Returns the already visited list for the given filename. If none is found it * allocates a new one. */ -static ff_visited_list_hdr_T* ff_get_visited_list(filename, list_headp) -char_u *filename; -ff_visited_list_hdr_T **list_headp; +static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, ff_visited_list_hdr_T **list_headp) { ff_visited_list_hdr_T *retptr = NULL; @@ -4456,9 +4343,7 @@ ff_visited_list_hdr_T **list_headp; * - the only differences are in the counters behind a '**', so * '**\20' is equal to '**\24' */ -static int ff_wc_equal(s1, s2) -char_u *s1; -char_u *s2; +static int ff_wc_equal(char_u *s1, char_u *s2) { int i; int prev1 = NUL; @@ -4495,11 +4380,7 @@ char_u *s2; * -> return TRUE - Better the file is found several times instead of * never. */ -static int ff_check_visited(visited_list, fname - , wc_path) -ff_visited_T **visited_list; -char_u *fname; -char_u *wc_path; +static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path) { ff_visited_T *vp; #ifdef UNIX @@ -4576,13 +4457,7 @@ char_u *wc_path; /* * create stack element from given path pieces */ -static ff_stack_T * ff_create_stack_element(fix_part, - wc_part, - level, star_star_empty) -char_u *fix_part; -char_u *wc_part; -int level; -int star_star_empty; +static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, int level, int star_star_empty) { ff_stack_T *new; @@ -4620,9 +4495,7 @@ int star_star_empty; /* * Push a dir on the directory stack. */ -static void ff_push(search_ctx, stack_ptr) -ff_search_ctx_T *search_ctx; -ff_stack_T *stack_ptr; +static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr) { /* check for NULL pointer, not to return an error to the user, but * to prevent a crash */ @@ -4636,8 +4509,7 @@ ff_stack_T *stack_ptr; * Pop a dir from the directory stack. * Returns NULL if stack is empty. */ -static ff_stack_T * ff_pop(search_ctx) -ff_search_ctx_T *search_ctx; +static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx) { ff_stack_T *sptr; @@ -4651,8 +4523,7 @@ ff_search_ctx_T *search_ctx; /* * free the given stack element */ -static void ff_free_stack_element(stack_ptr) -ff_stack_T *stack_ptr; +static void ff_free_stack_element(ff_stack_T *stack_ptr) { /* vim_free handles possible NULL pointers */ vim_free(stack_ptr->ffs_fix_path); @@ -4667,8 +4538,7 @@ ff_stack_T *stack_ptr; /* * Clear the search context, but NOT the visited list. */ -static void ff_clear(search_ctx) -ff_search_ctx_T *search_ctx; +static void ff_clear(ff_search_ctx_T *search_ctx) { ff_stack_T *sptr; @@ -4704,10 +4574,7 @@ ff_search_ctx_T *search_ctx; * check if the given path is in the stopdirs * returns TRUE if yes else FALSE */ -static int ff_path_in_stoplist(path, path_len, stopdirs_v) -char_u *path; -int path_len; -char_u **stopdirs_v; +static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v) { int i = 0; @@ -4761,12 +4628,14 @@ char_u **stopdirs_v; * Returns an allocated string for the file name. NULL for error. * */ -char_u * find_file_in_path(ptr, len, options, first, rel_fname) -char_u *ptr; /* file name */ -int len; /* length of file name */ -int options; -int first; /* use count'th matching file name */ -char_u *rel_fname; /* file name searching relative to */ +char_u * +find_file_in_path ( + char_u *ptr, /* file name */ + int len, /* length of file name */ + int options, + int first, /* use count'th matching file name */ + char_u *rel_fname /* file name searching relative to */ +) { return find_file_in_path_option(ptr, len, options, first, *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path, @@ -4777,7 +4646,7 @@ static char_u *ff_file_to_find = NULL; static void *fdip_search_ctx = NULL; #if defined(EXITFREE) -static void free_findfile() { +static void free_findfile(void) { vim_free(ff_file_to_find); vim_findfile_cleanup(fdip_search_ctx); } @@ -4794,27 +4663,29 @@ static void free_findfile() { * * Returns an allocated string for the file name. NULL for error. */ -char_u * find_directory_in_path(ptr, len, options, rel_fname) -char_u *ptr; /* file name */ -int len; /* length of file name */ -int options; -char_u *rel_fname; /* file name searching relative to */ +char_u * +find_directory_in_path ( + char_u *ptr, /* file name */ + int len, /* length of file name */ + int options, + char_u *rel_fname /* file name searching relative to */ +) { return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath, FINDFILE_DIR, rel_fname, (char_u *)""); } -char_u * find_file_in_path_option(ptr, len, options, first, path_option, - find_what, rel_fname, - suffixes) -char_u *ptr; /* file name */ -int len; /* length of file name */ -int options; -int first; /* use count'th matching file name */ -char_u *path_option; /* p_path or p_cdpath */ -int find_what; /* FINDFILE_FILE, _DIR or _BOTH */ -char_u *rel_fname; /* file name we are looking relative to. */ -char_u *suffixes; /* list of suffixes, 'suffixesadd' option */ +char_u * +find_file_in_path_option ( + char_u *ptr, /* file name */ + int len, /* length of file name */ + int options, + int first, /* use count'th matching file name */ + char_u *path_option, /* p_path or p_cdpath */ + int find_what, /* FINDFILE_FILE, _DIR or _BOTH */ + char_u *rel_fname, /* file name we are looking relative to. */ + char_u *suffixes /* list of suffixes, 'suffixesadd' option */ +) { static char_u *dir; static int did_findfile_init = FALSE; @@ -4973,8 +4844,7 @@ theend: * Change directory to "new_dir". If FEAT_SEARCHPATH is defined, search * 'cdpath' for relative directory names, otherwise just mch_chdir(). */ -int vim_chdir(new_dir) -char_u *new_dir; +int vim_chdir(char_u *new_dir) { char_u *dir_name; int r; @@ -4995,9 +4865,7 @@ char_u *new_dir; * cache the result. * Returns OK or FAIL. */ -int get_user_name(buf, len) -char_u *buf; -int len; +int get_user_name(char_u *buf, int len) { if (username == NULL) { if (mch_get_user_name(buf, len) == FAIL) @@ -5053,16 +4921,12 @@ int (*cmp)__ARGS((const void *, const void *)); static int sort_compare __ARGS((const void *s1, const void *s2)); -static int sort_compare(s1, s2) -const void *s1; -const void *s2; +static int sort_compare(const void *s1, const void *s2) { return STRCMP(*(char **)s1, *(char **)s2); } -void sort_strings(files, count) -char_u **files; -int count; +void sort_strings(char_u **files, int count) { qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare); } @@ -5073,9 +4937,7 @@ int count; * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" * Return value like strcmp(p, q), but consider path separators. */ -int pathcmp(p, q, maxlen) -const char *p, *q; -int maxlen; +int pathcmp(const char *p, const char *q, int maxlen) { int i; int c1, c2; @@ -5174,8 +5036,7 @@ static int findenv __ARGS((char *name)); /* look for a name in the env. */ static int newenv __ARGS((void)); /* copy env. from stack to heap */ static int moreenv __ARGS((void)); /* incr. size of env. */ -int putenv(string) -const char *string; +int putenv(const char *string) { int i; char *p; @@ -5208,8 +5069,7 @@ const char *string; return 0; } -static int findenv(name) -char *name; +static int findenv(char *name) { char *namechar, *envchar; int i, found; @@ -5227,7 +5087,7 @@ char *name; return found ? i - 1 : -1; } -static int newenv() { +static int newenv(void) { char **env, *elem; int i, esize; @@ -5252,7 +5112,7 @@ static int newenv() { return 0; } -static int moreenv() { +static int moreenv(void) { int esize; char **env; @@ -5266,8 +5126,7 @@ static int moreenv() { } # ifdef USE_VIMPTY_GETENV -char_u * vimpty_getenv(string) -const char_u *string; +char_u *vimpty_getenv(const char_u *string) { int i; char_u *p; @@ -5291,8 +5150,7 @@ const char_u *string; * Return 0 for not writable, 1 for writable file, 2 for a dir which we have * rights to write into. */ -int filewritable(fname) -char_u *fname; +int filewritable(char_u *fname) { int retval = 0; #if defined(UNIX) || defined(VMS) @@ -5319,8 +5177,7 @@ char_u *fname; * Print an error message with one or two "%s" and one or two string arguments. * This is not in message.c to avoid a warning for prototypes. */ -int emsg3(s, a1, a2) -char_u *s, *a1, *a2; +int emsg3(char_u *s, char_u *a1, char_u *a2) { if (emsg_not_now()) return TRUE; /* no error messages at the moment */ @@ -5336,9 +5193,7 @@ char_u *s, *a1, *a2; * Print an error message with one "%ld" and one long int argument. * This is not in message.c to avoid a warning for prototypes. */ -int emsgn(s, n) -char_u *s; -long n; +int emsgn(char_u *s, long n) { if (emsg_not_now()) return TRUE; /* no error messages at the moment */ @@ -5349,8 +5204,7 @@ long n; /* * Read 2 bytes from "fd" and turn them into an int, MSB first. */ -int get2c(fd) -FILE *fd; +int get2c(FILE *fd) { int n; @@ -5362,8 +5216,7 @@ FILE *fd; /* * Read 3 bytes from "fd" and turn them into an int, MSB first. */ -int get3c(fd) -FILE *fd; +int get3c(FILE *fd) { int n; @@ -5376,8 +5229,7 @@ FILE *fd; /* * Read 4 bytes from "fd" and turn them into an int, MSB first. */ -int get4c(fd) -FILE *fd; +int get4c(FILE *fd) { /* Use unsigned rather than int otherwise result is undefined * when left-shift sets the MSB. */ @@ -5393,8 +5245,7 @@ FILE *fd; /* * Read 8 bytes from "fd" and turn them into a time_t, MSB first. */ -time_t get8ctime(fd) -FILE *fd; +time_t get8ctime(FILE *fd) { time_t n = 0; int i; @@ -5408,9 +5259,7 @@ FILE *fd; * Read a string of length "cnt" from "fd" into allocated memory. * Returns NULL when out of memory or unable to read that many bytes. */ -char_u * read_string(fd, cnt) -FILE *fd; -int cnt; +char_u *read_string(FILE *fd, int cnt) { char_u *str; int i; @@ -5436,10 +5285,7 @@ int cnt; /* * Write a number to file "fd", MSB first, in "len" bytes. */ -int put_bytes(fd, nr, len) -FILE *fd; -long_u nr; -int len; +int put_bytes(FILE *fd, long_u nr, int len) { int i; @@ -5453,9 +5299,7 @@ int len; /* * Write time_t to file "fd" in 8 bytes. */ -void put_time(fd, the_time) -FILE *fd; -time_t the_time; +void put_time(FILE *fd, time_t the_time) { int c; int i; @@ -5491,8 +5335,7 @@ time_t the_time; * Return TRUE if string "s" contains a non-ASCII character (128 or higher). * When "s" is NULL FALSE is returned. */ -int has_non_ascii(s) -char_u *s; +int has_non_ascii(char_u *s) { char_u *p; diff --git a/src/move.c b/src/move.c index ed63dd212b..60547e4a94 100644 --- a/src/move.c +++ b/src/move.c @@ -42,8 +42,7 @@ static void max_topfill __ARGS((void)); * Compute wp->w_botline for the current wp->w_topline. Can be called after * wp->w_topline changed. */ -static void comp_botline(wp) -win_T *wp; +static void comp_botline(win_T *wp) { int n; linenr_T lnum; @@ -99,7 +98,7 @@ win_T *wp; * Update curwin->w_topline and redraw if necessary. * Used to update the screen before printing a message. */ -void update_topline_redraw() { +void update_topline_redraw(void) { update_topline(); if (must_redraw) update_screen(0); @@ -108,7 +107,7 @@ void update_topline_redraw() { /* * Update curwin->w_topline to move the cursor onto the screen. */ -void update_topline() { +void update_topline(void) { long line_count; int halfheight; int n; @@ -296,7 +295,7 @@ void update_topline() { * When 'scrolljump' is positive use it as-is. * When 'scrolljump' is negative use it as a percentage of the window height. */ -static int scrolljump_value() { +static int scrolljump_value(void) { if (p_sj >= 0) return (int)p_sj; return (curwin->w_height * -p_sj) / 100; @@ -306,7 +305,7 @@ static int scrolljump_value() { * Return TRUE when there are not 'scrolloff' lines above the cursor for the * current window. */ -static int check_top_offset() { +static int check_top_offset(void) { lineoff_T loff; int n; @@ -332,7 +331,7 @@ static int check_top_offset() { return FALSE; } -void update_curswant() { +void update_curswant(void) { if (curwin->w_set_curswant) { validate_virtcol(); curwin->w_curswant = curwin->w_virtcol; @@ -343,8 +342,7 @@ void update_curswant() { /* * Check if the cursor has moved. Set the w_valid flag accordingly. */ -void check_cursor_moved(wp) -win_T *wp; +void check_cursor_moved(win_T *wp) { if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL @@ -367,12 +365,11 @@ win_T *wp; * the cursor position, botline and topline to be recomputed and the window to * be redrawn. E.g, when changing the 'wrap' option or folding. */ -void changed_window_setting() { +void changed_window_setting(void) { changed_window_setting_win(curwin); } -void changed_window_setting_win(wp) -win_T *wp; +void changed_window_setting_win(win_T *wp) { wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); @@ -383,9 +380,7 @@ win_T *wp; /* * Set wp->w_topline to a certain number. */ -void set_topline(wp, lnum) -win_T *wp; -linenr_T lnum; +void set_topline(win_T *wp, linenr_T lnum) { /* go to first of folded lines */ (void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL); @@ -404,13 +399,12 @@ linenr_T lnum; * characters) has changed, and the change is before the cursor. * Need to take care of w_botline separately! */ -void changed_cline_bef_curs() { +void changed_cline_bef_curs(void) { curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL |VALID_CHEIGHT|VALID_TOPLINE); } -void changed_cline_bef_curs_win(wp) -win_T *wp; +void changed_cline_bef_curs_win(win_T *wp) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL |VALID_CHEIGHT|VALID_TOPLINE); @@ -421,13 +415,12 @@ win_T *wp; * the cursor have changed. * Need to take care of w_botline separately! */ -void changed_line_abv_curs() { +void changed_line_abv_curs(void) { curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW |VALID_CHEIGHT|VALID_TOPLINE); } -void changed_line_abv_curs_win(wp) -win_T *wp; +void changed_line_abv_curs_win(win_T *wp) { wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW |VALID_CHEIGHT|VALID_TOPLINE); @@ -436,7 +429,7 @@ win_T *wp; /* * Make sure the value of curwin->w_botline is valid. */ -void validate_botline() { +void validate_botline(void) { if (!(curwin->w_valid & VALID_BOTLINE)) comp_botline(curwin); } @@ -444,8 +437,7 @@ void validate_botline() { /* * Make sure the value of wp->w_botline is valid. */ -static void validate_botline_win(wp) -win_T *wp; +static void validate_botline_win(win_T *wp) { if (!(wp->w_valid & VALID_BOTLINE)) comp_botline(wp); @@ -454,18 +446,16 @@ win_T *wp; /* * Mark curwin->w_botline as invalid (because of some change in the buffer). */ -void invalidate_botline() { +void invalidate_botline(void) { curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); } -void invalidate_botline_win(wp) -win_T *wp; +void invalidate_botline_win(win_T *wp) { wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); } -void approximate_botline_win(wp) -win_T *wp; +void approximate_botline_win(win_T *wp) { wp->w_valid &= ~VALID_BOTLINE; } @@ -473,7 +463,7 @@ win_T *wp; /* * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid. */ -int cursor_valid() { +int cursor_valid(void) { check_cursor_moved(curwin); return (curwin->w_valid & (VALID_WROW|VALID_WCOL)) == (VALID_WROW|VALID_WCOL); @@ -483,7 +473,7 @@ int cursor_valid() { * Validate cursor position. Makes sure w_wrow and w_wcol are valid. * w_topline must be valid, you may need to call update_topline() first! */ -void validate_cursor() { +void validate_cursor(void) { check_cursor_moved(curwin); if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) curs_columns(TRUE); @@ -495,9 +485,11 @@ void validate_cursor() { * * Returns OK when cursor is in the window, FAIL when it isn't. */ -static void curs_rows(wp, do_botline) -win_T *wp; -int do_botline; /* also compute w_botline */ +static void +curs_rows ( + win_T *wp, + int do_botline /* also compute w_botline */ +) { linenr_T lnum; int i; @@ -585,15 +577,14 @@ int do_botline; /* also compute w_botline */ /* * Validate curwin->w_virtcol only. */ -void validate_virtcol() { +void validate_virtcol(void) { validate_virtcol_win(curwin); } /* * Validate wp->w_virtcol only. */ -void validate_virtcol_win(wp) -win_T *wp; +void validate_virtcol_win(win_T *wp) { check_cursor_moved(wp); if (!(wp->w_valid & VALID_VIRTCOL)) { @@ -609,7 +600,7 @@ win_T *wp; /* * Validate curwin->w_cline_height only. */ -static void validate_cheight() { +static void validate_cheight(void) { check_cursor_moved(curwin); if (!(curwin->w_valid & VALID_CHEIGHT)) { if (curwin->w_cursor.lnum == curwin->w_topline) @@ -625,7 +616,7 @@ static void validate_cheight() { /* * Validate w_wcol and w_virtcol only. */ -void validate_cursor_col() { +void validate_cursor_col(void) { colnr_T off; colnr_T col; int width; @@ -657,8 +648,7 @@ void validate_cursor_col() { * Compute offset of a window, occupied by absolute or relative line number, * fold column and sign column (these don't move when scrolling horizontally). */ -int win_col_off(wp) -win_T *wp; +int win_col_off(win_T *wp) { return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) + (cmdwin_type == 0 || wp != curwin ? 0 : 1) @@ -666,7 +656,7 @@ win_T *wp; ; } -int curwin_col_off() { +int curwin_col_off(void) { return win_col_off(curwin); } @@ -675,15 +665,14 @@ int curwin_col_off() { * wrapped line. It's 8 if 'number' or 'relativenumber' is on and 'n' is in * 'cpoptions'. */ -int win_col_off2(wp) -win_T *wp; +int win_col_off2(win_T *wp) { if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL) return number_width(wp) + 1; return 0; } -int curwin_col_off2() { +int curwin_col_off2(void) { return win_col_off2(curwin); } @@ -692,8 +681,10 @@ int curwin_col_off2() { * Also updates curwin->w_wrow and curwin->w_cline_row. * Also updates curwin->w_leftcol. */ -void curs_columns(may_scroll) -int may_scroll; /* when TRUE, may scroll horizontally */ +void +curs_columns ( + int may_scroll /* when TRUE, may scroll horizontally */ +) { int diff; int extra; /* offset for first screen line */ @@ -920,9 +911,11 @@ int may_scroll; /* when TRUE, may scroll horizontally */ /* * Scroll the current window down by "line_count" logical lines. "CTRL-Y" */ -void scrolldown(line_count, byfold) -long line_count; -int byfold UNUSED; /* TRUE: count a closed fold as one line */ +void +scrolldown ( + long line_count, + int byfold /* TRUE: count a closed fold as one line */ +) { long done = 0; /* total # of physical lines done */ int wrow; @@ -999,9 +992,11 @@ int byfold UNUSED; /* TRUE: count a closed fold as one line */ /* * Scroll the current window up by "line_count" logical lines. "CTRL-E" */ -void scrollup(line_count, byfold) -long line_count; -int byfold UNUSED; /* TRUE: count a closed fold as one line */ +void +scrollup ( + long line_count, + int byfold /* TRUE: count a closed fold as one line */ +) { linenr_T lnum; @@ -1055,9 +1050,11 @@ int byfold UNUSED; /* TRUE: count a closed fold as one line */ /* * Don't end up with too many filler lines in the window. */ -void check_topfill(wp, down) -win_T *wp; -int down; /* when TRUE scroll down when not enough space */ +void +check_topfill ( + win_T *wp, + int down /* when TRUE scroll down when not enough space */ +) { int n; @@ -1080,7 +1077,7 @@ int down; /* when TRUE scroll down when not enough space */ * Use as many filler lines as possible for w_topline. Make sure w_topline * is still visible. */ -static void max_topfill() { +static void max_topfill(void) { int n; n = plines_nofill(curwin->w_topline); @@ -1097,7 +1094,7 @@ static void max_topfill() { * Scroll the screen one line down, but don't do it if it would move the * cursor off the screen. */ -void scrolldown_clamp() { +void scrolldown_clamp(void) { int end_row; int can_fill = (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline)); @@ -1145,7 +1142,7 @@ void scrolldown_clamp() { * Scroll the screen one line up, but don't do it if it would move the cursor * off the screen. */ -void scrollup_clamp() { +void scrollup_clamp(void) { int start_row; if (curwin->w_topline == curbuf->b_ml.ml_line_count @@ -1186,8 +1183,7 @@ void scrollup_clamp() { * Returns the height of the added line in "lp->height". * Lines above the first one are incredibly high: MAXCOL. */ -static void topline_back(lp) -lineoff_T *lp; +static void topline_back(lineoff_T *lp) { if (lp->fill < diff_check_fill(curwin, lp->lnum)) { /* Add a filler line. */ @@ -1213,8 +1209,7 @@ lineoff_T *lp; * Returns the height of the added line in "lp->height". * Lines below the last one are incredibly high. */ -static void botline_forw(lp) -lineoff_T *lp; +static void botline_forw(lineoff_T *lp) { if (lp->fill < diff_check_fill(curwin, lp->lnum + 1)) { /* Add a filler line. */ @@ -1239,8 +1234,7 @@ lineoff_T *lp; * lines above loff.lnum + 1. This keeps pointing to the same line. * When there are no filler lines nothing changes. */ -static void botline_topline(lp) -lineoff_T *lp; +static void botline_topline(lineoff_T *lp) { if (lp->fill > 0) { ++lp->lnum; @@ -1253,8 +1247,7 @@ lineoff_T *lp; * lines below loff.lnum - 1. This keeps pointing to the same line. * When there are no filler lines nothing changes. */ -static void topline_botline(lp) -lineoff_T *lp; +static void topline_botline(lineoff_T *lp) { if (lp->fill > 0) { lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1; @@ -1267,9 +1260,7 @@ lineoff_T *lp; * Scroll at least "min_scroll" lines. * If "always" is TRUE, always set topline (for "zt"). */ -void scroll_cursor_top(min_scroll, always) -int min_scroll; -int always; +void scroll_cursor_top(int min_scroll, int always) { int scrolled = 0; int extra = 0; @@ -1383,9 +1374,7 @@ int always; * Set w_empty_rows and w_filler_rows for window "wp", having used up "used" * screen lines for text lines. */ -void set_empty_rows(wp, used) -win_T *wp; -int used; +void set_empty_rows(win_T *wp, int used) { wp->w_filler_rows = 0; if (used == 0) @@ -1410,9 +1399,7 @@ int used; * If "set_topbot" is TRUE, set topline and botline first (for "zb"). * This is messy stuff!!! */ -void scroll_cursor_bot(min_scroll, set_topbot) -int min_scroll; -int set_topbot; +void scroll_cursor_bot(int min_scroll, int set_topbot) { int used; int scrolled = 0; @@ -1586,8 +1573,7 @@ int set_topbot; * Recompute topline to put the cursor halfway the window * If "atend" is TRUE, also put it halfway at the end of the file. */ -void scroll_cursor_halfway(atend) -int atend; +void scroll_cursor_halfway(int atend) { int above = 0; linenr_T topline; @@ -1645,7 +1631,7 @@ int atend; * If not possible, put it at the same position as scroll_cursor_halfway(). * When called topline must be valid! */ -void cursor_correct() { +void cursor_correct(void) { int above = 0; /* screen lines above topline */ linenr_T topline; int below = 0; /* screen lines below botline */ @@ -1748,9 +1734,7 @@ static void get_scroll_overlap __ARGS((lineoff_T *lp, int dir)); * * return FAIL for failure, OK otherwise */ -int onepage(dir, count) -int dir; -long count; +int onepage(int dir, long count) { long n; int retval = OK; @@ -1936,9 +1920,7 @@ long count; * ------------- l3 second text line * l3 etc. */ -static void get_scroll_overlap(lp, dir) -lineoff_T *lp; -int dir; +static void get_scroll_overlap(lineoff_T *lp, int dir) { int h1, h2, h3, h4; int min_height = curwin->w_height - 2; @@ -1991,9 +1973,7 @@ int dir; /* * Scroll 'scroll' lines up or down. */ -void halfpage(flag, Prenum) -int flag; -linenr_T Prenum; +void halfpage(int flag, linenr_T Prenum) { long scrolled = 0; int i; @@ -2153,7 +2133,7 @@ linenr_T Prenum; redraw_later(VALID); } -void do_check_cursorbind() { +void do_check_cursorbind(void) { linenr_T line = curwin->w_cursor.lnum; colnr_T col = curwin->w_cursor.col; colnr_T coladd = curwin->w_cursor.coladd; diff --git a/src/normal.c b/src/normal.c index c141f468b2..2a8327a451 100644 --- a/src/normal.c +++ b/src/normal.c @@ -384,9 +384,7 @@ static int nv_max_linear; * Compare functions for qsort() below, that checks the command character * through the index in nv_cmd_idx[]. */ -static int nv_compare(s1, s2) -const void *s1; -const void *s2; +static int nv_compare(const void *s1, const void *s2) { int c1, c2; @@ -403,7 +401,7 @@ const void *s2; /* * Initialize the nv_cmd_idx[] table. */ -void init_normal_cmds() { +void init_normal_cmds(void) { int i; /* Fill the index table with a one to one relation. */ @@ -424,8 +422,7 @@ void init_normal_cmds() { * Search for a command in the commands table. * Returns -1 for invalid command. */ -static int find_command(cmdchar) -int cmdchar; +static int find_command(int cmdchar) { int i; int idx; @@ -470,9 +467,11 @@ int cmdchar; /* * Execute a command in Normal mode. */ -void normal_cmd(oap, toplevel) -oparg_T *oap; -int toplevel UNUSED; /* TRUE when called from main() */ +void +normal_cmd ( + oparg_T *oap, + int toplevel /* TRUE when called from main() */ +) { cmdarg_T ca; /* command arguments */ int c; @@ -1140,9 +1139,7 @@ normal_end: * Set v:count and v:count1 according to "cap". * Set v:prevcount only when "set_prevcount" is TRUE. */ -static void set_vcount_ca(cap, set_prevcount) -cmdarg_T *cap; -int *set_prevcount; +static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount) { long count = cap->count0; @@ -1156,10 +1153,7 @@ int *set_prevcount; /* * Handle an operator after visual mode or when the movement is finished */ -void do_pending_operator(cap, old_col, gui_yank) -cmdarg_T *cap; -int old_col; -int gui_yank; +void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) { oparg_T *oap = cap->oap; pos_T old_cursor; @@ -1782,8 +1776,7 @@ int gui_yank; /* * Handle indent and format operators and visual mode ":". */ -static void op_colon(oap) -oparg_T *oap; +static void op_colon(oparg_T *oap) { stuffcharReadbuff(':'); if (oap->is_VIsual) @@ -1830,8 +1823,7 @@ oparg_T *oap; /* * Handle the "g@" operator: call 'operatorfunc'. */ -static void op_function(oap) -oparg_T *oap UNUSED; +static void op_function(oparg_T *oap) { char_u *(argv[1]); int save_virtual_op = virtual_op; @@ -1899,12 +1891,14 @@ oparg_T *oap UNUSED; * * Return TRUE if start_arrow() should be called for edit mode. */ -int do_mouse(oap, c, dir, count, fixindent) -oparg_T *oap; /* operator argument, can be NULL */ -int c; /* K_LEFTMOUSE, etc */ -int dir; /* Direction to 'put' if necessary */ -long count; -int fixindent; /* PUT_FIXINDENT if fixing indent necessary */ +int +do_mouse ( + oparg_T *oap, /* operator argument, can be NULL */ + int c, /* K_LEFTMOUSE, etc */ + int dir, /* Direction to 'put' if necessary */ + long count, + int fixindent /* PUT_FIXINDENT if fixing indent necessary */ +) { static int do_always = FALSE; /* ignore 'mouse' setting next time */ static int got_click = FALSE; /* got a click some time back */ @@ -2574,8 +2568,7 @@ int fixindent; /* PUT_FIXINDENT if fixing indent necessary */ /* * Move "pos" back to the start of the word it's in. */ -static void find_start_of_word(pos) -pos_T *pos; +static void find_start_of_word(pos_T *pos) { char_u *line; int cclass; @@ -2597,8 +2590,7 @@ pos_T *pos; * Move "pos" forward to the end of the word it's in. * When 'selection' is "exclusive", the position is just after the word. */ -static void find_end_of_word(pos) -pos_T *pos; +static void find_end_of_word(pos_T *pos) { char_u *line; int cclass; @@ -2628,8 +2620,7 @@ pos_T *pos; * 2: normal word character * >2: multi-byte word character. */ -static int get_mouse_class(p) -char_u *p; +static int get_mouse_class(char_u *p) { int c; @@ -2658,7 +2649,7 @@ char_u *p; * Check if highlighting for visual mode is possible, give a warning message * if not. */ -void check_visual_highlight() { +void check_visual_highlight(void) { static int did_check = FALSE; if (full_screen) { @@ -2673,7 +2664,7 @@ void check_visual_highlight() { * This function should ALWAYS be called to end Visual mode, except from * do_pending_operator(). */ -void end_visual_mode() { +void end_visual_mode(void) { VIsual_active = FALSE; setmouse(); @@ -2699,7 +2690,7 @@ void end_visual_mode() { /* * Reset VIsual_active and VIsual_reselect. */ -void reset_VIsual_and_resel() { +void reset_VIsual_and_resel(void) { if (VIsual_active) { end_visual_mode(); redraw_curbuf_later(INVERTED); /* delete the inversion later */ @@ -2710,7 +2701,7 @@ void reset_VIsual_and_resel() { /* * Reset VIsual_active and VIsual_reselect if it's set. */ -void reset_VIsual() { +void reset_VIsual(void) { if (VIsual_active) { end_visual_mode(); redraw_curbuf_later(INVERTED); /* delete the inversion later */ @@ -2739,9 +2730,7 @@ void reset_VIsual() { * If a string is found, a pointer to the string is put in "*string". This * string is not always NUL terminated. */ -int find_ident_under_cursor(string, find_type) -char_u **string; -int find_type; +int find_ident_under_cursor(char_u **string, int find_type) { return find_ident_at_pos(curwin, curwin->w_cursor.lnum, curwin->w_cursor.col, string, find_type); @@ -2751,12 +2740,7 @@ int find_type; * Like find_ident_under_cursor(), but for any window and any position. * However: Uses 'iskeyword' from the current window!. */ -int find_ident_at_pos(wp, lnum, startcol, string, find_type) -win_T *wp; -linenr_T lnum; -colnr_T startcol; -char_u **string; -int find_type; +int find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **string, int find_type) { char_u *ptr; int col = 0; /* init to shut up GCC */ @@ -2870,8 +2854,7 @@ int find_type; /* * Prepare for redo of a normal command. */ -static void prep_redo_cmd(cap) -cmdarg_T *cap; +static void prep_redo_cmd(cmdarg_T *cap) { prep_redo(cap->oap->regname, cap->count0, NUL, cap->cmdchar, NUL, NUL, cap->nchar); @@ -2881,14 +2864,7 @@ cmdarg_T *cap; * Prepare for redo of any command. * Note that only the last argument can be a multi-byte char. */ -static void prep_redo(regname, num, cmd1, cmd2, cmd3, cmd4, cmd5) -int regname; -long num; -int cmd1; -int cmd2; -int cmd3; -int cmd4; -int cmd5; +static void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5) { ResetRedobuff(); if (regname != 0) { /* yank from specified buffer */ @@ -2915,8 +2891,7 @@ int cmd5; * * return TRUE if operator was active */ -static int checkclearop(oap) -oparg_T *oap; +static int checkclearop(oparg_T *oap) { if (oap->op_type == OP_NOP) return FALSE; @@ -2929,8 +2904,7 @@ oparg_T *oap; * * Return TRUE if operator or Visual was active. */ -static int checkclearopq(oap) -oparg_T *oap; +static int checkclearopq(oparg_T *oap) { if (oap->op_type == OP_NOP && !VIsual_active @@ -2940,8 +2914,7 @@ oparg_T *oap; return TRUE; } -static void clearop(oap) -oparg_T *oap; +static void clearop(oparg_T *oap) { oap->op_type = OP_NOP; oap->regname = 0; @@ -2949,8 +2922,7 @@ oparg_T *oap; oap->use_reg_one = FALSE; } -static void clearopbeep(oap) -oparg_T *oap; +static void clearopbeep(oparg_T *oap) { clearop(oap); beep_flush(); @@ -2959,8 +2931,7 @@ oparg_T *oap; /* * Remove the shift modifier from a special key. */ -static void unshift_special(cap) -cmdarg_T *cap; +static void unshift_special(cmdarg_T *cap) { switch (cap->cmdchar) { case K_S_RIGHT: cap->cmdchar = K_RIGHT; break; @@ -2985,7 +2956,7 @@ static int showcmd_visual = FALSE; static void display_showcmd __ARGS((void)); -void clear_showcmd() { +void clear_showcmd(void) { if (!p_sc) return; @@ -3066,8 +3037,7 @@ void clear_showcmd() { * Add 'c' to string of shown command chars. * Return TRUE if output has been written (and setcursor() has been called). */ -int add_to_showcmd(c) -int c; +int add_to_showcmd(int c) { char_u *p; int old_len; @@ -3119,8 +3089,7 @@ int c; return TRUE; } -void add_to_showcmd_c(c) -int c; +void add_to_showcmd_c(int c) { if (!add_to_showcmd(c)) setcursor(); @@ -3129,8 +3098,7 @@ int c; /* * Delete 'len' characters from the end of the shown command. */ -static void del_from_showcmd(len) -int len; +static void del_from_showcmd(int len) { int old_len; @@ -3150,12 +3118,12 @@ int len; * push_showcmd() and pop_showcmd() are used when waiting for the user to type * something and there is a partial mapping. */ -void push_showcmd() { +void push_showcmd(void) { if (p_sc) STRCPY(old_showcmd_buf, showcmd_buf); } -void pop_showcmd() { +void pop_showcmd(void) { if (!p_sc) return; @@ -3164,7 +3132,7 @@ void pop_showcmd() { display_showcmd(); } -static void display_showcmd() { +static void display_showcmd(void) { int len; cursor_off(); @@ -3191,8 +3159,7 @@ static void display_showcmd() { * When "check" is TRUE, take care of scroll-binding after the window has * scrolled. Called from normal_cmd() and edit(). */ -void do_check_scrollbind(check) -int check; +void do_check_scrollbind(int check) { static win_T *old_curwin = NULL; static linenr_T old_topline = 0; @@ -3248,9 +3215,7 @@ int check; * number of rows by which the current window has changed * (1998-11-02 16:21:01 R. Edward Ralston ) */ -void check_scrollbind(topline_diff, leftcol_diff) -linenr_T topline_diff; -long leftcol_diff; +void check_scrollbind(linenr_T topline_diff, long leftcol_diff) { int want_ver; int want_hor; @@ -3327,8 +3292,7 @@ long leftcol_diff; * Used for CTRL-Q and CTRL-S to avoid problems with terminals that use * xon/xoff. */ -static void nv_ignore(cap) -cmdarg_T *cap; +static void nv_ignore(cmdarg_T *cap) { cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */ } @@ -3337,16 +3301,14 @@ cmdarg_T *cap; * Command character that doesn't do anything, but unlike nv_ignore() does * start edit(). Used for "startinsert" executed while starting up. */ -static void nv_nop(cap) -cmdarg_T *cap UNUSED; +static void nv_nop(cmdarg_T *cap) { } /* * Command character doesn't exist. */ -static void nv_error(cap) -cmdarg_T *cap; +static void nv_error(cmdarg_T *cap) { clearopbeep(cap->oap); } @@ -3354,8 +3316,7 @@ cmdarg_T *cap; /* * and commands. */ -static void nv_help(cap) -cmdarg_T *cap; +static void nv_help(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) ex_help(NULL); @@ -3364,8 +3325,7 @@ cmdarg_T *cap; /* * CTRL-A and CTRL-X: Add or subtract from letter or number under cursor. */ -static void nv_addsub(cap) -cmdarg_T *cap; +static void nv_addsub(cmdarg_T *cap) { if (!checkclearopq(cap->oap) && do_addsub((int)cap->cmdchar, cap->count1) == OK) @@ -3375,8 +3335,7 @@ cmdarg_T *cap; /* * CTRL-F, CTRL-B, etc: Scroll page up or down. */ -static void nv_page(cap) -cmdarg_T *cap; +static void nv_page(cmdarg_T *cap) { if (!checkclearop(cap->oap)) { if (mod_mask & MOD_MASK_CTRL) { @@ -3393,10 +3352,12 @@ cmdarg_T *cap; /* * Implementation of "gd" and "gD" command. */ -static void nv_gd(oap, nchar, thisblock) -oparg_T *oap; -int nchar; -int thisblock; /* 1 for "1gd" and "1gD" */ +static void +nv_gd ( + oparg_T *oap, + int nchar, + int thisblock /* 1 for "1gd" and "1gD" */ +) { int len; char_u *ptr; @@ -3415,12 +3376,14 @@ int thisblock; /* 1 for "1gd" and "1gD" */ * When "thisblock" is TRUE check the {} block scope. * Return FAIL when not found. */ -int find_decl(ptr, len, locally, thisblock, searchflags) -char_u *ptr; -int len; -int locally; -int thisblock; -int searchflags; /* flags passed to searchit() */ +int +find_decl ( + char_u *ptr, + int len, + int locally, + int thisblock, + int searchflags /* flags passed to searchit() */ +) { char_u *pat; pos_T old_pos; @@ -3532,10 +3495,7 @@ int searchflags; /* flags passed to searchit() */ * * Return OK if able to move cursor, FAIL otherwise. */ -static int nv_screengo(oap, dir, dist) -oparg_T *oap; -int dir; -long dist; +static int nv_screengo(oparg_T *oap, int dir, long dist) { int linelen = linetabsize(ml_get_curline()); int retval = OK; @@ -3660,8 +3620,7 @@ long dist; * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2) */ -static void nv_mousescroll(cap) -cmdarg_T *cap; +static void nv_mousescroll(cmdarg_T *cap) { win_T *old_curwin = curwin; @@ -3695,8 +3654,7 @@ cmdarg_T *cap; /* * Mouse clicks and drags. */ -static void nv_mouse(cap) -cmdarg_T *cap; +static void nv_mouse(cmdarg_T *cap) { (void)do_mouse(cap->oap, cap->cmdchar, BACKWARD, cap->count1, 0); } @@ -3705,8 +3663,7 @@ cmdarg_T *cap; * Handle CTRL-E and CTRL-Y commands: scroll a line up or down. * cap->arg must be TRUE for CTRL-E. */ -static void nv_scroll_line(cap) -cmdarg_T *cap; +static void nv_scroll_line(cmdarg_T *cap) { if (!checkclearop(cap->oap)) scroll_redraw(cap->arg, cap->count1); @@ -3715,9 +3672,7 @@ cmdarg_T *cap; /* * Scroll "count" lines up or down, and redraw. */ -void scroll_redraw(up, count) -int up; -long count; +void scroll_redraw(int up, long count) { linenr_T prev_topline = curwin->w_topline; int prev_topfill = curwin->w_topfill; @@ -3764,8 +3719,7 @@ long count; /* * Commands that start with "z". */ -static void nv_zet(cap) -cmdarg_T *cap; +static void nv_zet(cmdarg_T *cap) { long n; colnr_T col; @@ -4191,8 +4145,7 @@ dozet: /* * "Q" command. */ -static void nv_exmode(cap) -cmdarg_T *cap; +static void nv_exmode(cmdarg_T *cap) { /* * Ignore 'Q' in Visual mode, just give a beep. @@ -4206,8 +4159,7 @@ cmdarg_T *cap; /* * Handle a ":" command. */ -static void nv_colon(cap) -cmdarg_T *cap; +static void nv_colon(cmdarg_T *cap) { int old_p_im; int cmd_result; @@ -4264,8 +4216,7 @@ cmdarg_T *cap; /* * Handle CTRL-G command. */ -static void nv_ctrlg(cap) -cmdarg_T *cap; +static void nv_ctrlg(cmdarg_T *cap) { if (VIsual_active) { /* toggle Selection/Visual mode */ VIsual_select = !VIsual_select; @@ -4278,8 +4229,7 @@ cmdarg_T *cap; /* * Handle CTRL-H command. */ -static void nv_ctrlh(cap) -cmdarg_T *cap; +static void nv_ctrlh(cmdarg_T *cap) { if (VIsual_active && VIsual_select) { cap->cmdchar = 'x'; /* BS key behaves like 'x' in Select mode */ @@ -4291,8 +4241,7 @@ cmdarg_T *cap; /* * CTRL-L: clear screen and redraw. */ -static void nv_clear(cap) -cmdarg_T *cap; +static void nv_clear(cmdarg_T *cap) { if (!checkclearop(cap->oap)) { /* Clear all syntax states to force resyncing. */ @@ -4305,8 +4254,7 @@ cmdarg_T *cap; * CTRL-O: In Select mode: switch to Visual mode for one command. * Otherwise: Go to older pcmark. */ -static void nv_ctrlo(cap) -cmdarg_T *cap; +static void nv_ctrlo(cmdarg_T *cap) { if (VIsual_active && VIsual_select) { VIsual_select = FALSE; @@ -4321,8 +4269,7 @@ cmdarg_T *cap; /* * CTRL-^ command, short for ":e #" */ -static void nv_hat(cap) -cmdarg_T *cap; +static void nv_hat(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) (void)buflist_getfile((int)cap->count0, (linenr_T)0, @@ -4332,8 +4279,7 @@ cmdarg_T *cap; /* * "Z" commands. */ -static void nv_Zet(cap) -cmdarg_T *cap; +static void nv_Zet(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { switch (cap->nchar) { @@ -4353,9 +4299,7 @@ cmdarg_T *cap; /* * Call nv_ident() as if "c1" was used, with "c2" as next character. */ -void do_nv_ident(c1, c2) -int c1; -int c2; +void do_nv_ident(int c1, int c2) { oparg_T oa; cmdarg_T ca; @@ -4376,8 +4320,7 @@ int c2; * [g] '#' ? to current identifier or string * g ']' :tselect for current identifier */ -static void nv_ident(cap) -cmdarg_T *cap; +static void nv_ident(cmdarg_T *cap) { char_u *ptr = NULL; char_u *buf; @@ -4581,10 +4524,12 @@ cmdarg_T *cap; * Get visually selected text, within one line only. * Returns FAIL if more than one line selected. */ -int get_visual_text(cap, pp, lenp) -cmdarg_T *cap; -char_u **pp; /* return: start of selected text */ -int *lenp; /* return: length of selected text */ +int +get_visual_text ( + cmdarg_T *cap, + char_u **pp, /* return: start of selected text */ + int *lenp /* return: length of selected text */ +) { if (VIsual_mode != 'V') unadjust_for_sel(); @@ -4615,8 +4560,7 @@ int *lenp; /* return: length of selected text */ /* * CTRL-T: backwards in tag stack */ -static void nv_tagpop(cap) -cmdarg_T *cap; +static void nv_tagpop(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) do_tag((char_u *)"", DT_POP, (int)cap->count1, FALSE, TRUE); @@ -4625,8 +4569,7 @@ cmdarg_T *cap; /* * Handle scrolling command 'H', 'L' and 'M'. */ -static void nv_scroll(cap) -cmdarg_T *cap; +static void nv_scroll(cmdarg_T *cap) { int used = 0; long n; @@ -4700,8 +4643,7 @@ cmdarg_T *cap; /* * Cursor right commands. */ -static void nv_right(cap) -cmdarg_T *cap; +static void nv_right(cmdarg_T *cap) { long n; int PAST_LINE; @@ -4789,8 +4731,7 @@ cmdarg_T *cap; * * Returns TRUE when operator end should not be adjusted. */ -static void nv_left(cap) -cmdarg_T *cap; +static void nv_left(cmdarg_T *cap) { long n; @@ -4850,8 +4791,7 @@ cmdarg_T *cap; * Cursor up commands. * cap->arg is TRUE for "-": Move cursor to first non-blank. */ -static void nv_up(cap) -cmdarg_T *cap; +static void nv_up(cmdarg_T *cap) { if (mod_mask & MOD_MASK_SHIFT) { /* is page up */ @@ -4870,8 +4810,7 @@ cmdarg_T *cap; * Cursor down commands. * cap->arg is TRUE for CR and "+": Move cursor to first non-blank. */ -static void nv_down(cap) -cmdarg_T *cap; +static void nv_down(cmdarg_T *cap) { if (mod_mask & MOD_MASK_SHIFT) { /* is page down */ @@ -4901,8 +4840,7 @@ cmdarg_T *cap; /* * Grab the file name under the cursor and edit it. */ -static void nv_gotofile(cap) -cmdarg_T *cap; +static void nv_gotofile(cmdarg_T *cap) { char_u *ptr; linenr_T lnum = -1; @@ -4939,8 +4877,7 @@ cmdarg_T *cap; /* * command: to end of current line or last line. */ -static void nv_end(cap) -cmdarg_T *cap; +static void nv_end(cmdarg_T *cap) { if (cap->arg || (mod_mask & MOD_MASK_CTRL)) { /* CTRL-END = goto last line */ cap->arg = TRUE; @@ -4953,8 +4890,7 @@ cmdarg_T *cap; /* * Handle the "$" command. */ -static void nv_dollar(cap) -cmdarg_T *cap; +static void nv_dollar(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->inclusive = TRUE; @@ -4975,8 +4911,7 @@ cmdarg_T *cap; * Implementation of '?' and '/' commands. * If cap->arg is TRUE don't set PC mark. */ -static void nv_search(cap) -cmdarg_T *cap; +static void nv_search(cmdarg_T *cap) { oparg_T *oap = cap->oap; @@ -5003,8 +4938,7 @@ cmdarg_T *cap; * Handle "N" and "n" commands. * cap->arg is SEARCH_REV for "N", 0 for "n". */ -static void nv_next(cap) -cmdarg_T *cap; +static void nv_next(cmdarg_T *cap) { normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg); } @@ -5013,11 +4947,13 @@ cmdarg_T *cap; * Search for "pat" in direction "dir" ('/' or '?', 0 for repeat). * Uses only cap->count1 and cap->oap from "cap". */ -static void normal_search(cap, dir, pat, opt) -cmdarg_T *cap; -int dir; -char_u *pat; -int opt; /* extra flags for do_search() */ +static void +normal_search ( + cmdarg_T *cap, + int dir, + char_u *pat, + int opt /* extra flags for do_search() */ +) { int i; @@ -5049,8 +4985,7 @@ int opt; /* extra flags for do_search() */ * ',' and FALSE for ';'. * cap->nchar is NUL for ',' and ';' (repeat the search) */ -static void nv_csearch(cap) -cmdarg_T *cap; +static void nv_csearch(cmdarg_T *cap) { int t_cmd; @@ -5083,8 +5018,7 @@ cmdarg_T *cap; * "[" and "]" commands. * cap->arg is BACKWARD for "[" and FORWARD for "]". */ -static void nv_brackets(cap) -cmdarg_T *cap; +static void nv_brackets(cmdarg_T *cap) { pos_T new_pos = INIT_POS_T(0, 0, 0); pos_T prev_pos; @@ -5342,8 +5276,7 @@ cmdarg_T *cap; /* * Handle Normal mode "%" command. */ -static void nv_percent(cap) -cmdarg_T *cap; +static void nv_percent(cmdarg_T *cap) { pos_T *pos; linenr_T lnum = curwin->w_cursor.lnum; @@ -5391,8 +5324,7 @@ cmdarg_T *cap; * Handle "(" and ")" commands. * cap->arg is BACKWARD for "(" and FORWARD for ")". */ -static void nv_brace(cap) -cmdarg_T *cap; +static void nv_brace(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->use_reg_one = TRUE; @@ -5414,8 +5346,7 @@ cmdarg_T *cap; /* * "m" command: Mark a position. */ -static void nv_mark(cap) -cmdarg_T *cap; +static void nv_mark(cmdarg_T *cap) { if (!checkclearop(cap->oap)) { if (setmark(cap->nchar) == FAIL) @@ -5427,8 +5358,7 @@ cmdarg_T *cap; * "{" and "}" commands. * cmd->arg is BACKWARD for "{" and FORWARD for "}". */ -static void nv_findpar(cap) -cmdarg_T *cap; +static void nv_findpar(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; @@ -5446,8 +5376,7 @@ cmdarg_T *cap; /* * "u" command: Undo or make lower case. */ -static void nv_undo(cap) -cmdarg_T *cap; +static void nv_undo(cmdarg_T *cap) { if (cap->oap->op_type == OP_LOWER || VIsual_active @@ -5463,8 +5392,7 @@ cmdarg_T *cap; /* * command. */ -static void nv_kundo(cap) -cmdarg_T *cap; +static void nv_kundo(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { u_undo((int)cap->count1); @@ -5475,8 +5403,7 @@ cmdarg_T *cap; /* * Handle the "r" command. */ -static void nv_replace(cap) -cmdarg_T *cap; +static void nv_replace(cmdarg_T *cap) { char_u *ptr; int had_ctrl_v; @@ -5646,8 +5573,7 @@ cmdarg_T *cap; * 'o': Exchange start and end of Visual area. * 'O': same, but in block mode exchange left and right corners. */ -static void v_swap_corners(cmdchar) -int cmdchar; +static void v_swap_corners(int cmdchar) { pos_T old_cursor; colnr_T left, right; @@ -5691,8 +5617,7 @@ int cmdchar; /* * "R" (cap->arg is FALSE) and "gR" (cap->arg is TRUE). */ -static void nv_Replace(cap) -cmdarg_T *cap; +static void nv_Replace(cmdarg_T *cap) { if (VIsual_active) { /* "R" is replace lines */ cap->cmdchar = 'c'; @@ -5714,8 +5639,7 @@ cmdarg_T *cap; /* * "gr". */ -static void nv_vreplace(cap) -cmdarg_T *cap; +static void nv_vreplace(cmdarg_T *cap) { if (VIsual_active) { cap->cmdchar = 'r'; @@ -5739,8 +5663,7 @@ cmdarg_T *cap; /* * Swap case for "~" command, when it does not work like an operator. */ -static void n_swapchar(cap) -cmdarg_T *cap; +static void n_swapchar(cmdarg_T *cap) { long n; pos_T startpos; @@ -5794,10 +5717,7 @@ cmdarg_T *cap; /* * Move cursor to mark. */ -static void nv_cursormark(cap, flag, pos) -cmdarg_T *cap; -int flag; -pos_T *pos; +static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos) { if (check_mark(pos) == FAIL) clearop(cap->oap); @@ -5823,8 +5743,7 @@ pos_T *pos; /* * Handle commands that are operators in Visual mode. */ -static void v_visop(cap) -cmdarg_T *cap; +static void v_visop(cmdarg_T *cap) { static char_u trans[] = "YyDdCcxdXdAAIIrr"; @@ -5844,8 +5763,7 @@ cmdarg_T *cap; /* * "s" and "S" commands. */ -static void nv_subst(cap) -cmdarg_T *cap; +static void nv_subst(cmdarg_T *cap) { if (VIsual_active) { /* "vs" and "vS" are the same as "vc" */ if (cap->cmdchar == 'S') { @@ -5861,8 +5779,7 @@ cmdarg_T *cap; /* * Abbreviated commands. */ -static void nv_abbrev(cap) -cmdarg_T *cap; +static void nv_abbrev(cmdarg_T *cap) { if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL) cap->cmdchar = 'x'; /* DEL key behaves like 'x' */ @@ -5877,8 +5794,7 @@ cmdarg_T *cap; /* * Translate a command into another command. */ -static void nv_optrans(cap) -cmdarg_T *cap; +static void nv_optrans(cmdarg_T *cap) { static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh", (char_u *)"d$", (char_u *)"c$", @@ -5911,8 +5827,7 @@ cmdarg_T *cap; * "'" and "`" commands. Also for "g'" and "g`". * cap->arg is TRUE for "'" and "g'". */ -static void nv_gomark(cap) -cmdarg_T *cap; +static void nv_gomark(cmdarg_T *cap) { pos_T *pos; int c; @@ -5947,8 +5862,7 @@ cmdarg_T *cap; /* * Handle CTRL-O, CTRL-I, "g;" and "g," commands. */ -static void nv_pcmark(cap) -cmdarg_T *cap; +static void nv_pcmark(cmdarg_T *cap) { pos_T *pos; linenr_T lnum = curwin->w_cursor.lnum; @@ -5984,8 +5898,7 @@ cmdarg_T *cap; /* * Handle '"' command. */ -static void nv_regname(cap) -cmdarg_T *cap; +static void nv_regname(cmdarg_T *cap) { if (checkclearop(cap->oap)) return; @@ -6005,8 +5918,7 @@ cmdarg_T *cap; * is TRUE. * Handle CTRL-Q just like CTRL-V. */ -static void nv_visual(cap) -cmdarg_T *cap; +static void nv_visual(cmdarg_T *cap) { if (cap->cmdchar == Ctrl_Q) cap->cmdchar = Ctrl_V; @@ -6095,7 +6007,7 @@ cmdarg_T *cap; /* * Start selection for Shift-movement keys. */ -void start_selection() { +void start_selection(void) { /* if 'selectmode' contains "key", start Select mode */ may_start_select('k'); n_start_visual_mode('v'); @@ -6104,8 +6016,7 @@ void start_selection() { /* * Start Select mode, if "c" is in 'selectmode' and not in a mapping or menu. */ -void may_start_select(c) -int c; +void may_start_select(int c) { VIsual_select = (stuff_empty() && typebuf_typed() && (vim_strchr(p_slm, c) != NULL)); @@ -6115,8 +6026,7 @@ int c; * Start Visual mode "c". * Should set VIsual_select before calling this. */ -static void n_start_visual_mode(c) -int c; +static void n_start_visual_mode(int c) { /* Check for redraw before changing the state. */ conceal_check_cursur_line(); @@ -6154,8 +6064,7 @@ int c; /* * CTRL-W: Window commands */ -static void nv_window(cap) -cmdarg_T *cap; +static void nv_window(cmdarg_T *cap) { if (!checkclearop(cap->oap)) do_window(cap->nchar, cap->count0, NUL); /* everything is in window.c */ @@ -6164,8 +6073,7 @@ cmdarg_T *cap; /* * CTRL-Z: Suspend */ -static void nv_suspend(cap) -cmdarg_T *cap; +static void nv_suspend(cmdarg_T *cap) { clearop(cap->oap); if (VIsual_active) @@ -6176,8 +6084,7 @@ cmdarg_T *cap; /* * Commands starting with "g". */ -static void nv_g_cmd(cap) -cmdarg_T *cap; +static void nv_g_cmd(cmdarg_T *cap) { oparg_T *oap = cap->oap; pos_T tpos; @@ -6692,8 +6599,7 @@ cmdarg_T *cap; /* * Handle "o" and "O" commands. */ -static void n_opencmd(cap) -cmdarg_T *cap; +static void n_opencmd(cmdarg_T *cap) { linenr_T oldline = curwin->w_cursor.lnum; @@ -6727,8 +6633,7 @@ cmdarg_T *cap; /* * "." command: redo last change. */ -static void nv_dot(cap) -cmdarg_T *cap; +static void nv_dot(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { /* @@ -6744,8 +6649,7 @@ cmdarg_T *cap; /* * CTRL-R: undo undo */ -static void nv_redo(cap) -cmdarg_T *cap; +static void nv_redo(cmdarg_T *cap) { if (!checkclearopq(cap->oap)) { u_redo((int)cap->count1); @@ -6756,8 +6660,7 @@ cmdarg_T *cap; /* * Handle "U" command. */ -static void nv_Undo(cap) -cmdarg_T *cap; +static void nv_Undo(cmdarg_T *cap) { /* In Visual mode and typing "gUU" triggers an operator */ if (cap->oap->op_type == OP_UPPER @@ -6777,8 +6680,7 @@ cmdarg_T *cap; * '~' command: If tilde is not an operator and Visual is off: swap case of a * single character. */ -static void nv_tilde(cap) -cmdarg_T *cap; +static void nv_tilde(cmdarg_T *cap) { if (!p_to && !VIsual_active @@ -6792,8 +6694,7 @@ cmdarg_T *cap; * Handle an operator command. * The actual work is done by do_pending_operator(). */ -static void nv_operator(cap) -cmdarg_T *cap; +static void nv_operator(cmdarg_T *cap) { int op_type; @@ -6811,8 +6712,7 @@ cmdarg_T *cap; /* * Set v:operator to the characters for "optype". */ -static void set_op_var(optype) -int optype; +static void set_op_var(int optype) { char_u opchars[3]; @@ -6835,8 +6735,7 @@ int optype; * are really an alternate form of "d_" and "y_". It does accept a count, so * "d3_" works to delete 3 lines. */ -static void nv_lineop(cap) -cmdarg_T *cap; +static void nv_lineop(cmdarg_T *cap) { cap->oap->motion_type = MLINE; if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL) @@ -6854,8 +6753,7 @@ cmdarg_T *cap; /* * command. */ -static void nv_home(cap) -cmdarg_T *cap; +static void nv_home(cmdarg_T *cap) { /* CTRL-HOME is like "gg" */ if (mod_mask & MOD_MASK_CTRL) @@ -6871,8 +6769,7 @@ cmdarg_T *cap; /* * "|" command. */ -static void nv_pipe(cap) -cmdarg_T *cap; +static void nv_pipe(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; @@ -6891,8 +6788,7 @@ cmdarg_T *cap; * Handle back-word command "b" and "B". * cap->arg is 1 for "B" */ -static void nv_bck_word(cap) -cmdarg_T *cap; +static void nv_bck_word(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; @@ -6907,8 +6803,7 @@ cmdarg_T *cap; * Handle word motion commands "e", "E", "w" and "W". * cap->arg is TRUE for "E" and "W". */ -static void nv_wordcmd(cap) -cmdarg_T *cap; +static void nv_wordcmd(cmdarg_T *cap) { int n; int word_end; @@ -6987,8 +6882,7 @@ cmdarg_T *cap; * end of the line, may move it back to the last character and make the motion * inclusive. */ -static void adjust_cursor(oap) -oparg_T *oap; +static void adjust_cursor(oparg_T *oap) { /* The cursor cannot remain on the NUL when: * - the column is > 0 @@ -7011,8 +6905,7 @@ oparg_T *oap; * "0" and "^" commands. * cap->arg is the argument for beginline(). */ -static void nv_beginline(cap) -cmdarg_T *cap; +static void nv_beginline(cmdarg_T *cap) { cap->oap->motion_type = MCHAR; cap->oap->inclusive = FALSE; @@ -7026,8 +6919,7 @@ cmdarg_T *cap; /* * In exclusive Visual mode, may include the last character. */ -static void adjust_for_sel(cap) -cmdarg_T *cap; +static void adjust_for_sel(cmdarg_T *cap) { if (VIsual_active && cap->oap->inclusive && *p_sel == 'e' && gchar_cursor() != NUL && lt(VIsual, curwin->w_cursor)) { @@ -7044,7 +6936,7 @@ cmdarg_T *cap; * Should check VIsual_mode before calling this. * Returns TRUE when backed up to the previous line. */ -static int unadjust_for_sel() { +static int unadjust_for_sel(void) { pos_T *pp; if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor)) { @@ -7069,8 +6961,7 @@ static int unadjust_for_sel() { /* * SELECT key in Normal or Visual mode: end of Select mode mapping. */ -static void nv_select(cap) -cmdarg_T *cap; +static void nv_select(cmdarg_T *cap) { if (VIsual_active) VIsual_select = TRUE; @@ -7086,8 +6977,7 @@ cmdarg_T *cap; * "G", "gg", CTRL-END, CTRL-HOME. * cap->arg is TRUE for "G". */ -static void nv_goto(cap) -cmdarg_T *cap; +static void nv_goto(cmdarg_T *cap) { linenr_T lnum; @@ -7114,8 +7004,7 @@ cmdarg_T *cap; /* * CTRL-\ in Normal mode. */ -static void nv_normal(cap) -cmdarg_T *cap; +static void nv_normal(cmdarg_T *cap) { if (cap->nchar == Ctrl_N || cap->nchar == Ctrl_G) { clearop(cap->oap); @@ -7139,8 +7028,7 @@ cmdarg_T *cap; * ESC in Normal mode: beep, but don't flush buffers. * Don't even beep if we are canceling a command. */ -static void nv_esc(cap) -cmdarg_T *cap; +static void nv_esc(cmdarg_T *cap) { int no_reason; @@ -7188,8 +7076,7 @@ cmdarg_T *cap; /* * Handle "A", "a", "I", "i" and commands. */ -static void nv_edit(cap) -cmdarg_T *cap; +static void nv_edit(cmdarg_T *cap) { /* is equal to "i" */ if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS) @@ -7262,11 +7149,13 @@ cmdarg_T *cap; /* * Invoke edit() and take care of "restart_edit" and the return value. */ -static void invoke_edit(cap, repl, cmd, startln) -cmdarg_T *cap; -int repl; /* "r" or "gr" command */ -int cmd; -int startln; +static void +invoke_edit ( + cmdarg_T *cap, + int repl, /* "r" or "gr" command */ + int cmd, + int startln +) { int restart_edit_save = 0; @@ -7291,8 +7180,7 @@ int startln; /* * "a" or "i" while an operator is pending or in Visual mode: object motion. */ -static void nv_object(cap) -cmdarg_T *cap; +static void nv_object(cmdarg_T *cap) { int flag; int include; @@ -7363,8 +7251,7 @@ cmdarg_T *cap; * "q" command: Start/stop recording. * "q:", "q/", "q?": edit command-line in command-line window. */ -static void nv_record(cap) -cmdarg_T *cap; +static void nv_record(cmdarg_T *cap) { if (cap->oap->op_type == OP_FORMAT) { /* "gqq" is the same as "gqgq": format line */ @@ -7386,8 +7273,7 @@ cmdarg_T *cap; /* * Handle the "@r" command. */ -static void nv_at(cap) -cmdarg_T *cap; +static void nv_at(cmdarg_T *cap) { if (checkclearop(cap->oap)) return; @@ -7407,8 +7293,7 @@ cmdarg_T *cap; /* * Handle the CTRL-U and CTRL-D commands. */ -static void nv_halfpage(cap) -cmdarg_T *cap; +static void nv_halfpage(cmdarg_T *cap) { if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1) || (cap->cmdchar == Ctrl_D @@ -7421,8 +7306,7 @@ cmdarg_T *cap; /* * Handle "J" or "gJ" command. */ -static void nv_join(cap) -cmdarg_T *cap; +static void nv_join(cmdarg_T *cap) { if (VIsual_active) /* join the visual lines */ nv_operator(cap); @@ -7443,8 +7327,7 @@ cmdarg_T *cap; /* * "P", "gP", "p" and "gp" commands. */ -static void nv_put(cap) -cmdarg_T *cap; +static void nv_put(cmdarg_T *cap) { int regname = 0; void *reg1 = NULL, *reg2 = NULL; @@ -7555,8 +7438,7 @@ cmdarg_T *cap; /* * "o" and "O" commands. */ -static void nv_open(cap) -cmdarg_T *cap; +static void nv_open(cmdarg_T *cap) { /* "do" is ":diffget" */ if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'o') { @@ -7576,8 +7458,7 @@ cmdarg_T *cap; * When waiting for a character for 'updatetime' K_CURSORHOLD is put in the * input buffer. "did_cursorhold" is set to avoid retriggering. */ -static void nv_cursorhold(cap) -cmdarg_T *cap; +static void nv_cursorhold(cmdarg_T *cap) { apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf); did_cursorhold = TRUE; diff --git a/src/ops.c b/src/ops.c index 3acb297134..8b2a728acb 100644 --- a/src/ops.c +++ b/src/ops.c @@ -130,9 +130,7 @@ static char opchars[][3] = * Translate a command name into an operator type. * Must only be called with a valid operator name! */ -int get_op_type(char1, char2) -int char1; -int char2; +int get_op_type(int char1, int char2) { int i; @@ -149,8 +147,7 @@ int char2; /* * Return TRUE if operator "op" always works on whole lines. */ -int op_on_lines(op) -int op; +int op_on_lines(int op) { return opchars[op][2]; } @@ -159,8 +156,7 @@ int op; * Get first operator command character. * Returns 'g' or 'z' if there is another command character. */ -int get_op_char(optype) -int optype; +int get_op_char(int optype) { return opchars[optype][0]; } @@ -168,8 +164,7 @@ int optype; /* * Get second operator command character. */ -int get_extra_op_char(optype) -int optype; +int get_extra_op_char(int optype) { return opchars[optype][1]; } @@ -177,10 +172,7 @@ int optype; /* * op_shift - handle a shift operation */ -void op_shift(oap, curs_top, amount) -oparg_T *oap; -int curs_top; -int amount; +void op_shift(oparg_T *oap, int curs_top, int amount) { long i; int first_char; @@ -257,11 +249,13 @@ int amount; * shift the current line one shiftwidth left (if left != 0) or right * leaves cursor on first blank in the line */ -void shift_line(left, round, amount, call_changed_bytes) -int left; -int round; -int amount; -int call_changed_bytes; /* call changed_bytes() */ +void +shift_line ( + int left, + int round, + int amount, + int call_changed_bytes /* call changed_bytes() */ +) { int count; int i, j; @@ -301,9 +295,7 @@ int call_changed_bytes; /* call changed_bytes() */ * Shift one line of the current block one shiftwidth right or left. * Leaves cursor on first character in block. */ -static void shift_block(oap, amount) -oparg_T *oap; -int amount; +static void shift_block(oparg_T *oap, int amount) { int left = (oap->op_type == OP_LSHIFT); int oldstate = State; @@ -466,11 +458,7 @@ int amount; * Insert string "s" (b_insert ? before : after) block :AKelly * Caller must prepare for undo. */ -static void block_insert(oap, s, b_insert, bdp) -oparg_T *oap; -char_u *s; -int b_insert; -struct block_def *bdp; +static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def *bdp) { int p_ts; int count = 0; /* extra spaces to replace a cut TAB */ @@ -643,7 +631,7 @@ static char_u *expr_line = NULL; * Get an expression for the "\"=expr1" or "CTRL-R =expr1" * Returns '=' when OK, NUL otherwise. */ -int get_expr_register() { +int get_expr_register(void) { char_u *new_line; new_line = getcmdline('=', 0L, 0); @@ -660,8 +648,7 @@ int get_expr_register() { * Set the expression for the '=' register. * Argument must be an allocated string. */ -void set_expr_line(new_line) -char_u *new_line; +void set_expr_line(char_u *new_line) { vim_free(expr_line); expr_line = new_line; @@ -671,7 +658,7 @@ char_u *new_line; * Get the result of the '=' register expression. * Returns a pointer to allocated memory, or NULL for failure. */ -char_u * get_expr_line() { +char_u *get_expr_line(void) { char_u *expr_copy; char_u *rv; static int nested = 0; @@ -700,7 +687,7 @@ char_u * get_expr_line() { /* * Get the '=' register expression itself, without evaluating it. */ -char_u * get_expr_line_src() { +char_u *get_expr_line_src(void) { if (expr_line == NULL) return NULL; return vim_strsave(expr_line); @@ -710,9 +697,11 @@ char_u * get_expr_line_src() { * Check if 'regname' is a valid name of a yank register. * Note: There is no check for 0 (default register), caller should do this */ -int valid_yank_reg(regname, writing) -int regname; -int writing; /* if TRUE check for writable registers */ +int +valid_yank_reg ( + int regname, + int writing /* if TRUE check for writable registers */ +) { if ( (regname > 0 && ASCII_ISALNUM(regname)) || (!writing && vim_strchr((char_u *) @@ -734,9 +723,7 @@ int writing; /* if TRUE check for writable registers */ * If regname is 0 and writing, use register 0 * If regname is 0 and reading, use previous register */ -void get_yank_register(regname, writing) -int regname; -int writing; +void get_yank_register(int regname, int writing) { int i; @@ -767,9 +754,11 @@ int writing; * Obtain the contents of a "normal" register. The register is made empty. * The returned pointer has allocated memory, use put_register() later. */ -void * get_register(name, copy) -int name; -int copy; /* make a copy, if FALSE make register empty. */ +void * +get_register ( + int name, + int copy /* make a copy, if FALSE make register empty. */ +) { struct yankreg *reg; int i; @@ -799,9 +788,7 @@ int copy; /* make a copy, if FALSE make register empty. */ /* * Put "reg" into register "name". Free any previous contents and "reg". */ -void put_register(name, reg) -int name; -void *reg; +void put_register(int name, void *reg) { get_yank_register(name, 0); free_yank_all(); @@ -810,8 +797,7 @@ void *reg; } -void free_register(reg) -void *reg; +void free_register(void *reg) { struct yankreg tmp; @@ -825,8 +811,7 @@ void *reg; /* * return TRUE if the current yank register has type MLINE */ -int yank_register_mline(regname) -int regname; +int yank_register_mline(int regname) { if (regname != 0 && !valid_yank_reg(regname, FALSE)) return FALSE; @@ -841,8 +826,7 @@ int regname; * * Return FAIL for failure, OK otherwise. */ -int do_record(c) -int c; +int do_record(int c) { char_u *p; static int regname; @@ -896,9 +880,7 @@ int c; * * return FAIL for failure, OK otherwise */ -static int stuff_yank(regname, p) -int regname; -char_u *p; +static int stuff_yank(int regname, char_u *p) { char_u *lp; char_u **pp; @@ -946,11 +928,13 @@ static int execreg_lastc = NUL; * * return FAIL for failure, OK otherwise */ -int do_execreg(regname, colon, addcr, silent) -int regname; -int colon; /* insert ':' before each line */ -int addcr; /* always add '\n' to end of line */ -int silent; /* set "silent" flag in typeahead buffer */ +int +do_execreg ( + int regname, + int colon, /* insert ':' before each line */ + int addcr, /* always add '\n' to end of line */ + int silent /* set "silent" flag in typeahead buffer */ +) { long i; char_u *p; @@ -1052,8 +1036,7 @@ int silent; /* set "silent" flag in typeahead buffer */ * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's * used only after other typeahead has been processed. */ -static void put_reedit_in_typebuf(silent) -int silent; +static void put_reedit_in_typebuf(int silent) { char_u buf[3]; @@ -1077,11 +1060,13 @@ int silent; * When "esc" is TRUE it is to be taken literally: Escape CSI characters and * no remapping. */ -static int put_in_typebuf(s, esc, colon, silent) -char_u *s; -int esc; -int colon; /* add ':' before the line */ -int silent; +static int +put_in_typebuf ( + char_u *s, + int esc, + int colon, /* add ':' before the line */ + int silent +) { int retval = OK; @@ -1114,9 +1099,11 @@ int silent; * * return FAIL for failure, OK otherwise */ -int insert_reg(regname, literally) -int regname; -int literally; /* insert literally, not as if typed */ +int +insert_reg ( + int regname, + int literally /* insert literally, not as if typed */ +) { long i; int retval = OK; @@ -1169,9 +1156,7 @@ int literally; /* insert literally, not as if typed */ * Stuff a string into the typeahead buffer, such that edit() will insert it * literally ("literally" TRUE) or interpret is as typed characters. */ -static void stuffescaped(arg, literally) -char_u *arg; -int literally; +static void stuffescaped(char_u *arg, int literally) { int c; char_u *start; @@ -1206,11 +1191,13 @@ int literally; * If "regname" is a special register, return TRUE and store a pointer to its * value in "argp". */ -int get_spec_reg(regname, argp, allocated, errmsg) -int regname; -char_u **argp; -int *allocated; /* return: TRUE when value was allocated */ -int errmsg; /* give error message when failing */ +int +get_spec_reg ( + int regname, + char_u **argp, + int *allocated, /* return: TRUE when value was allocated */ + int errmsg /* give error message when failing */ +) { int cnt; @@ -1287,10 +1274,12 @@ int errmsg; /* give error message when failing */ * * return FAIL for failure, OK otherwise */ -int cmdline_paste_reg(regname, literally, remcr) -int regname; -int literally; /* Insert text literally instead of "as typed" */ -int remcr; /* don't add trailing CR */ +int +cmdline_paste_reg ( + int regname, + int literally, /* Insert text literally instead of "as typed" */ + int remcr /* don't add trailing CR */ +) { long i; @@ -1325,8 +1314,7 @@ int remcr; /* don't add trailing CR */ * * Return FAIL if undo failed, OK otherwise. */ -int op_delete(oap) -oparg_T *oap; +int op_delete(oparg_T *oap) { int n; linenr_T lnum; @@ -1667,8 +1655,7 @@ setmarks: * Adjust end of operating area for ending on a multi-byte character. * Used for deletion. */ -static void mb_adjust_opend(oap) -oparg_T *oap; +static void mb_adjust_opend(oparg_T *oap) { char_u *p; @@ -1681,9 +1668,7 @@ oparg_T *oap; /* * Replace a whole area with one character. */ -int op_replace(oap, c) -oparg_T *oap; -int c; +int op_replace(oparg_T *oap, int c) { int n, numc; int num_chars; @@ -1885,8 +1870,7 @@ static int swapchars __ARGS((int op_type, pos_T *pos, int length)); /* * Handle the (non-standard vi) tilde operator. Also for "gu", "gU" and "g?". */ -void op_tilde(oap) -oparg_T *oap; +void op_tilde(oparg_T *oap) { pos_T pos; struct block_def bd; @@ -1961,10 +1945,7 @@ oparg_T *oap; * Also works correctly when the number of bytes changes. * Returns TRUE if some character was changed. */ -static int swapchars(op_type, pos, length) -int op_type; -pos_T *pos; -int length; +static int swapchars(int op_type, pos_T *pos, int length) { int todo; int did_change = 0; @@ -1991,9 +1972,7 @@ int length; * else swap case of character at 'pos' * returns TRUE when something actually changed. */ -int swapchar(op_type, pos) -int op_type; -pos_T *pos; +int swapchar(int op_type, pos_T *pos) { int c; int nc; @@ -2050,9 +2029,7 @@ pos_T *pos; /* * op_insert - Insert and append operators for Visual mode. */ -void op_insert(oap, count1) -oparg_T *oap; -long count1; +void op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; char_u *firstline, *ins_text; @@ -2198,8 +2175,7 @@ long count1; * * return TRUE if edit() returns because of a CTRL-O command */ -int op_change(oap) -oparg_T *oap; +int op_change(oparg_T *oap) { colnr_T l; int retval; @@ -2318,7 +2294,7 @@ oparg_T *oap; /* * set all the yank registers to empty (called from main()) */ -void init_yank() { +void init_yank(void) { int i; for (i = 0; i < NUM_REGISTERS; ++i) @@ -2326,7 +2302,7 @@ void init_yank() { } #if defined(EXITFREE) || defined(PROTO) -void clear_registers() { +void clear_registers(void) { int i; for (i = 0; i < NUM_REGISTERS; ++i) { @@ -2342,8 +2318,7 @@ void clear_registers() { * Free "n" lines from the current yank register. * Called for normal freeing and in case of error. */ -static void free_yank(n) -long n; +static void free_yank(long n) { if (y_current->y_array != NULL) { long i; @@ -2356,7 +2331,7 @@ long n; } } -static void free_yank_all() { +static void free_yank_all(void) { free_yank(y_current->y_size); } @@ -2368,10 +2343,7 @@ static void free_yank_all() { * * Return FAIL for failure, OK otherwise. */ -int op_yank(oap, deleting, mess) -oparg_T *oap; -int deleting; -int mess; +int op_yank(oparg_T *oap, int deleting, int mess) { long y_idx; /* index in y_array[] */ struct yankreg *curr; /* copy of y_current */ @@ -2604,9 +2576,7 @@ fail: /* free the allocated lines */ return FAIL; } -static int yank_copy_line(bd, y_idx) -struct block_def *bd; -long y_idx; +static int yank_copy_line(struct block_def *bd, long y_idx) { char_u *pnew; @@ -2632,11 +2602,13 @@ long y_idx; * PUT_CURSEND leave cursor after end of new text * PUT_LINE force linewise put (":put") */ -void do_put(regname, dir, count, flags) -int regname; -int dir; /* BACKWARD for 'P', FORWARD for 'p' */ -long count; -int flags; +void +do_put ( + int regname, + int dir, /* BACKWARD for 'P', FORWARD for 'p' */ + long count, + int flags +) { char_u *ptr; char_u *newp, *oldp; @@ -3197,7 +3169,7 @@ end: * When the cursor is on the NUL past the end of the line and it should not be * there move it left. */ -void adjust_cursor_eol() { +void adjust_cursor_eol(void) { if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL && (ve_flags & VE_ONEMORE) == 0 @@ -3218,7 +3190,7 @@ void adjust_cursor_eol() { /* * Return TRUE if lines starting with '#' should be left aligned. */ -int preprocs_left() { +int preprocs_left(void) { return (curbuf->b_p_si && !curbuf->b_p_cin) || (curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE) @@ -3227,8 +3199,7 @@ int preprocs_left() { } /* Return the character name of the register with the given number */ -int get_register_name(num) -int num; +int get_register_name(int num) { if (num == -1) return '"'; @@ -3244,8 +3215,7 @@ int num; /* * ":dis" and ":registers": Display the contents of the yank registers. */ -void ex_display(eap) -exarg_T *eap; +void ex_display(exarg_T *eap) { int i, n; long j; @@ -3374,9 +3344,11 @@ exarg_T *eap; * display a string for do_dis() * truncate at end of screen line */ -static void dis_msg(p, skip_esc) -char_u *p; -int skip_esc; /* if TRUE, ignore trailing ESC */ +static void +dis_msg ( + char_u *p, + int skip_esc /* if TRUE, ignore trailing ESC */ +) { int n; int l; @@ -3406,11 +3378,7 @@ int skip_esc; /* if TRUE, ignore trailing ESC */ * is_comment - will indicate whether the current line ends with an unclosed * comment. */ -static char_u * skip_comment(line, process, include_space, is_comment) -char_u *line; -int process; -int include_space; -int *is_comment; +static char_u *skip_comment(char_u *line, int process, int include_space, int *is_comment) { char_u *comment_flags = NULL; int lead_len; @@ -3470,11 +3438,7 @@ int *is_comment; * * return FAIL for failure, OK otherwise */ -int do_join(count, insert_space, save_undo, use_formatoptions) -long count; -int insert_space; -int save_undo; -int use_formatoptions UNUSED; +int do_join(long count, int insert_space, int save_undo, int use_formatoptions) { char_u *curr = NULL; char_u *curr_start = NULL; @@ -3652,13 +3616,7 @@ theend: * the first line. White-space is ignored. Note that the whole of * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb */ -static int same_leader(lnum, leader1_len, leader1_flags, leader2_len, - leader2_flags) -linenr_T lnum; -int leader1_len; -char_u *leader1_flags; -int leader2_len; -char_u *leader2_flags; +static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, int leader2_len, char_u *leader2_flags) { int idx1 = 0, idx2 = 0; char_u *p; @@ -3719,9 +3677,11 @@ char_u *leader2_flags; /* * Implementation of the format operator 'gq'. */ -void op_format(oap, keep_cursor) -oparg_T *oap; -int keep_cursor; /* keep cursor on same text char */ +void +op_format ( + oparg_T *oap, + int keep_cursor /* keep cursor on same text char */ +) { long old_line_count = curbuf->b_ml.ml_line_count; @@ -3787,8 +3747,7 @@ int keep_cursor; /* keep cursor on same text char */ /* * Implementation of the format operator 'gq' for when using 'formatexpr'. */ -void op_formatexpr(oap) -oparg_T *oap; +void op_formatexpr(oparg_T *oap) { if (oap->is_VIsual) /* When there is no change: need to remove the Visual selection */ @@ -3800,10 +3759,12 @@ oparg_T *oap; op_format(oap, FALSE); } -int fex_format(lnum, count, c) -linenr_T lnum; -long count; -int c; /* character to be inserted */ +int +fex_format ( + linenr_T lnum, + long count, + int c /* character to be inserted */ +) { int use_sandbox = was_set_insecurely((char_u *)"formatexpr", OPT_LOCAL); @@ -3837,9 +3798,11 @@ int c; /* character to be inserted */ * Lines after the cursor line are saved for undo, caller must have saved the * first line. */ -void format_lines(line_count, avoid_fex) -linenr_T line_count; -int avoid_fex; /* don't use 'formatexpr' */ +void +format_lines ( + linenr_T line_count, + int avoid_fex /* don't use 'formatexpr' */ +) { int max_len; int is_not_par; /* current line not part of parag. */ @@ -4056,8 +4019,7 @@ int avoid_fex; /* don't use 'formatexpr' */ /* * Return TRUE if line "lnum" ends in a white character. */ -static int ends_in_white(lnum) -linenr_T lnum; +static int ends_in_white(linenr_T lnum) { char_u *s = ml_get(lnum); size_t l; @@ -4078,11 +4040,7 @@ linenr_T lnum; * previous line. A new paragraph starts after a blank line, or when the * comment leader changes -- webb. */ -static int fmt_check_par(lnum, leader_len, leader_flags, do_comments) -linenr_T lnum; -int *leader_len; -char_u **leader_flags; -int do_comments; +static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags, int do_comments) { char_u *flags = NULL; /* init for GCC */ char_u *ptr; @@ -4111,8 +4069,7 @@ int do_comments; * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the * previous line is in the same paragraph. Used for auto-formatting. */ -int paragraph_start(lnum) -linenr_T lnum; +int paragraph_start(linenr_T lnum) { char_u *p; int leader_len = 0; /* leader len of current line */ @@ -4165,11 +4122,7 @@ linenr_T lnum; * - start/endspaces is the number of columns of the first/last yanked char * that are to be yanked. */ -static void block_prep(oap, bdp, lnum, is_del) -oparg_T *oap; -struct block_def *bdp; -linenr_T lnum; -int is_del; +static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int is_del) { int incr = 0; char_u *pend; @@ -4281,8 +4234,7 @@ int is_del; static void reverse_line __ARGS((char_u *s)); -static void reverse_line(s) -char_u *s; +static void reverse_line(char_u *s) { int i, j; char_u c; @@ -4304,9 +4256,7 @@ char_u *s; * * return FAIL for failure, OK otherwise */ -int do_addsub(command, Prenum1) -int command; -linenr_T Prenum1; +int do_addsub(int command, linenr_T Prenum1) { int col; char_u *buf1; @@ -4530,9 +4480,7 @@ linenr_T Prenum1; return OK; } -int read_viminfo_register(virp, force) -vir_T *virp; -int force; +int read_viminfo_register(vir_T *virp, int force) { int eof; int do_it = TRUE; @@ -4622,8 +4570,7 @@ int force; return eof; } -void write_viminfo_registers(fp) -FILE *fp; +void write_viminfo_registers(FILE *fp) { int i, j; char_u *type; @@ -4710,9 +4657,7 @@ FILE *fp; * Used for getregtype() * Returns MAUTO for error. */ -char_u get_reg_type(regname, reglen) -int regname; -long *reglen; +char_u get_reg_type(int regname, long *reglen) { switch (regname) { case '%': /* file name */ @@ -4748,10 +4693,12 @@ long *reglen; * Used for "@r" in expressions and for getreg(). * Returns NULL for error. */ -char_u * get_reg_contents(regname, allowexpr, expr_src) -int regname; -int allowexpr; /* allow "=" register */ -int expr_src; /* get expression for "=" register */ +char_u * +get_reg_contents ( + int regname, + int allowexpr, /* allow "=" register */ + int expr_src /* get expression for "=" register */ +) { long i; char_u *retval; @@ -4835,22 +4782,12 @@ int expr_src; /* get expression for "=" register */ * Careful: 'str' is modified, you may have to use a copy! * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise. */ -void write_reg_contents(name, str, maxlen, must_append) -int name; -char_u *str; -int maxlen; -int must_append; +void write_reg_contents(int name, char_u *str, int maxlen, int must_append) { write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L); } -void write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len) -int name; -char_u *str; -int maxlen; -int must_append; -int yank_type; -long block_len; +void write_reg_contents_ex(int name, char_u *str, int maxlen, int must_append, int yank_type, long block_len) { struct yankreg *old_y_previous, *old_y_current; long len; @@ -4910,12 +4847,14 @@ long block_len; * Put a string into a register. When the register is not empty, the string * is appended. */ -static void str_to_reg(y_ptr, yank_type, str, len, blocklen) -struct yankreg *y_ptr; /* pointer to yank register */ -int yank_type; /* MCHAR, MLINE, MBLOCK, MAUTO */ -char_u *str; /* string to put in register */ -long len; /* length of string */ -long blocklen; /* width of Visual block */ +static void +str_to_reg ( + struct yankreg *y_ptr, /* pointer to yank register */ + int yank_type, /* MCHAR, MLINE, MBLOCK, MAUTO */ + char_u *str, /* string to put in register */ + long len, /* length of string */ + long blocklen /* width of Visual block */ +) { int type; /* MCHAR, MLINE or MBLOCK */ int lnum; @@ -5010,8 +4949,7 @@ long blocklen; /* width of Visual block */ y_ptr->y_width = 0; } -void clear_oparg(oap) -oparg_T *oap; +void clear_oparg(oparg_T *oap) { vim_memset(oap, 0, sizeof(oparg_T)); } @@ -5034,12 +4972,7 @@ static long line_count_info __ARGS((char_u *line, long *wc, long *cc, * case, eol_size will be added to the character count to account for * the size of the EOL character. */ -static long line_count_info(line, wc, cc, limit, eol_size) -char_u *line; -long *wc; -long *cc; -long limit; -int eol_size; +static long line_count_info(char_u *line, long *wc, long *cc, long limit, int eol_size) { long i; long words = 0; @@ -5076,7 +5009,7 @@ int eol_size; * In Visual mode, give some info about the selected region. (In this case, * the *_count_cursor variables store running totals for the selection.) */ -void cursor_pos_info() { +void cursor_pos_info(void) { char_u *p; char_u buf1[50]; char_u buf2[40]; diff --git a/src/option.c b/src/option.c index 9dc432a1d4..60bf6a663f 100644 --- a/src/option.c +++ b/src/option.c @@ -1921,7 +1921,7 @@ static int check_opt_wim __ARGS((void)); * * Called only once from main(), just after creating the first buffer. */ -void set_init_1() { +void set_init_1(void) { char_u *p; int opt_idx; long_u n; @@ -2212,10 +2212,12 @@ void set_init_1() { * Set an option to its default value. * This does not take care of side effects! */ -static void set_option_default(opt_idx, opt_flags, compatible) -int opt_idx; -int opt_flags; /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ -int compatible; /* use Vi default value */ +static void +set_option_default ( + int opt_idx, + int opt_flags, /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ + int compatible /* use Vi default value */ +) { char_u *varp; /* pointer to variable for current option */ int dvi; /* index in def_val[] */ @@ -2275,8 +2277,10 @@ int compatible; /* use Vi default value */ /* * Set all options (except terminal options) to their default value. */ -static void set_options_default(opt_flags) -int opt_flags; /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ +static void +set_options_default ( + int opt_flags /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ +) { int i; win_T *wp; @@ -2295,9 +2299,7 @@ int opt_flags; /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ * Set the Vi-default value of a string option. * Used for 'sh', 'backupskip' and 'term'. */ -void set_string_default(name, val) -char *name; -char_u *val; +void set_string_default(char *name, char_u *val) { char_u *p; int opt_idx; @@ -2318,9 +2320,7 @@ char_u *val; * Set the Vi-default value of a number option. * Used for 'lines' and 'columns'. */ -void set_number_default(name, val) -char *name; -long val; +void set_number_default(char *name, long val) { int opt_idx; @@ -2333,7 +2333,7 @@ long val; /* * Free all options. */ -void free_all_options() { +void free_all_options(void) { int i; for (i = 0; !istermoption(&options[i]); i++) { @@ -2357,7 +2357,7 @@ void free_all_options() { * Initialize the options, part two: After getting Rows and Columns and * setting 'term'. */ -void set_init_2() { +void set_init_2(void) { int idx; /* @@ -2411,7 +2411,7 @@ void set_init_2() { * values separated by semicolons; we want the last value in either * case. If this value is 0-6 or 8, our background is dark. */ -static char_u * term_bg_default() { +static char_u *term_bg_default(void) { char_u *p; if (STRCMP(T_NAME, "linux") == 0 @@ -2429,7 +2429,7 @@ static char_u * term_bg_default() { /* * Initialize the options, part three: After reading the .vimrc */ -void set_init_3() { +void set_init_3(void) { #if defined(UNIX) || defined(OS2) || defined(WIN3264) /* * Set 'shellpipe' and 'shellredir', depending on the 'shell' option. @@ -2520,8 +2520,7 @@ void set_init_3() { * When 'helplang' is still at its default value, set it to "lang". * Only the first two characters of "lang" are used. */ -void set_helplang_default(lang) -char_u *lang; +void set_helplang_default(char_u *lang) { int idx; @@ -2554,7 +2553,7 @@ char_u *lang; * they can be reset. This reduces startup time when using X on a remote * machine. */ -void set_title_defaults() { +void set_title_defaults(void) { int idx1; long val; @@ -2592,9 +2591,11 @@ void set_title_defaults() { * * returns FAIL if an error is detected, OK otherwise */ -int do_set(arg, opt_flags) -char_u *arg; /* option string (may be written to!) */ -int opt_flags; +int +do_set ( + char_u *arg, /* option string (may be written to!) */ + int opt_flags +) { int opt_idx; char_u *errmsg; @@ -3339,10 +3340,12 @@ theend: * Call this when an option has been given a new value through a user command. * Sets the P_WAS_SET flag and takes care of the P_INSECURE flag. */ -static void did_set_option(opt_idx, opt_flags, new_value) -int opt_idx; -int opt_flags; /* possibly with OPT_MODELINE */ -int new_value; /* value was replaced completely */ +static void +did_set_option ( + int opt_idx, + int opt_flags, /* possibly with OPT_MODELINE */ + int new_value /* value was replaced completely */ +) { long_u *p; @@ -3362,9 +3365,7 @@ int new_value; /* value was replaced completely */ *p = *p & ~P_INSECURE; } -static char_u * illegal_char(errbuf, c) -char_u *errbuf; -int c; +static char_u *illegal_char(char_u *errbuf, int c) { if (errbuf == NULL) return (char_u *)""; @@ -3377,8 +3378,7 @@ int c; * Convert a key name or string into a key value. * Used for 'wildchar' and 'cedit' options. */ -static int string_to_key(arg) -char_u *arg; +static int string_to_key(char_u *arg) { if (*arg == '<') return find_key_option(arg + 1); @@ -3391,7 +3391,7 @@ char_u *arg; * Check value of 'cedit' and set cedit_key. * Returns NULL if value is OK, error message otherwise. */ -static char_u * check_cedit() { +static char_u *check_cedit(void) { int n; if (*p_cedit == NUL) @@ -3411,8 +3411,10 @@ static char_u * check_cedit() { * When switching the title or icon off, call mch_restore_title() to get * the old value back. */ -static void did_set_title(icon) -int icon; /* Did set icon instead of title */ +static void +did_set_title ( + int icon /* Did set icon instead of title */ +) { if (starting != NO_SCREEN ) { @@ -3430,10 +3432,12 @@ int icon; /* Did set icon instead of title */ /* * set_options_bin - called when 'bin' changes value. */ -void set_options_bin(oldval, newval, opt_flags) -int oldval; -int newval; -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +void +set_options_bin ( + int oldval, + int newval, + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { /* * The option values that are changed when 'bin' changes are @@ -3491,8 +3495,7 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ * If the parameter is not specified in the string or there is no following * number, return -1. */ -int get_viminfo_parameter(type) -int type; +int get_viminfo_parameter(int type) { char_u *p; @@ -3507,8 +3510,7 @@ int type; * '/') in the 'viminfo' option and return a pointer to the string after it. * Return NULL if the parameter is not specified in the string. */ -char_u * find_viminfo_parameter(type) -int type; +char_u *find_viminfo_parameter(int type) { char_u *p; @@ -3530,9 +3532,7 @@ int type; * If "val" is NULL expand the current value of the option. * Return pointer to NameBuff, or NULL when not expanded. */ -static char_u * option_expand(opt_idx, val) -int opt_idx; -char_u *val; +static char_u *option_expand(int opt_idx, char_u *val) { /* if option doesn't need expansion nothing to do */ if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) @@ -3566,7 +3566,7 @@ char_u *val; * After setting various option values: recompute variables that depend on * option values. */ -static void didset_options() { +static void didset_options(void) { /* initialize the table for 'iskeyword' et.al. */ (void)init_chartab(); @@ -3590,7 +3590,7 @@ static void didset_options() { /* * Check for string options that are NULL (normally only termcap options). */ -void check_options() { +void check_options(void) { int opt_idx; for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) @@ -3601,8 +3601,7 @@ void check_options() { /* * Check string options in a buffer for NULL value. */ -void check_buf_options(buf) -buf_T *buf; +void check_buf_options(buf_T *buf) { check_string_option(&buf->b_p_bh); check_string_option(&buf->b_p_bt); @@ -3656,23 +3655,20 @@ buf_T *buf; * check_options(). * Does NOT check for P_ALLOCED flag! */ -void free_string_option(p) -char_u *p; +void free_string_option(char_u *p) { if (p != empty_option) vim_free(p); } -void clear_string_option(pp) -char_u **pp; +void clear_string_option(char_u **pp) { if (*pp != empty_option) vim_free(*pp); *pp = empty_option; } -static void check_string_option(pp) -char_u **pp; +static void check_string_option(char_u **pp) { if (*pp == NULL) *pp = empty_option; @@ -3681,8 +3677,7 @@ char_u **pp; /* * Mark a terminal option as allocated, found by a pointer into term_strings[]. */ -void set_term_option_alloced(p) -char_u **p; +void set_term_option_alloced(char_u **p) { int opt_idx; @@ -3699,9 +3694,7 @@ char_u **p; * Return FALSE when it wasn't. * Return -1 for an unknown option. */ -int was_set_insecurely(opt, opt_flags) -char_u *opt; -int opt_flags; +int was_set_insecurely(char_u *opt, int opt_flags) { int idx = findoption(opt); long_u *flagp; @@ -3718,9 +3711,7 @@ int opt_flags; * Get a pointer to the flags used for the P_INSECURE flag of option * "opt_idx". For some local options a local flags field is used. */ -static long_u * insecure_flag(opt_idx, opt_flags) -int opt_idx; -int opt_flags; +static long_u *insecure_flag(int opt_idx, int opt_flags) { if (opt_flags & OPT_LOCAL) switch ((int)options[opt_idx].indir) { @@ -3741,7 +3732,7 @@ static void redraw_titles __ARGS((void)); /* * Redraw the window title and/or tab page text later. */ -static void redraw_titles() { +static void redraw_titles(void) { need_maketitle = TRUE; redraw_tabline = TRUE; } @@ -3753,12 +3744,14 @@ static void redraw_titles() { * When "set_sid" is zero set the scriptID to current_SID. When "set_sid" is * SID_NONE don't set the scriptID. Otherwise set the scriptID to "set_sid". */ -void set_string_option_direct(name, opt_idx, val, opt_flags, set_sid) -char_u *name; -int opt_idx; -char_u *val; -int opt_flags; /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ -int set_sid UNUSED; +void +set_string_option_direct ( + char_u *name, + int opt_idx, + char_u *val, + int opt_flags, /* OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL */ + int set_sid +) { char_u *s; char_u **varp; @@ -3805,9 +3798,11 @@ int set_sid UNUSED; /* * Set global value for string option when it's a local option. */ -static void set_string_option_global(opt_idx, varp) -int opt_idx; /* option index */ -char_u **varp; /* pointer to option variable */ +static void +set_string_option_global ( + int opt_idx, /* option index */ + char_u **varp /* pointer to option variable */ +) { char_u **p, *s; @@ -3829,10 +3824,12 @@ char_u **varp; /* pointer to option variable */ * * Returns NULL on success or error message on error. */ -static char_u * set_string_option(opt_idx, value, opt_flags) -int opt_idx; -char_u *value; -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +static char_u * +set_string_option ( + int opt_idx, + char_u *value, + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { char_u *s; char_u **varp; @@ -3862,15 +3859,15 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ * Handle string options that need some action to perform when changed. * Returns NULL for success, or an error message for an error. */ -static char_u * did_set_string_option(opt_idx, varp, new_value_alloced, oldval, - errbuf, - opt_flags) -int opt_idx; /* index in options[] table */ -char_u **varp; /* pointer to the option variable */ -int new_value_alloced; /* new value was allocated */ -char_u *oldval; /* previous value of the option */ -char_u *errbuf; /* buffer for errors, or NULL */ -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +static char_u * +did_set_string_option ( + int opt_idx, /* index in options[] table */ + char_u **varp, /* pointer to the option variable */ + int new_value_alloced, /* new value was allocated */ + char_u *oldval, /* previous value of the option */ + char_u *errbuf, /* buffer for errors, or NULL */ + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { char_u *errmsg = NULL; char_u *s, *p; @@ -4817,9 +4814,7 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ /* * Simple int comparison function for use with qsort() */ -static int int_cmp(a, b) -const void *a; -const void *b; +static int int_cmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } @@ -4828,8 +4823,7 @@ const void *b; * Handle setting 'colorcolumn' or 'textwidth' in window "wp". * Returns error message, NULL if it's OK. */ -char_u * check_colorcolumn(wp) -win_T *wp; +char_u *check_colorcolumn(win_T *wp) { char_u *s; int col; @@ -4893,8 +4887,7 @@ skip: * Handle setting 'listchars' or 'fillchars'. * Returns error message, NULL if it's OK. */ -static char_u * set_chars_option(varp) -char_u **varp; +static char_u *set_chars_option(char_u **varp) { int round, i, len, entries; char_u *p, *s; @@ -4991,8 +4984,7 @@ char_u **varp; * Check validity of options with the 'statusline' format. * Return error message or NULL. */ -char_u * check_stl_option(s) -char_u *s; +char_u *check_stl_option(char_u *s) { int itemcnt = 0; int groupdepth = 0; @@ -5055,8 +5047,7 @@ char_u *s; * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. * Return error message when failed, NULL when OK. */ -static char_u * compile_cap_prog(synblock) -synblock_T *synblock; +static char_u *compile_cap_prog(synblock_T *synblock) { regprog_T *rp = synblock->b_cap_prog; char_u *re; @@ -5084,10 +5075,7 @@ synblock_T *synblock; * Set the scriptID for an option, taking care of setting the buffer- or * window-local value. */ -static void set_option_scriptID_idx(opt_idx, opt_flags, id) -int opt_idx; -int opt_flags; -int id; +static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id) { int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; @@ -5108,11 +5096,13 @@ int id; * Set the value of a boolean option, and take care of side effects. * Returns NULL for success, or an error message for an error. */ -static char_u * set_bool_option(opt_idx, varp, value, opt_flags) -int opt_idx; /* index in options[] table */ -char_u *varp; /* pointer to the option variable */ -int value; /* new value */ -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +static char_u * +set_bool_option ( + int opt_idx, /* index in options[] table */ + char_u *varp, /* pointer to the option variable */ + int value, /* new value */ + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { int old_value = *(int *)varp; @@ -5496,15 +5486,16 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ * Set the value of a number option, and take care of side effects. * Returns NULL for success, or an error message for an error. */ -static char_u * set_num_option(opt_idx, varp, value, errbuf, errbuflen, - opt_flags) -int opt_idx; /* index in options[] table */ -char_u *varp; /* pointer to the option variable */ -long value; /* new value */ -char_u *errbuf; /* buffer for error messages */ -size_t errbuflen; /* length of "errbuf" */ -int opt_flags; /* OPT_LOCAL, OPT_GLOBAL and +static char_u * +set_num_option ( + int opt_idx, /* index in options[] table */ + char_u *varp, /* pointer to the option variable */ + long value, /* new value */ + char_u *errbuf, /* buffer for error messages */ + size_t errbuflen, /* length of "errbuf" */ + int opt_flags /* OPT_LOCAL, OPT_GLOBAL and OPT_MODELINE */ +) { char_u *errmsg = NULL; long old_value = *(long *)varp; @@ -5867,8 +5858,7 @@ int opt_flags; /* OPT_LOCAL, OPT_GLOBAL and /* * Called after an option changed: check if something needs to be redrawn. */ -static void check_redraw(flags) -long_u flags; +static void check_redraw(long_u flags) { /* Careful: P_RCLR and P_RALL are a combination of other P_ flags */ int doclear = (flags & P_RCLR) == P_RCLR; @@ -5891,8 +5881,7 @@ long_u flags; * Find index for option 'arg'. * Return -1 if not found. */ -static int findoption(arg) -char_u *arg; +static int findoption(char_u *arg) { int opt_idx; char *s, *p; @@ -5956,11 +5945,13 @@ char_u *arg; * hidden String option: -2. * unknown option: -3. */ -int get_option_value(name, numval, stringval, opt_flags) -char_u *name; -long *numval; -char_u **stringval; /* NULL when only checking existence */ -int opt_flags; +int +get_option_value ( + char_u *name, + long *numval, + char_u **stringval, /* NULL when only checking existence */ + int opt_flags +) { int opt_idx; char_u *varp; @@ -6007,11 +5998,13 @@ int opt_flags; * * Returns NULL on success or error message on error. */ -char_u * set_option_value(name, number, string, opt_flags) -char_u *name; -long number; -char_u *string; -int opt_flags; /* OPT_LOCAL or 0 (both) */ +char_u * +set_option_value ( + char_u *name, + long number, + char_u *string, + int opt_flags /* OPT_LOCAL or 0 (both) */ +) { int opt_idx; char_u *varp; @@ -6067,8 +6060,7 @@ int opt_flags; /* OPT_LOCAL or 0 (both) */ * Get the terminal code for a terminal option. * Returns NULL when not found. */ -char_u * get_term_code(tname) -char_u *tname; +char_u *get_term_code(char_u *tname) { int opt_idx; char_u *varp; @@ -6085,7 +6077,7 @@ char_u *tname; return find_termcode(tname + 2); } -char_u * get_highlight_default() { +char_u *get_highlight_default(void) { int i; i = findoption((char_u *)"hl"); @@ -6094,7 +6086,7 @@ char_u * get_highlight_default() { return (char_u *)NULL; } -char_u * get_encoding_default() { +char_u *get_encoding_default(void) { int i; i = findoption((char_u *)"enc"); @@ -6106,8 +6098,7 @@ char_u * get_encoding_default() { /* * Translate a string like "t_xx", "" or "" to a key number. */ -static int find_key_option(arg) -char_u *arg; +static int find_key_option(char_u *arg) { int key; int modifiers; @@ -6133,9 +6124,11 @@ char_u *arg; * if 'all' == 1: show all normal options * if 'all' == 2: show all terminal options */ -static void showoptions(all, opt_flags) -int all; -int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ +static void +showoptions ( + int all, + int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */ +) { struct vimoption *p; int col; @@ -6231,9 +6224,7 @@ int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL */ /* * Return TRUE if option "p" has its default value. */ -static int optval_default(p, varp) -struct vimoption *p; -char_u *varp; +static int optval_default(struct vimoption *p, char_u *varp) { int dvi; @@ -6254,9 +6245,11 @@ char_u *varp; * showoneopt: show the value of one option * must not be called with a hidden option! */ -static void showoneopt(p, opt_flags) -struct vimoption *p; -int opt_flags; /* OPT_LOCAL or OPT_GLOBAL */ +static void +showoneopt ( + struct vimoption *p, + int opt_flags /* OPT_LOCAL or OPT_GLOBAL */ +) { char_u *varp; int save_silent = silent_mode; @@ -6308,10 +6301,7 @@ int opt_flags; /* OPT_LOCAL or OPT_GLOBAL */ * * Return FAIL on error, OK otherwise. */ -int makeset(fd, opt_flags, local_only) -FILE *fd; -int opt_flags; -int local_only; +int makeset(FILE *fd, int opt_flags, int local_only) { struct vimoption *p; char_u *varp; /* currently used value */ @@ -6413,8 +6403,7 @@ int local_only; * Generate set commands for the local fold options only. Used when * 'sessionoptions' or 'viewoptions' contains "folds" but not "options". */ -int makefoldset(fd) -FILE *fd; +int makefoldset(FILE *fd) { if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, FALSE) == FAIL || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, FALSE) @@ -6433,12 +6422,7 @@ FILE *fd; return OK; } -static int put_setstring(fd, cmd, name, valuep, expand) -FILE *fd; -char *cmd; -char *name; -char_u **valuep; -int expand; +static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int expand) { char_u *s; char_u *buf; @@ -6472,11 +6456,7 @@ int expand; return OK; } -static int put_setnum(fd, cmd, name, valuep) -FILE *fd; -char *cmd; -char *name; -long *valuep; +static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep) { long wc; @@ -6493,11 +6473,7 @@ long *valuep; return OK; } -static int put_setbool(fd, cmd, name, value) -FILE *fd; -char *cmd; -char *name; -int value; +static int put_setbool(FILE *fd, char *cmd, char *name, int value) { if (value < 0) /* global/local option using global value */ return OK; @@ -6512,7 +6488,7 @@ int value; * If the option has been allocated, free the memory. * Terminal options are never hidden or indirect. */ -void clear_termoptions() { +void clear_termoptions(void) { /* * Reset a few things before clearing the old options. This may cause * outputting a few things that the terminal doesn't understand, but the @@ -6525,7 +6501,7 @@ void clear_termoptions() { free_termoptions(); } -void free_termoptions() { +void free_termoptions(void) { struct vimoption *p; for (p = &options[0]; p->fullname != NULL; p++) @@ -6546,8 +6522,7 @@ void free_termoptions() { * Set the string to empty_option and clear allocated flag. * "var" points to the option value. */ -void free_one_termoption(var) -char_u *var; +void free_one_termoption(char_u *var) { struct vimoption *p; @@ -6565,7 +6540,7 @@ char_u *var; * Set the terminal option defaults to the current value. * Used after setting the terminal name. */ -void set_term_defaults() { +void set_term_defaults(void) { struct vimoption *p; for (p = &options[0]; p->fullname != NULL; p++) { @@ -6586,8 +6561,7 @@ void set_term_defaults() { /* * return TRUE if 'p' starts with 't_' */ -static int istermoption(p) -struct vimoption *p; +static int istermoption(struct vimoption *p) { return p->fullname[0] == 't' && p->fullname[1] == '_'; } @@ -6601,7 +6575,7 @@ struct vimoption *p; #define COL_RULER 17 /* columns needed by standard ruler */ -void comp_col() { +void comp_col(void) { int last_has_status = (p_ls == 2 || (p_ls == 1 && firstwin != lastwin)); sc_col = 0; @@ -6628,9 +6602,7 @@ void comp_col() { /* * Unset local option value, similar to ":set opt<". */ -void unset_global_local_option(name, from) -char_u *name; -void *from; +void unset_global_local_option(char_u *name, void *from) { struct vimoption *p; int opt_idx; @@ -6692,9 +6664,7 @@ void *from; /* * Get pointer to option variable, depending on local or global scope. */ -static char_u * get_varp_scope(p, opt_flags) -struct vimoption *p; -int opt_flags; +static char_u *get_varp_scope(struct vimoption *p, int opt_flags) { if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) @@ -6727,8 +6697,7 @@ int opt_flags; /* * Get pointer to option variable. */ -static char_u * get_varp(p) -struct vimoption *p; +static char_u *get_varp(struct vimoption *p) { /* hidden option, always return NULL */ if (p->var == NULL) @@ -6871,7 +6840,7 @@ struct vimoption *p; /* * Get the value of 'equalprg', either the buffer-local one or the global one. */ -char_u * get_equalprg() { +char_u *get_equalprg(void) { if (*curbuf->b_p_ep == NUL) return p_ep; return curbuf->b_p_ep; @@ -6881,9 +6850,7 @@ char_u * get_equalprg() { * Copy options from one window to another. * Used when splitting a window. */ -void win_copy_options(wp_from, wp_to) -win_T *wp_from; -win_T *wp_to; +void win_copy_options(win_T *wp_from, win_T *wp_to) { copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt); copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt); @@ -6897,9 +6864,7 @@ win_T *wp_to; * The 'scroll' option is not copied, because it depends on the window height. * The 'previewwindow' option is reset, there can be only one preview window. */ -void copy_winopt(from, to) -winopt_T *from; -winopt_T *to; +void copy_winopt(winopt_T *from, winopt_T *to) { to->wo_arab = from->wo_arab; to->wo_list = from->wo_list; @@ -6945,8 +6910,7 @@ winopt_T *to; /* * Check string options in a window for a NULL value. */ -void check_win_options(win) -win_T *win; +void check_win_options(win_T *win) { check_winopt(&win->w_onebuf_opt); check_winopt(&win->w_allbuf_opt); @@ -6955,8 +6919,7 @@ win_T *win; /* * Check for NULL pointers in a winopt_T and replace them with empty_option. */ -void check_winopt(wop) -winopt_T *wop UNUSED; +void check_winopt(winopt_T *wop) { check_string_option(&wop->wo_fdi); check_string_option(&wop->wo_fdm); @@ -6973,8 +6936,7 @@ winopt_T *wop UNUSED; /* * Free the allocated memory inside a winopt_T. */ -void clear_winopt(wop) -winopt_T *wop UNUSED; +void clear_winopt(winopt_T *wop) { clear_string_option(&wop->wo_fdi); clear_string_option(&wop->wo_fdm); @@ -6997,9 +6959,7 @@ winopt_T *wop UNUSED; * appropriate. * BCO_NOHELP Don't copy the values to a help buffer. */ -void buf_copy_options(buf, flags) -buf_T *buf; -int flags; +void buf_copy_options(buf_T *buf, int flags) { int should_copy = TRUE; char_u *save_p_isk = NULL; /* init for GCC */ @@ -7175,7 +7135,7 @@ int flags; /* * Reset the 'modifiable' option and its default value. */ -void reset_modifiable() { +void reset_modifiable(void) { int opt_idx; curbuf->b_p_ma = FALSE; @@ -7188,14 +7148,14 @@ void reset_modifiable() { /* * Set the global value for 'iminsert' to the local value. */ -void set_iminsert_global() { +void set_iminsert_global(void) { p_iminsert = curbuf->b_p_iminsert; } /* * Set the global value for 'imsearch' to the local value. */ -void set_imsearch_global() { +void set_imsearch_global(void) { p_imsearch = curbuf->b_p_imsearch; } @@ -7203,10 +7163,12 @@ static int expand_option_idx = -1; static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL}; static int expand_option_flags = 0; -void set_context_in_set_cmd(xp, arg, opt_flags) -expand_T *xp; -char_u *arg; -int opt_flags; /* OPT_GLOBAL and/or OPT_LOCAL */ +void +set_context_in_set_cmd ( + expand_T *xp, + char_u *arg, + int opt_flags /* OPT_GLOBAL and/or OPT_LOCAL */ +) { int nextchar; long_u flags = 0; /* init for GCC */ @@ -7373,11 +7335,7 @@ int opt_flags; /* OPT_GLOBAL and/or OPT_LOCAL */ return; } -int ExpandSettings(xp, regmatch, num_file, file) -expand_T *xp; -regmatch_T *regmatch; -int *num_file; -char_u ***file; +int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file) { int num_normal = 0; /* Nr of matching non-term-code settings */ int num_term = 0; /* Nr of matching terminal code settings */ @@ -7517,9 +7475,7 @@ char_u ***file; return OK; } -int ExpandOldSetting(num_file, file) -int *num_file; -char_u ***file; +int ExpandOldSetting(int *num_file, char_u ***file) { char_u *var = NULL; /* init for GCC */ char_u *buf; @@ -7576,9 +7532,11 @@ char_u ***file; * Get the value for the numeric or string option *opp in a nice format into * NameBuff[]. Must not be called with a hidden option! */ -static void option_value2string(opp, opt_flags) -struct vimoption *opp; -int opt_flags; /* OPT_GLOBAL and/or OPT_LOCAL */ +static void +option_value2string ( + struct vimoption *opp, + int opt_flags /* OPT_GLOBAL and/or OPT_LOCAL */ +) { char_u *varp; @@ -7615,9 +7573,7 @@ int opt_flags; /* OPT_GLOBAL and/or OPT_LOCAL */ * printed as a keyname. * "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'. */ -static int wc_use_keyname(varp, wcp) -char_u *varp; -long *wcp; +static int wc_use_keyname(char_u *varp, long *wcp) { if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm)) { *wcp = *(long *)varp; @@ -7655,9 +7611,7 @@ static void langmap_set_entry __ARGS((int from, int to)); * Search for an entry in "langmap_mapga" for "from". If found set the "to" * field. If not found insert a new entry at the appropriate location. */ -static void langmap_set_entry(from, to) -int from; -int to; +static void langmap_set_entry(int from, int to) { langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); int a = 0; @@ -7693,8 +7647,7 @@ int to; /* * Apply 'langmap' to multi-byte character "c" and return the result. */ -int langmap_adjust_mb(c) -int c; +int langmap_adjust_mb(int c) { langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); int a = 0; @@ -7714,7 +7667,7 @@ int c; return c; /* no entry found, return "c" unmodified */ } -static void langmap_init() { +static void langmap_init(void) { int i; for (i = 0; i < 256; i++) @@ -7726,7 +7679,7 @@ static void langmap_init() { * Called when langmap option is set; the language map can be * changed at any time! */ -static void langmap_set() { +static void langmap_set(void) { char_u *p; char_u *p2; int from, to; @@ -7804,8 +7757,7 @@ static void langmap_set() { * Return TRUE if format option 'x' is in effect. * Take care of no formatting when 'paste' is set. */ -int has_format_option(x) -int x; +int has_format_option(int x) { if (p_paste) return FALSE; @@ -7816,8 +7768,7 @@ int x; * Return TRUE if "x" is present in 'shortmess' option, or * 'shortmess' contains 'a' and "x" is present in SHM_A. */ -int shortmess(x) -int x; +int shortmess(int x) { return p_shm != NULL && ( vim_strchr(p_shm, x) != NULL @@ -7828,7 +7779,7 @@ int x; /* * paste_option_changed() - Called after p_paste was set or reset. */ -static void paste_option_changed() { +static void paste_option_changed(void) { static int old_p_paste = FALSE; static int save_sm = 0; static int save_ru = 0; @@ -7924,9 +7875,7 @@ static void paste_option_changed() { * Don't do this if the 'compatible' option has been set or reset before. * When "fname" is not NULL, use it to set $"envname" when it wasn't set yet. */ -void vimrc_found(fname, envname) -char_u *fname; -char_u *envname; +void vimrc_found(char_u *fname, char_u *envname) { int opt_idx; int dofree = FALSE; @@ -7957,8 +7906,7 @@ char_u *envname; /* * Set 'compatible' on or off. Called for "-C" and "-N" command line arg. */ -void change_compatible(on) -int on; +void change_compatible(int on) { int opt_idx; @@ -7975,8 +7923,7 @@ int on; * Return TRUE when option "name" has been set. * Only works correctly for global options. */ -int option_was_set(name) -char_u *name; +int option_was_set(char_u *name) { int idx; @@ -7991,8 +7938,7 @@ char_u *name; /* * Reset the flag indicating option "name" was set. */ -void reset_option_was_set(name) -char_u *name; +void reset_option_was_set(char_u *name) { int idx = findoption(name); @@ -8008,7 +7954,7 @@ char_u *name; * When 'compatible' is unset: Set all options that have a different default * for Vim (without the P_VI_DEF flag) to that default. */ -static void compatible_set() { +static void compatible_set(void) { int opt_idx; for (opt_idx = 0; !istermoption(&options[opt_idx]); opt_idx++) @@ -8021,7 +7967,7 @@ static void compatible_set() { /* * fill_breakat_flags() -- called when 'breakat' changes value. */ -static void fill_breakat_flags() { +static void fill_breakat_flags(void) { char_u *p; int i; @@ -8039,10 +7985,12 @@ static void fill_breakat_flags() { * Return OK for correct value, FAIL otherwise. * Empty is always OK. */ -static int check_opt_strings(val, values, list) -char_u *val; -char **values; -int list; /* when TRUE: accept a list of values */ +static int +check_opt_strings ( + char_u *val, + char **values, + int list /* when TRUE: accept a list of values */ +) { return opt_strings_flags(val, values, NULL, list); } @@ -8054,11 +8002,13 @@ int list; /* when TRUE: accept a list of values */ * Return OK for correct value, FAIL otherwise. * Empty is always OK. */ -static int opt_strings_flags(val, values, flagp, list) -char_u *val; /* new value */ -char **values; /* array of valid string values */ -unsigned *flagp; -int list; /* when TRUE: accept a list of values */ +static int +opt_strings_flags ( + char_u *val, /* new value */ + char **values, /* array of valid string values */ + unsigned *flagp, + int list /* when TRUE: accept a list of values */ +) { int i; int len; @@ -8087,7 +8037,7 @@ int list; /* when TRUE: accept a list of values */ /* * Read the 'wildmode' option, fill wim_flags[]. */ -static int check_opt_wim() { +static int check_opt_wim(void) { char_u new_wim_flags[4]; char_u *p; int i; @@ -8134,8 +8084,10 @@ static int check_opt_wim() { /* * Check if backspacing over something is allowed. */ -int can_bs(what) -int what; /* BS_INDENT, BS_EOL or BS_START */ +int +can_bs ( + int what /* BS_INDENT, BS_EOL or BS_START */ +) { switch (*p_bs) { case '2': return TRUE; @@ -8149,8 +8101,7 @@ int what; /* BS_INDENT, BS_EOL or BS_START */ * Save the current values of 'fileformat' and 'fileencoding', so that we know * the file must be considered changed when the value is different. */ -void save_file_ff(buf) -buf_T *buf; +void save_file_ff(buf_T *buf) { buf->b_start_ffc = *buf->b_p_ff; buf->b_start_eol = buf->b_p_eol; @@ -8172,9 +8123,7 @@ buf_T *buf; * When "ignore_empty" is true don't consider a new, empty buffer to be * changed. */ -int file_ff_differs(buf, ignore_empty) -buf_T *buf; -int ignore_empty; +int file_ff_differs(buf_T *buf, int ignore_empty) { /* In a buffer that was never loaded the options are not valid. */ if (buf->b_flags & BF_NEVERLOADED) @@ -8198,8 +8147,7 @@ int ignore_empty; /* * return OK if "p" is a valid fileformat name, FAIL otherwise. */ -int check_ff_value(p) -char_u *p; +int check_ff_value(char_u *p) { return check_opt_strings(p, p_ff_values, FALSE); } @@ -8208,8 +8156,7 @@ char_u *p; * Return the effective shiftwidth value for current buffer, using the * 'tabstop' value when 'shiftwidth' is zero. */ -long get_sw_value(buf) -buf_T *buf; +long get_sw_value(buf_T *buf) { return buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts; } @@ -8218,7 +8165,7 @@ buf_T *buf; * Return the effective softtabstop value for the current buffer, using the * 'tabstop' value when 'softtabstop' is negative. */ -long get_sts_value() { +long get_sts_value(void) { return curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts; } @@ -8228,11 +8175,7 @@ long get_sts_value() { * the opposite character. Set "*backwards" to the direction. * When "switchit" is TRUE swap the direction. */ -void find_mps_values(initc, findc, backwards, switchit) -int *initc; -int *findc; -int *backwards; -int switchit; +void find_mps_values(int *initc, int *findc, int *backwards, int switchit) { char_u *ptr; diff --git a/src/os_unix.c b/src/os_unix.c index 344be7b0df..8dbd512726 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -221,8 +221,7 @@ static struct signalinfo { {-1, "Unknown!", FALSE} }; -int mch_chdir(path) -char *path; +int mch_chdir(char *path) { if (p_verbose >= 5) { verbose_enter(); @@ -235,9 +234,7 @@ char *path; /* * Write s[len] to the screen. */ -void mch_write(s, len) -char_u *s; -int len; +void mch_write(char_u *s, int len) { ignored = (int)write(1, (char *)s, len); if (p_wd) /* Unix is too fast, slow down a bit more */ @@ -252,74 +249,75 @@ int len; * If wtime == n wait a short time for characters. * If wtime == -1 wait forever for characters. */ -int mch_inchar(buf, maxlen, wtime, tb_change_cnt) -char_u *buf; -int maxlen; -long wtime; /* don't use "time", MIPS cannot handle it */ -int tb_change_cnt; +int mch_inchar( + char_u *buf, + int maxlen, + long wtime, /* don't use "time", MIPS cannot handle it */ + int tb_change_cnt + ) { - int len; + int len; - /* Check if window changed size while we were busy, perhaps the ":set - * columns=99" command was used. */ - while (do_resize) - handle_resize(); + /* Check if window changed size while we were busy, perhaps the ":set + * columns=99" command was used. */ + while (do_resize) + handle_resize(); - if (wtime >= 0) { - while (WaitForChar(wtime) == 0) { /* no character available */ - if (!do_resize) /* return if not interrupted by resize */ - return 0; - handle_resize(); - } - } else { /* wtime == -1 */ - /* - * If there is no character available within 'updatetime' seconds - * flush all the swap files to disk. - * Also done when interrupted by SIGWINCH. - */ - if (WaitForChar(p_ut) == 0) { - if (trigger_cursorhold() && maxlen >= 3 - && !typebuf_changed(tb_change_cnt)) { - buf[0] = K_SPECIAL; - buf[1] = KS_EXTRA; - buf[2] = (int)KE_CURSORHOLD; - return 3; - } - before_blocking(); + if (wtime >= 0) { + while (WaitForChar(wtime) == 0) { /* no character available */ + if (!do_resize) /* return if not interrupted by resize */ + return 0; + handle_resize(); + } + } else { /* wtime == -1 */ + /* + * If there is no character available within 'updatetime' seconds + * flush all the swap files to disk. + * Also done when interrupted by SIGWINCH. + */ + if (WaitForChar(p_ut) == 0) { + if (trigger_cursorhold() && maxlen >= 3 + && !typebuf_changed(tb_change_cnt)) { + buf[0] = K_SPECIAL; + buf[1] = KS_EXTRA; + buf[2] = (int)KE_CURSORHOLD; + return 3; + } + before_blocking(); + } } - } - for (;; ) { /* repeat until we got a character */ - while (do_resize) /* window changed size */ - handle_resize(); + for (;; ) { /* repeat until we got a character */ + while (do_resize) /* window changed size */ + handle_resize(); - /* - * We want to be interrupted by the winch signal - * or by an event on the monitored file descriptors. - */ - if (WaitForChar(-1L) == 0) { - if (do_resize) /* interrupted by SIGWINCH signal */ - handle_resize(); - return 0; - } + /* + * We want to be interrupted by the winch signal + * or by an event on the monitored file descriptors. + */ + if (WaitForChar(-1L) == 0) { + if (do_resize) /* interrupted by SIGWINCH signal */ + handle_resize(); + return 0; + } - /* If input was put directly in typeahead buffer bail out here. */ - if (typebuf_changed(tb_change_cnt)) - return 0; + /* If input was put directly in typeahead buffer bail out here. */ + if (typebuf_changed(tb_change_cnt)) + return 0; - /* - * For some terminals we only get one character at a time. - * We want the get all available characters, so we could keep on - * trying until none is available - * For some other terminals this is quite slow, that's why we don't do - * it. - */ - len = read_from_input_buf(buf, (long)maxlen); - if (len > 0) { - return len; + /* + * For some terminals we only get one character at a time. + * We want the get all available characters, so we could keep on + * trying until none is available + * For some other terminals this is quite slow, that's why we don't do + * it. + */ + len = read_from_input_buf(buf, (long)maxlen); + if (len > 0) { + return len; + } } - } } static void handle_resize() { @@ -349,8 +347,7 @@ int mch_char_avail() { * Return total amount of memory available in Kbyte. * Doesn't change when memory has been allocated. */ -long_u mch_total_mem(special) -int special UNUSED; +long_u mch_total_mem(int special) { long_u mem = 0; long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */ @@ -430,9 +427,7 @@ int special UNUSED; } #endif -void mch_delay(msec, ignoreinput) -long msec; -int ignoreinput; +void mch_delay(long msec, int ignoreinput) { int old_tmode; @@ -508,8 +503,7 @@ static int stack_grows_downwards; * Find out if the stack grows upwards or downwards. * "p" points to a variable on the stack of the caller. */ -static void check_stack_growth(p) -char *p; +static void check_stack_growth(char *p) { int i; @@ -577,8 +571,7 @@ static void get_stack_limit() { * Return FAIL when running out of stack space. * "p" must point to any variable local to the caller that's on the stack. */ -int mch_stackcheck(p) -char *p; +int mch_stackcheck(char *p) { if (stack_limit != NULL) { if (stack_grows_downwards) { @@ -1005,9 +998,10 @@ void reset_signals() { #endif } -static void catch_signals(func_deadly, func_other) -RETSIGTYPE (*func_deadly)(); -RETSIGTYPE (*func_other)(); +static void catch_signals( + RETSIGTYPE (*func_deadly)(), + RETSIGTYPE (*func_other)() + ) { int i; @@ -1056,8 +1050,7 @@ RETSIGTYPE (*func_other)(); * signal * Returns TRUE when Vim should exit. */ -int vim_handle_signal(sig) -int sig; +int vim_handle_signal(int sig) { static int got_signal = 0; static int blocked = TRUE; @@ -1088,9 +1081,7 @@ int sig; /* * Check_win checks whether we have an interactive stdout. */ -int mch_check_win(argc, argv) -int argc UNUSED; -char **argv UNUSED; +int mch_check_win(int argc, char **argv) { if (isatty(1)) return OK; @@ -1106,14 +1097,12 @@ int mch_input_isatty() { return FALSE; } -static int get_x11_title(test_only) -int test_only UNUSED; +static int get_x11_title(int test_only) { return FALSE; } -static int get_x11_icon(test_only) -int test_only; +static int get_x11_icon(int test_only) { if (!test_only) { if (STRNCMP(T_NAME, "builtin_", 8) == 0) @@ -1136,9 +1125,7 @@ int mch_can_restore_icon() { /* * Set the window title and icon. */ -void mch_settitle(title, icon) -char_u *title; -char_u *icon; +void mch_settitle(char_u *title, char_u *icon) { int type = 0; static int recursive = 0; @@ -1195,8 +1182,7 @@ char_u *icon; * 2 only restore icon * 3 restore title and icon */ -void mch_restore_title(which) -int which; +void mch_restore_title(int which) { /* only restore the title or icon when it has been set */ mch_settitle(((which & 1) && did_set_title) ? @@ -1209,8 +1195,7 @@ int which; * Return TRUE if "name" looks like some xterm name. * Seiichi Sato mentioned that "mlterm" works like xterm. */ -int vim_is_xterm(name) -char_u *name; +int vim_is_xterm(char_u *name) { if (name == NULL) return FALSE; @@ -1227,8 +1212,7 @@ char_u *name; * known to support the xterm-style mouse protocol. * Relies on term_is_xterm having been set to its correct value. */ -int use_xterm_like_mouse(name) -char_u *name; +int use_xterm_like_mouse(char_u *name) { return name != NULL && (term_is_xterm || STRNICMP(name, "screen", 6) == 0); @@ -1253,8 +1237,7 @@ int use_xterm_mouse() { return 0; } -int vim_is_iris(name) -char_u *name; +int vim_is_iris(char_u *name) { if (name == NULL) return FALSE; @@ -1262,8 +1245,7 @@ char_u *name; || STRCMP(name, "builtin_iris-ansi") == 0; } -int vim_is_vt300(name) -char_u *name; +int vim_is_vt300(char_u *name) { if (name == NULL) return FALSE; /* actually all ANSI comp. terminals should be here */ @@ -1277,8 +1259,7 @@ char_u *name; * Return TRUE if "name" is a terminal for which 'ttyfast' should be set. * This should include all windowed terminal emulators. */ -int vim_is_fastterm(name) -char_u *name; +int vim_is_fastterm(char_u *name) { if (name == NULL) return FALSE; @@ -1294,9 +1275,7 @@ char_u *name; * Insert user name in s[len]. * Return OK if a name found. */ -int mch_get_user_name(s, len) -char_u *s; -int len; +int mch_get_user_name(char_u *s, int len) { return mch_get_uname(getuid(), s, len); } @@ -1305,10 +1284,7 @@ int len; * Insert user name for "uid" in s[len]. * Return OK if a name found. */ -int mch_get_uname(uid, s, len) -uid_t uid; -char_u *s; -int len; +int mch_get_uname(uid_t uid, char_u *s, int len) { #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) struct passwd *pw; @@ -1328,9 +1304,7 @@ int len; */ #ifdef HAVE_SYS_UTSNAME_H -void mch_get_host_name(s, len) -char_u *s; -int len; +void mch_get_host_name(char_u *s, int len) { struct utsname vutsname; @@ -1345,9 +1319,7 @@ int len; # define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len) # endif -void mch_get_host_name(s, len) -char_u *s; -int len; +void mch_get_host_name(char_u *s, int len) { gethostname((char *)s, len); s[len - 1] = NUL; /* make sure it's terminated */ @@ -1364,8 +1336,7 @@ long mch_get_pid() { #if !defined(HAVE_STRERROR) && defined(USE_GETCWD) static char *strerror __ARGS((int)); -static char * strerror(err) -int err; +static char * strerror(int err) { extern int sys_nerr; extern char *sys_errlist[]; @@ -1382,9 +1353,7 @@ int err; * Get name of current directory into buffer 'buf' of length 'len' bytes. * Return OK for success, FAIL for failure. */ -int mch_dirname(buf, len) -char_u *buf; -int len; +int mch_dirname(char_u *buf, int len) { #if defined(USE_GETCWD) if (getcwd((char *)buf, len) == NULL) { @@ -1403,10 +1372,12 @@ int len; * * return FAIL for failure, OK for success */ -int mch_FullName(fname, buf, len, force) -char_u *fname, *buf; -int len; -int force; /* also expand when already absolute path */ +int mch_FullName( + char_u *fname, + char_u *buf, + int len, + int force /* also expand when already absolute path */ + ) { int l; #ifdef HAVE_FCHDIR @@ -1512,8 +1483,7 @@ int force; /* also expand when already absolute path */ /* * Return TRUE if "fname" does not depend on the current directory. */ -int mch_isFullName(fname) -char_u *fname; +int mch_isFullName(char_u *fname) { return *fname == '/' || *fname == '~'; } @@ -1524,9 +1494,10 @@ char_u *fname; * file name to remain exactly the same. * Only required for file systems where case is ignored and preserved. */ -void fname_case(name, len) -char_u *name; -int len UNUSED; /* buffer size, only used when name gets longer */ +void fname_case( +char_u *name, +int len; /* buffer size, only used when name gets longer */ +) { struct stat st; char_u *slash, *tail; @@ -1578,8 +1549,7 @@ int len UNUSED; /* buffer size, only used when name gets longer */ * Get file permissions for 'name'. * Returns -1 when it doesn't exist. */ -long mch_getperm(name) -char_u *name; +long mch_getperm(char_u *name) { struct stat statb; @@ -1600,9 +1570,7 @@ char_u *name; * * return FAIL for failure, OK otherwise */ -int mch_setperm(name, perm) -char_u *name; -long perm; +int mch_setperm(char_u *name, long perm) { return chmod((char *) name, @@ -1622,9 +1590,7 @@ long perm; /* * Copy security info from "from_file" to "to_file". */ -void mch_copy_sec(from_file, to_file) -char_u *from_file; -char_u *to_file; +void mch_copy_sec(char_u *from_file, char_u *to_file) { if (from_file == NULL) return; @@ -1672,8 +1638,7 @@ char_u *to_file; * Return a pointer to the ACL of file "fname" in allocated memory. * Return NULL if the ACL is not available for whatever reason. */ -vim_acl_T mch_get_acl(fname) -char_u *fname UNUSED; +vim_acl_T mch_get_acl(char_u *fname) { vim_acl_T ret = NULL; return ret; @@ -1682,16 +1647,13 @@ char_u *fname UNUSED; /* * Set the ACL of file "fname" to "acl" (unless it's NULL). */ -void mch_set_acl(fname, aclent) -char_u *fname UNUSED; -vim_acl_T aclent; +void mch_set_acl(char_u *fname, vim_acl_T aclent) { if (aclent == NULL) return; } -void mch_free_acl(aclent) -vim_acl_T aclent; +void mch_free_acl(vim_acl_T aclent) { if (aclent == NULL) return; @@ -1701,8 +1663,7 @@ vim_acl_T aclent; /* * Set hidden flag for "name". */ -void mch_hide(name) -char_u *name UNUSED; +void mch_hide(char_u *name) { /* can't hide a file */ } @@ -1712,8 +1673,7 @@ char_u *name UNUSED; * return FALSE if "name" is not a directory * return FALSE for error */ -int mch_isdir(name) -char_u *name; +int mch_isdir(char_u *name) { struct stat statb; @@ -1733,8 +1693,7 @@ static int executable_file __ARGS((char_u *name)); /* * Return 1 if "name" is an executable file, 0 if not or it doesn't exist. */ -static int executable_file(name) -char_u *name; +static int executable_file(char_u *name) { struct stat st; @@ -1747,8 +1706,7 @@ char_u *name; * Return 1 if "name" can be found in $PATH and executed, 0 if not. * Return -1 if unknown. */ -int mch_can_exe(name) -char_u *name; +int mch_can_exe(char_u *name) { char_u *buf; char_u *p, *e; @@ -1801,8 +1759,7 @@ char_u *name; * NODE_WRITABLE: writable device, socket, fifo, etc. * NODE_OTHER: non-writable things */ -int mch_nodetype(name) -char_u *name; +int mch_nodetype(char_u *name) { struct stat st; @@ -1876,8 +1833,7 @@ static void exit_scroll() { } } -void mch_exit(r) -int r; +void mch_exit(int r) { exiting = TRUE; @@ -1934,8 +1890,7 @@ static void may_core_dump() { } } -void mch_settmode(tmode) -int tmode; +void mch_settmode(int tmode) { static int first = TRUE; @@ -2196,7 +2151,7 @@ void check_mouse_termcode() { * set screen mode, always fails. */ int mch_screenmode(arg) -char_u *arg UNUSED; +char_u *arg; { EMSG(_(e_screenmode)); return FAIL; @@ -3153,7 +3108,7 @@ long msec; static int RealWaitForChar(fd, msec, check_for_gpm) int fd; long msec; -int *check_for_gpm UNUSED; +int *check_for_gpm; { int ret; diff --git a/src/os_unix.h b/src/os_unix.h index f0fc3d5f9a..692bb3442b 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -81,7 +81,7 @@ # define SIGDUMMYARG 0, 0, (struct sigcontext *)0 # else # define SIGPROTOARG (int) -# define SIGDEFARG(s) (s) int s UNUSED; +# define SIGDEFARG(s) (s) int s; # define SIGDUMMYARG 0 # endif #else diff --git a/src/po/sjiscorr.c b/src/po/sjiscorr.c index fec4740c04..6976ed8b9e 100644 --- a/src/po/sjiscorr.c +++ b/src/po/sjiscorr.c @@ -1,15 +1,4 @@ -/* - * Simplistic program to correct SJIS inside strings. When a trail byte is a - * backslash it needs to be doubled. - * Public domain. - */ -#include -#include - - int -main(argc, argv) - int argc; - char **argv; +__END_DECLS int main(int argc, char **argv) { char buffer[BUFSIZ]; char *p; diff --git a/src/popupmnu.c b/src/popupmnu.c index ff28fc2676..be8c3ec0e0 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -40,11 +40,13 @@ static int pum_set_selected __ARGS((int n, int repeat)); * When possible the leftmost character is aligned with screen column "col". * The menu appears above the screen line "row" or at "row" + "height" - 1. */ -void pum_display(array, size, selected) -pumitem_T *array; -int size; -int selected; /* index of initially selected item, none if +void +pum_display ( + pumitem_T *array, + int size, + int selected /* index of initially selected item, none if out of range */ +) { int w; int def_width; @@ -231,7 +233,7 @@ redo: /* * Redraw the popup menu, using "pum_first" and "pum_selected". */ -void pum_redraw() { +void pum_redraw(void) { int row = pum_row; int col; int attr_norm = highlight_attr[HLF_PNI]; @@ -415,9 +417,7 @@ void pum_redraw() { * Returns TRUE when the window was resized and the location of the popup menu * must be recomputed. */ -static int pum_set_selected(n, repeat) -int n; -int repeat; +static int pum_set_selected(int n, int repeat) { int resized = FALSE; int context = pum_height / 2; @@ -584,7 +584,7 @@ int repeat; /* * Undisplay the popup menu (later). */ -void pum_undisplay() { +void pum_undisplay(void) { pum_array = NULL; redraw_all_later(SOME_VALID); redraw_tabline = TRUE; @@ -595,7 +595,7 @@ void pum_undisplay() { * Clear the popup menu. Currently only resets the offset to the first * displayed item. */ -void pum_clear() { +void pum_clear(void) { pum_first = 0; } @@ -603,7 +603,7 @@ void pum_clear() { * Return TRUE if the popup menu is displayed. * Overruled when "pum_do_redraw" is set, used to redraw the status lines. */ -int pum_visible() { +int pum_visible(void) { return !pum_do_redraw && pum_array != NULL; } @@ -611,7 +611,7 @@ int pum_visible() { * Return the height of the popup menu, the number of entries visible. * Only valid when pum_visible() returns TRUE! */ -int pum_get_height() { +int pum_get_height(void) { return pum_height; } diff --git a/src/quickfix.c b/src/quickfix.c index 28f3a469f6..5fa175c0cb 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -152,12 +152,14 @@ static qf_info_T *ll_get_or_alloc_list __ARGS((win_T *)); * list. Set the error list's title to qf_title. * Return -1 for error, number of errors for success. */ -int qf_init(wp, efile, errorformat, newlist, qf_title) -win_T *wp; -char_u *efile; -char_u *errorformat; -int newlist; /* TRUE: start a new error list */ -char_u *qf_title; +int +qf_init ( + win_T *wp, + char_u *efile, + char_u *errorformat, + int newlist, /* TRUE: start a new error list */ + char_u *qf_title +) { qf_info_T *qi = &ql_info; @@ -184,18 +186,18 @@ char_u *qf_title; * Set the title of the list to "qf_title". * Return -1 for error, number of errors for success. */ -static int qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, - lnumlast, - qf_title) -qf_info_T *qi; -char_u *efile; -buf_T *buf; -typval_T *tv; -char_u *errorformat; -int newlist; /* TRUE: start a new error list */ -linenr_T lnumfirst; /* first line number to use */ -linenr_T lnumlast; /* last line number to use */ -char_u *qf_title; +static int +qf_init_ext ( + qf_info_T *qi, + char_u *efile, + buf_T *buf, + typval_T *tv, + char_u *errorformat, + int newlist, /* TRUE: start a new error list */ + linenr_T lnumfirst, /* first line number to use */ + linenr_T lnumlast, /* last line number to use */ + char_u *qf_title +) { char_u *namebuf; char_u *errmsg; @@ -803,9 +805,7 @@ qf_init_end: /* * Prepare for adding a new quickfix list. */ -static void qf_new_list(qi, qf_title) -qf_info_T *qi; -char_u *qf_title; +static void qf_new_list(qf_info_T *qi, char_u *qf_title) { int i; @@ -841,8 +841,7 @@ char_u *qf_title; /* * Free a location list */ -static void ll_free_all(pqi) -qf_info_T **pqi; +static void ll_free_all(qf_info_T **pqi) { int i; qf_info_T *qi; @@ -861,8 +860,7 @@ qf_info_T **pqi; } } -void qf_free_all(wp) -win_T *wp; +void qf_free_all(win_T *wp) { int i; qf_info_T *qi = &ql_info; @@ -881,23 +879,22 @@ win_T *wp; * Add an entry to the end of the list of errors. * Returns OK or FAIL. */ -static int qf_add_entry(qi, prevp, dir, fname, bufnum, mesg, lnum, col, vis_col, - pattern, - nr, type, - valid) -qf_info_T *qi; /* quickfix list */ -qfline_T **prevp; /* pointer to previously added entry or NULL */ -char_u *dir; /* optional directory name */ -char_u *fname; /* file name or NULL */ -int bufnum; /* buffer number or zero */ -char_u *mesg; /* message */ -long lnum; /* line number */ -int col; /* column */ -int vis_col; /* using visual column */ -char_u *pattern; /* search pattern */ -int nr; /* error number */ -int type; /* type character */ -int valid; /* valid entry */ +static int +qf_add_entry ( + qf_info_T *qi, /* quickfix list */ + qfline_T **prevp, /* pointer to previously added entry or NULL */ + char_u *dir, /* optional directory name */ + char_u *fname, /* file name or NULL */ + int bufnum, /* buffer number or zero */ + char_u *mesg, /* message */ + long lnum, /* line number */ + int col, /* column */ + int vis_col, /* using visual column */ + char_u *pattern, /* search pattern */ + int nr, /* error number */ + int type, /* type character */ + int valid /* valid entry */ +) { qfline_T *qfp; @@ -952,7 +949,7 @@ int valid; /* valid entry */ /* * Allocate a new location list */ -static qf_info_T * ll_new_list() { +static qf_info_T *ll_new_list(void) { qf_info_T *qi; qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); @@ -968,8 +965,7 @@ static qf_info_T * ll_new_list() { * Return the location list for window 'wp'. * If not present, allocate a location list */ -static qf_info_T * ll_get_or_alloc_list(wp) -win_T *wp; +static qf_info_T *ll_get_or_alloc_list(win_T *wp) { if (IS_LL_WINDOW(wp)) /* For a location list window, use the referenced location list */ @@ -989,9 +985,7 @@ win_T *wp; /* * Copy the location list from window "from" to window "to". */ -void copy_loclist(from, to) -win_T *from; -win_T *to; +void copy_loclist(win_T *from, win_T *to) { qf_info_T *qi; int idx; @@ -1087,9 +1081,7 @@ win_T *to; /* * get buffer number for file "dir.name" */ -static int qf_get_fnum(directory, fname) -char_u *directory; -char_u *fname; +static int qf_get_fnum(char_u *directory, char_u *fname) { if (fname == NULL || *fname == NUL) /* no file name */ return 0; @@ -1131,9 +1123,7 @@ char_u *fname; * push dirbuf onto the directory stack and return pointer to actual dir or * NULL on error */ -static char_u * qf_push_dir(dirbuf, stackptr) -char_u *dirbuf; -struct dir_stack_T **stackptr; +static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) { struct dir_stack_T *ds_new; struct dir_stack_T *ds_ptr; @@ -1198,8 +1188,7 @@ struct dir_stack_T **stackptr; * pop dirbuf from the directory stack and return previous directory or NULL if * stack is empty */ -static char_u * qf_pop_dir(stackptr) -struct dir_stack_T **stackptr; +static char_u *qf_pop_dir(struct dir_stack_T **stackptr) { struct dir_stack_T *ds_ptr; @@ -1221,8 +1210,7 @@ struct dir_stack_T **stackptr; /* * clean up directory stack */ -static void qf_clean_dir_stack(stackptr) -struct dir_stack_T **stackptr; +static void qf_clean_dir_stack(struct dir_stack_T **stackptr) { struct dir_stack_T *ds_ptr; @@ -1253,8 +1241,7 @@ struct dir_stack_T **stackptr; * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. * qf_guess_filepath will return NULL. */ -static char_u * qf_guess_filepath(filename) -char_u *filename; +static char_u *qf_guess_filepath(char_u *filename) { struct dir_stack_T *ds_ptr; struct dir_stack_T *ds_tmp; @@ -1302,11 +1289,7 @@ char_u *filename; * else if "errornr" is zero, redisplay the same line * else go to entry "errornr" */ -void qf_jump(qi, dir, errornr, forceit) -qf_info_T *qi; -int dir; -int errornr; -int forceit; +void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit) { qf_info_T *ll_ref; qfline_T *qf_ptr; @@ -1734,8 +1717,7 @@ theend: * ":clist": list all errors * ":llist": list all locations */ -void qf_list(eap) -exarg_T *eap; +void qf_list(exarg_T *eap) { buf_T *buf; char_u *fname; @@ -1831,10 +1813,7 @@ exarg_T *eap; * Remove newlines and leading whitespace from an error message. * Put the result in "buf[bufsize]". */ -static void qf_fmt_text(text, buf, bufsize) -char_u *text; -char_u *buf; -int bufsize; +static void qf_fmt_text(char_u *text, char_u *buf, int bufsize) { int i; char_u *p = text; @@ -1857,8 +1836,7 @@ int bufsize; * ":lolder [count]": Up in the location list stack. * ":lnewer [count]": Down in the location list stack. */ -void qf_age(eap) -exarg_T *eap; +void qf_age(exarg_T *eap) { qf_info_T *qi = &ql_info; int count; @@ -1893,8 +1871,7 @@ exarg_T *eap; qf_msg(qi); } -static void qf_msg(qi) -qf_info_T *qi; +static void qf_msg(qf_info_T *qi) { smsg((char_u *)_("error list %d of %d; %d errors"), qi->qf_curlist + 1, qi->qf_listcount, @@ -1905,9 +1882,7 @@ qf_info_T *qi; /* * Free error list "idx". */ -static void qf_free(qi, idx) -qf_info_T *qi; -int idx; +static void qf_free(qf_info_T *qi, int idx) { qfline_T *qfp; int stop = FALSE; @@ -1935,12 +1910,7 @@ int idx; /* * qf_mark_adjust: adjust marks */ -void qf_mark_adjust(wp, line1, line2, amount, amount_after) -win_T *wp; -linenr_T line1; -linenr_T line2; -long amount; -long amount_after; +void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after) { int i; qfline_T *qfp; @@ -1983,8 +1953,7 @@ long amount_after; * other n " c n" * 1 x "" :helpgrep */ -static char_u * qf_types(c, nr) -int c, nr; +static char_u *qf_types(int c, int nr) { static char_u buf[20]; static char_u cc[3]; @@ -2018,8 +1987,7 @@ int c, nr; * ":lwindow": open the location list window if we have locations to display, * close it if not. */ -void ex_cwindow(eap) -exarg_T *eap; +void ex_cwindow(exarg_T *eap) { qf_info_T *qi = &ql_info; win_T *win; @@ -2051,8 +2019,7 @@ exarg_T *eap; * ":cclose": close the window showing the list of errors. * ":lclose": close the window showing the location list */ -void ex_cclose(eap) -exarg_T *eap; +void ex_cclose(exarg_T *eap) { win_T *win = NULL; qf_info_T *qi = &ql_info; @@ -2073,8 +2040,7 @@ exarg_T *eap; * ":copen": open a window that shows the list of errors. * ":lopen": open a window that shows the location list. */ -void ex_copen(eap) -exarg_T *eap; +void ex_copen(exarg_T *eap) { qf_info_T *qi = &ql_info; int height; @@ -2178,8 +2144,7 @@ exarg_T *eap; * Return the number of the current entry (line number in the quickfix * window). */ -linenr_T qf_current_entry(wp) -win_T *wp; +linenr_T qf_current_entry(win_T *wp) { qf_info_T *qi = &ql_info; @@ -2194,9 +2159,11 @@ win_T *wp; * Update the cursor position in the quickfix window to the current error. * Return TRUE if there is a quickfix window. */ -static int qf_win_pos_update(qi, old_qf_index) -qf_info_T *qi; -int old_qf_index; /* previous qf_index or zero */ +static int +qf_win_pos_update ( + qf_info_T *qi, + int old_qf_index /* previous qf_index or zero */ +) { win_T *win; int qf_index = qi->qf_lists[qi->qf_curlist].qf_index; @@ -2235,9 +2202,7 @@ int old_qf_index; /* previous qf_index or zero */ * Check whether the given window is displaying the specified quickfix/location * list buffer */ -static int is_qf_win(win, qi) -win_T *win; -qf_info_T *qi; +static int is_qf_win(win_T *win, qf_info_T *qi) { /* * A window displaying the quickfix buffer will have the w_llist_ref field @@ -2257,8 +2222,7 @@ qf_info_T *qi; * Find a window displaying the quickfix/location list 'qi' * Searches in only the windows opened in the current tab. */ -static win_T * qf_find_win(qi) -qf_info_T *qi; +static win_T *qf_find_win(qf_info_T *qi) { win_T *win; @@ -2273,8 +2237,7 @@ qf_info_T *qi; * Find a quickfix buffer. * Searches in windows opened in all the tabs. */ -static buf_T * qf_find_buf(qi) -qf_info_T *qi; +static buf_T *qf_find_buf(qf_info_T *qi) { tabpage_T *tp; win_T *win; @@ -2289,8 +2252,7 @@ qf_info_T *qi; /* * Find the quickfix buffer. If it exists, update the contents. */ -static void qf_update_buffer(qi) -qf_info_T *qi; +static void qf_update_buffer(qf_info_T *qi) { buf_T *buf; win_T *win; @@ -2321,8 +2283,7 @@ qf_info_T *qi; } } -static void qf_set_title(qi) -qf_info_T *qi; +static void qf_set_title(qf_info_T *qi) { set_internal_string_var((char_u *)"w:quickfix_title", qi->qf_lists[qi->qf_curlist].qf_title); @@ -2332,8 +2293,7 @@ qf_info_T *qi; * Fill current buffer with quickfix errors, replacing any previous contents. * curbuf must be the quickfix buffer! */ -static void qf_fill_buffer(qi) -qf_info_T *qi; +static void qf_fill_buffer(qf_info_T *qi) { linenr_T lnum; qfline_T *qfp; @@ -2423,8 +2383,7 @@ qf_info_T *qi; /* * Return TRUE if "buf" is the quickfix buffer. */ -int bt_quickfix(buf) -buf_T *buf; +int bt_quickfix(buf_T *buf) { return buf != NULL && buf->b_p_bt[0] == 'q'; } @@ -2433,8 +2392,7 @@ buf_T *buf; * Return TRUE if "buf" is a "nofile" or "acwrite" buffer. * This means the buffer name is not a file name. */ -int bt_nofile(buf) -buf_T *buf; +int bt_nofile(buf_T *buf) { return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') || buf->b_p_bt[0] == 'a'); @@ -2443,14 +2401,12 @@ buf_T *buf; /* * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. */ -int bt_dontwrite(buf) -buf_T *buf; +int bt_dontwrite(buf_T *buf) { return buf != NULL && buf->b_p_bt[0] == 'n'; } -int bt_dontwrite_msg(buf) -buf_T *buf; +int bt_dontwrite_msg(buf_T *buf) { if (bt_dontwrite(buf)) { EMSG(_("E382: Cannot write, 'buftype' option is set")); @@ -2463,8 +2419,7 @@ buf_T *buf; * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" * and 'bufhidden'. */ -int buf_hide(buf) -buf_T *buf; +int buf_hide(buf_T *buf) { /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ switch (buf->b_p_bh[0]) { @@ -2479,8 +2434,7 @@ buf_T *buf; /* * Return TRUE when using ":vimgrep" for ":grep". */ -int grep_internal(cmdidx) -cmdidx_T cmdidx; +int grep_internal(cmdidx_T cmdidx) { return (cmdidx == CMD_grep || cmdidx == CMD_lgrep @@ -2493,8 +2447,7 @@ cmdidx_T cmdidx; /* * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd" */ -void ex_make(eap) -exarg_T *eap; +void ex_make(exarg_T *eap) { char_u *fname; char_u *cmd; @@ -2591,7 +2544,7 @@ exarg_T *eap; * Find a new unique name when 'makeef' contains "##". * Returns NULL for error. */ -static char_u * get_mef_name() { +static char_u *get_mef_name(void) { char_u *p; char_u *name; static int start = -1; @@ -2643,8 +2596,7 @@ static char_u * get_mef_name() { * ":cc", ":crewind", ":cfirst" and ":clast". * ":ll", ":lrewind", ":lfirst" and ":llast". */ -void ex_cc(eap) -exarg_T *eap; +void ex_cc(exarg_T *eap) { qf_info_T *qi = &ql_info; @@ -2675,8 +2627,7 @@ exarg_T *eap; * ":cnext", ":cnfile", ":cNext" and ":cprevious". * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". */ -void ex_cnext(eap) -exarg_T *eap; +void ex_cnext(exarg_T *eap) { qf_info_T *qi = &ql_info; @@ -2708,8 +2659,7 @@ exarg_T *eap; * ":cfile"/":cgetfile"/":caddfile" commands. * ":lfile"/":lgetfile"/":laddfile" commands. */ -void ex_cfile(eap) -exarg_T *eap; +void ex_cfile(exarg_T *eap) { win_T *wp = NULL; qf_info_T *qi = &ql_info; @@ -2765,8 +2715,7 @@ exarg_T *eap; * ":lvimgrep {pattern} file(s)" * ":lvimgrepadd {pattern} file(s)" */ -void ex_vimgrep(eap) -exarg_T *eap; +void ex_vimgrep(exarg_T *eap) { regmmatch_T regmatch; int fcount; @@ -3103,10 +3052,7 @@ theend: * If "s" is not NULL terminate the pattern with a NUL. * Return a pointer to the char just past the pattern plus flags. */ -char_u * skip_vimgrep_pat(p, s, flags) -char_u *p; -char_u **s; -int *flags; +char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags) { int c; @@ -3149,8 +3095,7 @@ int *flags; * Restore current working directory to "dirname_start" if they differ, taking * into account whether it is set locally or globally. */ -static void restore_start_dir(dirname_start) -char_u *dirname_start; +static void restore_start_dir(char_u *dirname_start) { char_u *dirname_now = alloc(MAXPATHL); @@ -3181,10 +3126,12 @@ char_u *dirname_start; * * Returns NULL if it fails. */ -static buf_T * load_dummy_buffer(fname, dirname_start, resulting_dir) -char_u *fname; -char_u *dirname_start; /* in: old directory */ -char_u *resulting_dir; /* out: new directory */ +static buf_T * +load_dummy_buffer ( + char_u *fname, + char_u *dirname_start, /* in: old directory */ + char_u *resulting_dir /* out: new directory */ +) { buf_T *newbuf; buf_T *newbuf_to_wipe = NULL; @@ -3258,9 +3205,7 @@ char_u *resulting_dir; /* out: new directory */ * directory to "dirname_start" prior to returning, if autocmds or the * 'autochdir' option have changed it. */ -static void wipe_dummy_buffer(buf, dirname_start) -buf_T *buf; -char_u *dirname_start; +static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start) { if (curbuf != buf) { /* safety check */ cleanup_T cs; @@ -3285,9 +3230,7 @@ char_u *dirname_start; * directory to "dirname_start" prior to returning, if autocmds or the * 'autochdir' option have changed it. */ -static void unload_dummy_buffer(buf, dirname_start) -buf_T *buf; -char_u *dirname_start; +static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) { if (curbuf != buf) { /* safety check */ close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE); @@ -3300,9 +3243,7 @@ char_u *dirname_start; /* * Add each quickfix error to list "list" as a dictionary. */ -int get_errorlist(wp, list) -win_T *wp; -list_T *list; +int get_errorlist(win_T *wp, list_T *list) { qf_info_T *qi = &ql_info; dict_T *dict; @@ -3357,11 +3298,7 @@ list_T *list; * Populate the quickfix list with the items supplied in the list * of dictionaries. "title" will be copied to w:quickfix_title */ -int set_errorlist(wp, list, action, title) -win_T *wp; -list_T *list; -int action; -char_u *title; +int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) { listitem_T *li; dict_T *d; @@ -3473,8 +3410,7 @@ char_u *title; * ":[range]laddbuffer [bufnr]" command. * ":[range]lgetbuffer [bufnr]" command. */ -void ex_cbuffer(eap) -exarg_T *eap; +void ex_cbuffer(exarg_T *eap) { buf_T *buf = NULL; qf_info_T *qi = &ql_info; @@ -3527,8 +3463,7 @@ exarg_T *eap; * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command. * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command. */ -void ex_cexpr(eap) -exarg_T *eap; +void ex_cexpr(exarg_T *eap) { typval_T *tv; qf_info_T *qi = &ql_info; @@ -3562,8 +3497,7 @@ exarg_T *eap; /* * ":helpgrep {pattern}" */ -void ex_helpgrep(eap) -exarg_T *eap; +void ex_helpgrep(exarg_T *eap) { regmatch_T regmatch; char_u *save_cpo; diff --git a/src/regexp.c b/src/regexp.c index d1852f7ba9..de98543a11 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -255,16 +255,14 @@ static int no_Magic __ARGS((int x)); static int toggle_Magic __ARGS((int x)); -static int no_Magic(x) -int x; +static int no_Magic(int x) { if (is_Magic(x)) return un_Magic(x); return x; } -static int toggle_Magic(x) -int x; +static int toggle_Magic(int x) { if (is_Magic(x)) return un_Magic(x); @@ -376,8 +374,7 @@ static char_u e_empty_sb[] = N_("E70: Empty %s%%[]"); * Return MULTI_ONE if c is a single "multi" operator. * Return MULTI_MULT if c is a multi "multi" operator. */ -static int re_multi_type(c) -int c; +static int re_multi_type(int c) { if (c == Magic('@') || c == Magic('=') || c == Magic('?')) return MULTI_ONE; @@ -434,8 +431,7 @@ static void init_class_tab __ARGS((void)); /* * Translate '\x' to its control character, except "\n", which is Magic. */ -static int backslash_trans(c) -int c; +static int backslash_trans(int c) { switch (c) { case 'r': return CAR; @@ -451,8 +447,7 @@ int c; * Returns one of the CLASS_ items. CLASS_NONE means that no item was * recognized. Otherwise "pp" is advanced to after the item. */ -static int get_char_class(pp) -char_u **pp; +static int get_char_class(char_u **pp) { static const char *(class_names[]) = { @@ -518,7 +513,7 @@ static short class_tab[256]; #define RI_UPPER 0x80 #define RI_WHITE 0x100 -static void init_class_tab() { +static void init_class_tab(void) { int i; static int done = FALSE; @@ -687,8 +682,7 @@ static regengine_T nfa_regengine; /* * Return TRUE if compiled regular expression "prog" can match a line break. */ -int re_multiline(prog) -regprog_T *prog; +int re_multiline(regprog_T *prog) { return prog->regflags & RF_HASNL; } @@ -697,8 +691,7 @@ regprog_T *prog; * Return TRUE if compiled regular expression "prog" looks before the start * position (pattern contains "\@<=" or "\@regflags & RF_LOOKBH; } @@ -708,8 +701,7 @@ regprog_T *prog; * Returns a character representing the class. Zero means that no item was * recognized. Otherwise "pp" is advanced to after the item. */ -static int get_equi_class(pp) -char_u **pp; +static int get_equi_class(char_u **pp) { int c; int l = 1; @@ -736,8 +728,7 @@ char_u **pp; * Currently only handles latin1, latin9 and utf-8. * NOTE: When changing this function, also change nfa_emit_equi_class() */ -static void reg_equi_class(c) -int c; +static void reg_equi_class(int c) { if (enc_utf8 || STRCMP(p_enc, "latin1") == 0 || STRCMP(p_enc, "iso-8859-15") == 0) { @@ -1044,8 +1035,7 @@ int c; * "pp" is advanced to after the item. * Currently only single characters are recognized! */ -static int get_coll_element(pp) -char_u **pp; +static int get_coll_element(char_u **pp) { int c; int l = 1; @@ -1070,7 +1060,7 @@ static void get_cpo_flags __ARGS((void)); static int reg_cpo_lit; /* 'cpoptions' contains 'l' flag */ static int reg_cpo_bsl; /* 'cpoptions' contains '\' flag */ -static void get_cpo_flags() { +static void get_cpo_flags(void) { reg_cpo_lit = vim_strchr(p_cpo, CPO_LITERAL) != NULL; reg_cpo_bsl = vim_strchr(p_cpo, CPO_BACKSL) != NULL; } @@ -1080,8 +1070,7 @@ static void get_cpo_flags() { * "p" must point to the character after the '['. * The returned pointer is on the matching ']', or the terminating NUL. */ -static char_u * skip_anyof(p) -char_u *p; +static char_u *skip_anyof(char_u *p) { int l; @@ -1122,11 +1111,7 @@ char_u *p; * expression and change "\?" to "?". If "*newp" is not NULL the expression * is changed in-place. */ -char_u * skip_regexp(startp, dirc, magic, newp) -char_u *startp; -int dirc; -int magic; -char_u **newp; +char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp) { int mymagic; char_u *p = startp; @@ -1192,9 +1177,7 @@ static void bt_regfree __ARGS((regprog_T *prog)); * of the structure of the compiled regexp. * "re_flags": RE_MAGIC and/or RE_STRING. */ -static regprog_T * bt_regcomp(expr, re_flags) -char_u *expr; -int re_flags; +static regprog_T *bt_regcomp(char_u *expr, int re_flags) { bt_regprog_T *r; char_u *scan; @@ -1314,8 +1297,7 @@ int re_flags; /* * Free a compiled regexp program, returned by bt_regcomp(). */ -static void bt_regfree(prog) -regprog_T *prog; +static void bt_regfree(regprog_T *prog) { vim_free(prog); } @@ -1323,9 +1305,11 @@ regprog_T *prog; /* * Setup to parse the regexp. Used once to get the length and once to do it. */ -static void regcomp_start(expr, re_flags) -char_u *expr; -int re_flags; /* see vim_regcomp() */ +static void +regcomp_start ( + char_u *expr, + int re_flags /* see vim_regcomp() */ +) { initchr(expr); if (re_flags & RE_MAGIC) @@ -1351,7 +1335,7 @@ int re_flags; /* see vim_regcomp() */ * Check if during the previous call to vim_regcomp the EOL item "$" has been * found. This is messy, but it works fine. */ -int vim_regcomp_had_eol() { +int vim_regcomp_had_eol(void) { return had_eol; } @@ -1364,9 +1348,11 @@ int vim_regcomp_had_eol() { * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ -static char_u * reg(paren, flagp) -int paren; /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */ -int *flagp; +static char_u * +reg ( + int paren, /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */ + int *flagp +) { char_u *ret; char_u *br; @@ -1460,8 +1446,7 @@ int *flagp; * Parse one alternative of an | operator. * Implements the & operator. */ -static char_u * regbranch(flagp) -int *flagp; +static char_u *regbranch(int *flagp) { char_u *ret; char_u *chain = NULL; @@ -1501,8 +1486,7 @@ int *flagp; * Parse one alternative of an | or & operator. * Implements the concatenation operator. */ -static char_u * regconcat(flagp) -int *flagp; +static char_u *regconcat(int *flagp) { char_u *first = NULL; char_u *chain = NULL; @@ -1581,8 +1565,7 @@ int *flagp; * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ -static char_u * regpiece(flagp) -int *flagp; +static char_u *regpiece(int *flagp) { char_u *ret; int op; @@ -1728,8 +1711,7 @@ static int classcodes[] = { * it can turn them into a single node, which is smaller to store and * faster to run. Don't do this when one_exactly is set. */ -static char_u * regatom(flagp) -int *flagp; +static char_u *regatom(int *flagp) { char_u *ret; int flags; @@ -2427,8 +2409,7 @@ do_multibyte: * Return TRUE if MULTIBYTECODE should be used instead of EXACTLY for * character "c". */ -static int use_multibytecode(c) -int c; +static int use_multibytecode(int c) { return has_mbyte && (*mb_char2len)(c) > 1 && (re_multi_type(peekchr()) != NOT_MULTI @@ -2439,8 +2420,7 @@ int c; * Emit a node. * Return pointer to generated code. */ -static char_u * regnode(op) -int op; +static char_u *regnode(int op) { char_u *ret; @@ -2458,8 +2438,7 @@ int op; /* * Emit (if appropriate) a byte of code */ -static void regc(b) -int b; +static void regc(int b) { if (regcode == JUST_CALC_SIZE) regsize++; @@ -2470,8 +2449,7 @@ int b; /* * Emit (if appropriate) a multi-byte character of code */ -static void regmbc(c) -int c; +static void regmbc(int c) { if (!has_mbyte && c > 0xff) return; @@ -2486,9 +2464,7 @@ int c; * * Means relocating the operand. */ -static void reginsert(op, opnd) -int op; -char_u *opnd; +static void reginsert(int op, char_u *opnd) { char_u *src; char_u *dst; @@ -2514,10 +2490,7 @@ char_u *opnd; * Insert an operator in front of already-emitted operand. * Add a number to the operator. */ -static void reginsert_nr(op, val, opnd) -int op; -long val; -char_u *opnd; +static void reginsert_nr(int op, long val, char_u *opnd) { char_u *src; char_u *dst; @@ -2546,11 +2519,7 @@ char_u *opnd; * * Means relocating the operand. */ -static void reginsert_limits(op, minval, maxval, opnd) -int op; -long minval; -long maxval; -char_u *opnd; +static void reginsert_limits(int op, long minval, long maxval, char_u *opnd) { char_u *src; char_u *dst; @@ -2578,9 +2547,7 @@ char_u *opnd; /* * Write a long as four bytes at "p" and return pointer to the next char. */ -static char_u * re_put_long(p, val) -char_u *p; -long_u val; +static char_u *re_put_long(char_u *p, long_u val) { *p++ = (char_u) ((val >> 24) & 0377); *p++ = (char_u) ((val >> 16) & 0377); @@ -2592,9 +2559,7 @@ long_u val; /* * Set the next-pointer at the end of a node chain. */ -static void regtail(p, val) -char_u *p; -char_u *val; +static void regtail(char_u *p, char_u *val) { char_u *scan; char_u *temp; @@ -2630,9 +2595,7 @@ char_u *val; /* * Like regtail, on item after a BRANCH; nop if none. */ -static void regoptail(p, val) -char_u *p; -char_u *val; +static void regoptail(char_u *p, char_u *val) { /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */ if (p == NULL || p == JUST_CALC_SIZE @@ -2652,8 +2615,7 @@ static int prev_at_start; /* True when on the second character */ /* * Start parsing at "str". */ -static void initchr(str) -char_u *str; +static void initchr(char_u *str) { regparse = str; prevchr_len = 0; @@ -2666,8 +2628,7 @@ char_u *str; * Save the current parse state, so that it can be restored and parsing * starts in the same state again. */ -static void save_parse_state(ps) -parse_state_T *ps; +static void save_parse_state(parse_state_T *ps) { ps->regparse = regparse; ps->prevchr_len = prevchr_len; @@ -2683,8 +2644,7 @@ parse_state_T *ps; /* * Restore a previously saved parse state. */ -static void restore_parse_state(ps) -parse_state_T *ps; +static void restore_parse_state(parse_state_T *ps) { regparse = ps->regparse; prevchr_len = ps->prevchr_len; @@ -2701,7 +2661,7 @@ parse_state_T *ps; /* * Get the next character without advancing. */ -static int peekchr() { +static int peekchr(void) { static int after_slash = FALSE; if (curchr == -1) { @@ -2844,7 +2804,7 @@ static int peekchr() { /* * Eat one lexed character. Do this in a way that we can undo it. */ -static void skipchr() { +static void skipchr(void) { /* peekchr() eats a backslash, do the same here */ if (*regparse == '\\') prevchr_len = 1; @@ -2872,7 +2832,7 @@ static void skipchr() { * Skip a character while keeping the value of prev_at_start for at_start. * prevchr and prevprevchr are also kept. */ -static void skipchr_keepstart() { +static void skipchr_keepstart(void) { int as = prev_at_start; int pr = prevchr; int prpr = prevprevchr; @@ -2887,7 +2847,7 @@ static void skipchr_keepstart() { * Get the next character from the pattern. We know about magic and such, so * therefore we need a lexical analyzer. */ -static int getchr() { +static int getchr(void) { int chr = peekchr(); skipchr(); @@ -2897,7 +2857,7 @@ static int getchr() { /* * put character back. Works only once! */ -static void ungetchr() { +static void ungetchr(void) { nextchr = curchr; curchr = prevchr; prevchr = prevprevchr; @@ -2918,8 +2878,7 @@ static void ungetchr() { * The parameter controls the maximum number of input characters. This will be * 2 when reading a \%x20 sequence and 4 when reading a \%u20AC sequence. */ -static int gethexchrs(maxinputlen) -int maxinputlen; +static int gethexchrs(int maxinputlen) { int nr = 0; int c; @@ -2943,7 +2902,7 @@ int maxinputlen; * Get and return the value of the decimal string immediately after the * current position. Return -1 for invalid. Consumes all digits. */ -static int getdecchrs() { +static int getdecchrs(void) { int nr = 0; int c; int i; @@ -2971,7 +2930,7 @@ static int getdecchrs() { * blahblah\%o210asdf * before-^ ^-after */ -static int getoctchrs() { +static int getoctchrs(void) { int nr = 0; int c; int i; @@ -2994,7 +2953,7 @@ static int getoctchrs() { * Get a number after a backslash that is inside []. * When nothing is recognized return a backslash. */ -static int coll_get_char() { +static int coll_get_char(void) { int nr = -1; switch (*regparse++) { @@ -3019,9 +2978,7 @@ static int coll_get_char() { * Should end with 'end'. If minval is missing, zero is default, if maxval is * missing, a very big number is the default. */ -static int read_limits(minval, maxval) -long *minval; -long *maxval; +static int read_limits(long *minval, long *maxval) { int reverse = FALSE; char_u *first_char; @@ -3282,7 +3239,7 @@ static garray_T backpos = {0, 0, 0, 0, NULL}; #define BACKPOS_INITIAL 64 #if defined(EXITFREE) || defined(PROTO) -void free_regexp_stuff() { +void free_regexp_stuff(void) { ga_clear(®stack); ga_clear(&backpos); vim_free(reg_tofree); @@ -3294,8 +3251,7 @@ void free_regexp_stuff() { /* * Get pointer to the line "lnum", which is relative to "reg_firstlnum". */ -static char_u * reg_getline(lnum) -linenr_T lnum; +static char_u *reg_getline(linenr_T lnum) { /* when looking behind for a match/no-match lnum is negative. But we * can't go before line 1 */ @@ -3326,10 +3282,12 @@ static int bt_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); * * Return TRUE if there is a match, FALSE if not. */ -static int bt_regexec(rmp, line, col) -regmatch_T *rmp; -char_u *line; /* string to match against */ -colnr_T col; /* column to start looking for match */ +static int +bt_regexec ( + regmatch_T *rmp, + char_u *line, /* string to match against */ + colnr_T col /* column to start looking for match */ +) { reg_match = rmp; reg_mmatch = NULL; @@ -3351,10 +3309,12 @@ static int bt_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); /* * Like vim_regexec(), but consider a "\n" in "line" to be a line break. */ -static int bt_regexec_nl(rmp, line, col) -regmatch_T *rmp; -char_u *line; /* string to match against */ -colnr_T col; /* column to start looking for match */ +static int +bt_regexec_nl ( + regmatch_T *rmp, + char_u *line, /* string to match against */ + colnr_T col /* column to start looking for match */ +) { reg_match = rmp; reg_mmatch = NULL; @@ -3414,7 +3374,7 @@ proftime_T *tm; /* timeout limit or NULL */ static long bt_regexec_both(line, col, tm) char_u *line; colnr_T col; /* column to start looking for match */ -proftime_T *tm UNUSED; /* timeout limit or NULL */ +proftime_T *tm; /* timeout limit or NULL */ { bt_regprog_T *prog; char_u *s; @@ -3602,7 +3562,7 @@ static reg_extmatch_T *make_extmatch __ARGS((void)); /* * Create a new extmatch and mark it as referenced once. */ -static reg_extmatch_T * make_extmatch() { +static reg_extmatch_T *make_extmatch(void) { reg_extmatch_T *em; em = (reg_extmatch_T *)alloc_clear((unsigned)sizeof(reg_extmatch_T)); @@ -3614,8 +3574,7 @@ static reg_extmatch_T * make_extmatch() { /* * Add a reference to an extmatch. */ -reg_extmatch_T * ref_extmatch(em) -reg_extmatch_T *em; +reg_extmatch_T *ref_extmatch(reg_extmatch_T *em) { if (em != NULL) em->refcnt++; @@ -3626,8 +3585,7 @@ reg_extmatch_T *em; * Remove a reference to an extmatch. If there are no references left, free * the info. */ -void unref_extmatch(em) -reg_extmatch_T *em; +void unref_extmatch(reg_extmatch_T *em) { int i; @@ -3642,9 +3600,7 @@ reg_extmatch_T *em; * regtry - try match of "prog" with at regline["col"]. * Returns 0 for failure, number of lines contained in the match otherwise. */ -static long regtry(prog, col) -bt_regprog_T *prog; -colnr_T col; +static long regtry(bt_regprog_T *prog, colnr_T col) { reginput = regline + col; need_clear_subexpr = TRUE; @@ -3707,7 +3663,7 @@ static int reg_prev_class __ARGS((void)); /* * Get class of previous character. */ -static int reg_prev_class() { +static int reg_prev_class(void) { if (reginput > regline) return mb_get_class_buf(reginput - 1 - (*mb_head_off)(regline, reginput - 1), reg_buf); @@ -3719,7 +3675,7 @@ static int reg_match_visual __ARGS((void)); /* * Return TRUE if the current reginput position matches the Visual area. */ -static int reg_match_visual() { +static int reg_match_visual(void) { pos_T top, bot; linenr_T lnum; colnr_T col; @@ -3802,8 +3758,10 @@ static long bl_maxval; * Returns FALSE when there is no match. Leaves reginput and reglnum in an * undefined state! */ -static int regmatch(scan) -char_u *scan; /* Current node. */ +static int +regmatch ( + char_u *scan /* Current node. */ +) { char_u *next; /* Next node. */ int op; @@ -5103,9 +5061,7 @@ char_u *scan; /* Current node. */ * Push an item onto the regstack. * Returns pointer to new item. Returns NULL when out of memory. */ -static regitem_T * regstack_push(state, scan) -regstate_T state; -char_u *scan; +static regitem_T *regstack_push(regstate_T state, char_u *scan) { regitem_T *rp; @@ -5127,8 +5083,7 @@ char_u *scan; /* * Pop an item from the regstack. */ -static void regstack_pop(scan) -char_u **scan; +static void regstack_pop(char_u **scan) { regitem_T *rp; @@ -5142,9 +5097,11 @@ char_u **scan; * regrepeat - repeatedly match something simple, return how many. * Advances reginput (and reglnum) to just after the matched chars. */ -static int regrepeat(p, maxcount) -char_u *p; -long maxcount; /* maximum number of matches allowed */ +static int +regrepeat ( + char_u *p, + long maxcount /* maximum number of matches allowed */ +) { long count = 0; char_u *scan; @@ -5486,8 +5443,7 @@ do_class: * Returns NULL when calculating size, when there is no next item and when * there is an error. */ -static char_u * regnext(p) -char_u *p; +static char_u *regnext(char_u *p) { int offset; @@ -5508,7 +5464,7 @@ char_u *p; * Check the regexp program for its magic number. * Return TRUE if it's wrong. */ -static int prog_magic_wrong() { +static int prog_magic_wrong(void) { regprog_T *prog; prog = REG_MULTI ? reg_mmatch->regprog : reg_match->regprog; @@ -5528,7 +5484,7 @@ static int prog_magic_wrong() { * This construction is used to clear the subexpressions only when they are * used (to increase speed). */ -static void cleanup_subexpr() { +static void cleanup_subexpr(void) { if (need_clear_subexpr) { if (REG_MULTI) { /* Use 0xff to set lnum to -1 */ @@ -5542,7 +5498,7 @@ static void cleanup_subexpr() { } } -static void cleanup_zsubexpr() { +static void cleanup_zsubexpr(void) { if (need_clear_zsubexpr) { if (REG_MULTI) { /* Use 0xff to set lnum to -1 */ @@ -5560,8 +5516,7 @@ static void cleanup_zsubexpr() { * Save the current subexpr to "bp", so that they can be restored * later by restore_subexpr(). */ -static void save_subexpr(bp) -regbehind_T *bp; +static void save_subexpr(regbehind_T *bp) { int i; @@ -5584,8 +5539,7 @@ regbehind_T *bp; /* * Restore the subexpr from "bp". */ -static void restore_subexpr(bp) -regbehind_T *bp; +static void restore_subexpr(regbehind_T *bp) { int i; @@ -5607,7 +5561,7 @@ regbehind_T *bp; /* * Advance reglnum, regline and reginput to the next line. */ -static void reg_nextline() { +static void reg_nextline(void) { regline = reg_getline(++reglnum); reginput = regline; fast_breakcheck(); @@ -5616,9 +5570,7 @@ static void reg_nextline() { /* * Save the input line and position in a regsave_T. */ -static void reg_save(save, gap) -regsave_T *save; -garray_T *gap; +static void reg_save(regsave_T *save, garray_T *gap) { if (REG_MULTI) { save->rs_u.pos.col = (colnr_T)(reginput - regline); @@ -5631,9 +5583,7 @@ garray_T *gap; /* * Restore the input line and position from a regsave_T. */ -static void reg_restore(save, gap) -regsave_T *save; -garray_T *gap; +static void reg_restore(regsave_T *save, garray_T *gap) { if (REG_MULTI) { if (reglnum != save->rs_u.pos.lnum) { @@ -5651,8 +5601,7 @@ garray_T *gap; /* * Return TRUE if current position is equal to saved position. */ -static int reg_save_equal(save) -regsave_T *save; +static int reg_save_equal(regsave_T *save) { if (REG_MULTI) return reglnum == save->rs_u.pos.lnum @@ -5667,18 +5616,14 @@ regsave_T *save; * Use se_save() to use pointer (save_se_multi()) or position (save_se_one()), * depending on REG_MULTI. */ -static void save_se_multi(savep, posp) -save_se_T *savep; -lpos_T *posp; +static void save_se_multi(save_se_T *savep, lpos_T *posp) { savep->se_u.pos = *posp; posp->lnum = reglnum; posp->col = (colnr_T)(reginput - regline); } -static void save_se_one(savep, pp) -save_se_T *savep; -char_u **pp; +static void save_se_one(save_se_T *savep, char_u **pp) { savep->se_u.ptr = *pp; *pp = reginput; @@ -5687,9 +5632,7 @@ char_u **pp; /* * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL. */ -static int re_num_cmp(val, scan) -long_u val; -char_u *scan; +static int re_num_cmp(long_u val, char_u *scan) { long_u n = OPERAND_MIN(scan); @@ -5706,12 +5649,7 @@ char_u *scan; * If "bytelen" is not NULL, it is set to the byte length of the match in the * last line. */ -static int match_with_backref(start_lnum, start_col, end_lnum, end_col, bytelen) -linenr_T start_lnum; -colnr_T start_col; -linenr_T end_lnum; -colnr_T end_col; -int *bytelen; +static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T end_lnum, colnr_T end_col, int *bytelen) { linenr_T clnum = start_lnum; colnr_T ccol = start_col; @@ -5774,9 +5712,7 @@ int *bytelen; /* * regdump - dump a regexp onto stdout in vaguely comprehensible form */ -static void regdump(pattern, r) -char_u *pattern; -bt_regprog_T *r; +static void regdump(char_u *pattern, bt_regprog_T *r) { char_u *s; int op = EXACTLY; /* Arbitrary non-END op. */ @@ -5857,8 +5793,7 @@ bt_regprog_T *r; /* * regprop - printable representation of opcode */ -static char_u * regprop(op) -char_u *op; +static char_u *regprop(char_u *op) { char *p; static char buf[50]; @@ -6265,21 +6200,21 @@ static decomp_T decomp_table[0xfb4f-0xfb20+1] = {0x5d4, 0x5bc, 0}, /* 0xfb34 he+dagesh */ {0x5d5, 0x5bc, 0}, /* 0xfb35 vav+dagesh */ {0x5d6, 0x5bc, 0}, /* 0xfb36 zayin+dagesh */ - {0xfb37, 0, 0}, /* 0xfb37 -- UNUSED */ + {0xfb37, 0, 0}, /* 0xfb37 -- */ {0x5d8, 0x5bc, 0}, /* 0xfb38 tet+dagesh */ {0x5d9, 0x5bc, 0}, /* 0xfb39 yud+dagesh */ {0x5da, 0x5bc, 0}, /* 0xfb3a kaf sofit+dagesh */ {0x5db, 0x5bc, 0}, /* 0xfb3b kaf+dagesh */ {0x5dc, 0x5bc, 0}, /* 0xfb3c lamed+dagesh */ - {0xfb3d, 0, 0}, /* 0xfb3d -- UNUSED */ + {0xfb3d, 0, 0}, /* 0xfb3d -- */ {0x5de, 0x5bc, 0}, /* 0xfb3e mem+dagesh */ - {0xfb3f, 0, 0}, /* 0xfb3f -- UNUSED */ + {0xfb3f, 0, 0}, /* 0xfb3f -- */ {0x5e0, 0x5bc, 0}, /* 0xfb40 nun+dagesh */ {0x5e1, 0x5bc, 0}, /* 0xfb41 samech+dagesh */ - {0xfb42, 0, 0}, /* 0xfb42 -- UNUSED */ + {0xfb42, 0, 0}, /* 0xfb42 -- */ {0x5e3, 0x5bc, 0}, /* 0xfb43 pe sofit+dagesh */ {0x5e4, 0x5bc,0}, /* 0xfb44 pe+dagesh */ - {0xfb45, 0, 0}, /* 0xfb45 -- UNUSED */ + {0xfb45, 0, 0}, /* 0xfb45 -- */ {0x5e6, 0x5bc, 0}, /* 0xfb46 tsadi+dagesh */ {0x5e7, 0x5bc, 0}, /* 0xfb47 qof+dagesh */ {0x5e8, 0x5bc, 0}, /* 0xfb48 resh+dagesh */ @@ -6292,8 +6227,7 @@ static decomp_T decomp_table[0xfb4f-0xfb20+1] = {0x5d0, 0x5dc, 0} /* 0xfb4f alef-lamed */ }; -static void mb_decompose(c, c1, c2, c3) -int c, *c1, *c2, *c3; +static void mb_decompose(int c, int *c1, int *c2, int *c3) { decomp_T d; @@ -6313,9 +6247,7 @@ int c, *c1, *c2, *c3; * Return 0 if strings match, non-zero otherwise. * Correct the length "*n" when composing characters are ignored. */ -static int cstrncmp(s1, s2, n) -char_u *s1, *s2; -int *n; +static int cstrncmp(char_u *s1, char_u *s2, int *n) { int result; @@ -6363,9 +6295,7 @@ int *n; /* * cstrchr: This function is used a lot for simple searches, keep it fast! */ -static char_u * cstrchr(s, c) -char_u *s; -int c; +static char_u *cstrchr(char_u *s, int c) { char_u *p; int cc; @@ -6475,9 +6405,7 @@ int c; * * The tildes are parsed once before the first call to vim_regsub(). */ -char_u * regtilde(source, magic) -char_u *source; -int magic; +char_u *regtilde(char_u *source, int magic) { char_u *newsub = source; char_u *tmpsub; @@ -6557,13 +6485,7 @@ static int submatch_line_lbr; * * Returns the size of the replacement, including terminating NUL. */ -int vim_regsub(rmp, source, dest, copy, magic, backslash) -regmatch_T *rmp; -char_u *source; -char_u *dest; -int copy; -int magic; -int backslash; +int vim_regsub(regmatch_T *rmp, char_u *source, char_u *dest, int copy, int magic, int backslash) { reg_match = rmp; reg_mmatch = NULL; @@ -6572,14 +6494,7 @@ int backslash; return vim_regsub_both(source, dest, copy, magic, backslash); } -int vim_regsub_multi(rmp, lnum, source, dest, copy, magic, backslash) -regmmatch_T *rmp; -linenr_T lnum; -char_u *source; -char_u *dest; -int copy; -int magic; -int backslash; +int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash) { reg_match = NULL; reg_mmatch = rmp; @@ -6589,12 +6504,7 @@ int backslash; return vim_regsub_both(source, dest, copy, magic, backslash); } -static int vim_regsub_both(source, dest, copy, magic, backslash) -char_u *source; -char_u *dest; -int copy; -int magic; -int backslash; +static int vim_regsub_both(char_u *source, char_u *dest, int copy, int magic, int backslash) { char_u *src; char_u *dst; @@ -6902,8 +6812,7 @@ static char_u *reg_getline_submatch __ARGS((linenr_T lnum)); * substitute() was used the reg_maxline and other values have been * overwritten. */ -static char_u * reg_getline_submatch(lnum) -linenr_T lnum; +static char_u *reg_getline_submatch(linenr_T lnum) { char_u *s; linenr_T save_first = reg_firstlnum; @@ -6924,8 +6833,7 @@ linenr_T lnum; * allocated memory. * Returns NULL when not in a ":s" command and for a non-existing submatch. */ -char_u * reg_submatch(no) -int no; +char_u *reg_submatch(int no) { char_u *retval = NULL; char_u *s; @@ -7054,9 +6962,7 @@ static char_u regname[][30] = { * Use vim_regfree() to free the memory. * Returns NULL for an error. */ -regprog_T * vim_regcomp(expr_arg, re_flags) -char_u *expr_arg; -int re_flags; +regprog_T *vim_regcomp(char_u *expr_arg, int re_flags) { regprog_T *prog = NULL; char_u *expr = expr_arg; @@ -7122,8 +7028,7 @@ int re_flags; /* * Free a compiled regexp program, returned by vim_regcomp(). */ -void vim_regfree(prog) -regprog_T *prog; +void vim_regfree(regprog_T *prog) { if (prog != NULL) prog->engine->regfree(prog); @@ -7136,10 +7041,12 @@ regprog_T *prog; * * Return TRUE if there is a match, FALSE if not. */ -int vim_regexec(rmp, line, col) -regmatch_T *rmp; -char_u *line; /* string to match against */ -colnr_T col; /* column to start looking for match */ +int +vim_regexec ( + regmatch_T *rmp, + char_u *line, /* string to match against */ + colnr_T col /* column to start looking for match */ +) { return rmp->regprog->engine->regexec(rmp, line, col); } @@ -7149,10 +7056,7 @@ colnr_T col; /* column to start looking for match */ /* * Like vim_regexec(), but consider a "\n" in "line" to be a line break. */ -int vim_regexec_nl(rmp, line, col) -regmatch_T *rmp; -char_u *line; -colnr_T col; +int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col) { return rmp->regprog->engine->regexec_nl(rmp, line, col); } diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index 96d6a01a90..50e193924a 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -327,9 +327,11 @@ static int failure_chance __ARGS((nfa_state_T *state, int depth)); * Initialize internal variables before NFA compilation. * Return OK on success, FAIL otherwise. */ -static int nfa_regcomp_start(expr, re_flags) -char_u *expr; -int re_flags; /* see vim_regcomp() */ +static int +nfa_regcomp_start ( + char_u *expr, + int re_flags /* see vim_regcomp() */ +) { size_t postfix_size; int nstate_max; @@ -364,9 +366,7 @@ int re_flags; /* see vim_regcomp() */ * Figure out if the NFA state list starts with an anchor, must match at start * of the line. */ -static int nfa_get_reganch(start, depth) -nfa_state_T *start; -int depth; +static int nfa_get_reganch(nfa_state_T *start, int depth) { nfa_state_T *p = start; @@ -423,9 +423,7 @@ int depth; * Figure out if the NFA state list starts with a character which must match * at start of the match. */ -static int nfa_get_regstart(start, depth) -nfa_state_T *start; -int depth; +static int nfa_get_regstart(nfa_state_T *start, int depth) { nfa_state_T *p = start; @@ -504,8 +502,7 @@ int depth; * else. If so return a string in allocated memory with what must match after * regstart. Otherwise return NULL. */ -static char_u * nfa_get_match_text(start) -nfa_state_T *start; +static char_u *nfa_get_match_text(nfa_state_T *start) { nfa_state_T *p = start; int len = 0; @@ -543,7 +540,7 @@ nfa_state_T *start; * Allocate more space for post_start. Called when * running above the estimated number of states. */ -static int realloc_post_list() { +static int realloc_post_list(void) { int nstate_max = (int)(post_end - post_start); int new_max = nstate_max + 1000; int *new_start; @@ -571,10 +568,7 @@ static int realloc_post_list() { * Keep in mind that 'ignorecase' applies at execution time, thus [a-z] may * need to be interpreted as [a-zA-Z]. */ -static int nfa_recognize_char_class(start, end, extra_newl) -char_u *start; -char_u *end; -int extra_newl; +static int nfa_recognize_char_class(char_u *start, char_u *end, int extra_newl) { # define CLASS_not 0x80 # define CLASS_af 0x40 @@ -696,8 +690,7 @@ int extra_newl; * * NOTE! When changing this function, also update reg_equi_class() */ -static int nfa_emit_equi_class(c) -int c; +static int nfa_emit_equi_class(int c) { #define EMIT2(c) EMIT(c); EMIT(NFA_CONCAT); # define EMITMBC(c) EMIT(c); EMIT(NFA_CONCAT); @@ -1061,7 +1054,7 @@ int c; * or \%( pattern \) * or \z( pattern \) */ -static int nfa_regatom() { +static int nfa_regatom(void) { int c; int charclass; int equiclass; @@ -1740,7 +1733,7 @@ nfa_do_multibyte: * piece ::= atom * or atom multi */ -static int nfa_regpiece() { +static int nfa_regpiece(void) { int i; int op; int ret; @@ -1931,7 +1924,7 @@ static int nfa_regpiece() { * or piece piece piece * etc. */ -static int nfa_regconcat() { +static int nfa_regconcat(void) { int cont = TRUE; int first = TRUE; @@ -2003,7 +1996,7 @@ static int nfa_regconcat() { * or concat \& concat \& concat * etc. */ -static int nfa_regbranch() { +static int nfa_regbranch(void) { int ch; int old_post_pos; @@ -2047,8 +2040,10 @@ static int nfa_regbranch() { * or branch \| branch \| branch * etc. */ -static int nfa_reg(paren) -int paren; /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */ +static int +nfa_reg ( + int paren /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */ +) { int parno = 0; @@ -2101,8 +2096,7 @@ int paren; /* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */ #ifdef REGEXP_DEBUG static char_u code[50]; -static void nfa_set_code(c) -int c; +static void nfa_set_code(int c) { int addnl = FALSE; @@ -2330,9 +2324,7 @@ static FILE *log_fd; /* * Print the postfix notation of the current regexp. */ -static void nfa_postfix_dump(expr, retval) -char_u *expr; -int retval; +static void nfa_postfix_dump(char_u *expr, int retval) { int *p; FILE *f; @@ -2360,9 +2352,7 @@ int retval; /* * Print the NFA starting with a root node "state". */ -static void nfa_print_state(debugf, state) -FILE *debugf; -nfa_state_T *state; +static void nfa_print_state(FILE *debugf, nfa_state_T *state) { garray_T indent; @@ -2372,10 +2362,7 @@ nfa_state_T *state; ga_clear(&indent); } -static void nfa_print_state2(debugf, state, indent) -FILE *debugf; -nfa_state_T *state; -garray_T *indent; +static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent) { char_u *p; @@ -2433,8 +2420,7 @@ garray_T *indent; /* * Print the NFA state machine. */ -static void nfa_dump(prog) -nfa_regprog_T *prog; +static void nfa_dump(nfa_regprog_T *prog) { FILE *debugf = fopen(NFA_REGEXP_DUMP_LOG, "a"); @@ -2459,7 +2445,7 @@ nfa_regprog_T *prog; * Parse r.e. @expr and convert it into postfix form. * Return the postfix string on success, NULL otherwise. */ -static int * re2post() { +static int *re2post(void) { if (nfa_reg(REG_NOPAREN) == FAIL) return NULL; EMIT(NFA_MOPEN); @@ -2480,10 +2466,7 @@ static nfa_state_T *state_ptr; /* points to nfa_prog->state */ /* * Allocate and initialize nfa_state_T. */ -static nfa_state_T * alloc_state(c, out, out1) -int c; -nfa_state_T *out; -nfa_state_T *out1; +static nfa_state_T *alloc_state(int c, nfa_state_T *out, nfa_state_T *out1) { nfa_state_T *s; @@ -2536,9 +2519,7 @@ static Frag_T st_pop __ARGS((Frag_T **p, Frag_T *stack)); /* * Initialize a Frag_T struct and return it. */ -static Frag_T frag(start, out) -nfa_state_T *start; -Ptrlist *out; +static Frag_T frag(nfa_state_T *start, Ptrlist *out) { Frag_T n; @@ -2550,8 +2531,7 @@ Ptrlist *out; /* * Create singleton list containing just outp. */ -static Ptrlist * list1(outp) -nfa_state_T **outp; +static Ptrlist *list1(nfa_state_T **outp) { Ptrlist *l; @@ -2563,9 +2543,7 @@ nfa_state_T **outp; /* * Patch the list of states at out to point to start. */ -static void patch(l, s) -Ptrlist *l; -nfa_state_T *s; +static void patch(Ptrlist *l, nfa_state_T *s) { Ptrlist *next; @@ -2579,9 +2557,7 @@ nfa_state_T *s; /* * Join the two lists l1 and l2, returning the combination. */ -static Ptrlist * append(l1, l2) -Ptrlist *l1; -Ptrlist *l2; +static Ptrlist *append(Ptrlist *l1, Ptrlist *l2) { Ptrlist *oldl1; @@ -2597,10 +2573,7 @@ Ptrlist *l2; */ static Frag_T empty; -static void st_error(postfix, end, p) -int *postfix UNUSED; -int *end UNUSED; -int *p UNUSED; +static void st_error(int *postfix, int *end, int *p) { #ifdef NFA_REGEXP_ERROR_LOG FILE *df; @@ -2643,10 +2616,7 @@ int *p UNUSED; /* * Push an item onto the stack. */ -static void st_push(s, p, stack_end) -Frag_T s; -Frag_T **p; -Frag_T *stack_end; +static void st_push(Frag_T s, Frag_T **p, Frag_T *stack_end) { Frag_T *stackp = *p; @@ -2659,9 +2629,7 @@ Frag_T *stack_end; /* * Pop an item from the stack. */ -static Frag_T st_pop(p, stack) -Frag_T **p; -Frag_T *stack; +static Frag_T st_pop(Frag_T **p, Frag_T *stack) { Frag_T *stackp; @@ -2676,9 +2644,7 @@ Frag_T *stack; * Estimate the maximum byte length of anything matching "state". * When unknown or unlimited return -1. */ -static int nfa_max_width(startstate, depth) -nfa_state_T *startstate; -int depth; +static int nfa_max_width(nfa_state_T *startstate, int depth) { int l, r; nfa_state_T *state = startstate; @@ -2888,10 +2854,7 @@ int depth; * Convert a postfix form into its equivalent NFA. * Return the NFA start state on success, NULL otherwise. */ -static nfa_state_T * post2nfa(postfix, end, nfa_calc_size) -int *postfix; -int *end; -int nfa_calc_size; +static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size) { int *p; int mopen; @@ -3375,8 +3338,7 @@ theend: /* * After building the NFA program, inspect it to add optimization hints. */ -static void nfa_postprocess(prog) -nfa_regprog_T *prog; +static void nfa_postprocess(nfa_regprog_T *prog) { int i; int c; @@ -3489,16 +3451,14 @@ static void log_subsexpr __ARGS((regsubs_T *subs)); static void log_subexpr __ARGS((regsub_T *sub)); static char *pim_info __ARGS((nfa_pim_T *pim)); -static void log_subsexpr(subs) -regsubs_T *subs; +static void log_subsexpr(regsubs_T *subs) { log_subexpr(&subs->norm); if (nfa_has_zsubexpr) log_subexpr(&subs->synt); } -static void log_subexpr(sub) -regsub_T *sub; +static void log_subexpr(regsub_T *sub) { int j; @@ -3521,8 +3481,7 @@ regsub_T *sub; } } -static char * pim_info(pim) -nfa_pim_T *pim; +static char *pim_info(nfa_pim_T *pim) { static char buf[30]; @@ -3563,9 +3522,7 @@ static void addstate_here __ARGS((nfa_list_T *l, nfa_state_T *state, /* * Copy postponed invisible match info from "from" to "to". */ -static void copy_pim(to, from) -nfa_pim_T *to; -nfa_pim_T *from; +static void copy_pim(nfa_pim_T *to, nfa_pim_T *from) { to->result = from->result; to->state = from->state; @@ -3575,8 +3532,7 @@ nfa_pim_T *from; to->end = from->end; } -static void clear_sub(sub) -regsub_T *sub; +static void clear_sub(regsub_T *sub) { if (REG_MULTI) /* Use 0xff to set lnum to -1 */ @@ -3590,9 +3546,7 @@ regsub_T *sub; /* * Copy the submatches from "from" to "to". */ -static void copy_sub(to, from) -regsub_T *to; -regsub_T *from; +static void copy_sub(regsub_T *to, regsub_T *from) { to->in_use = from->in_use; if (from->in_use > 0) { @@ -3611,9 +3565,7 @@ regsub_T *from; /* * Like copy_sub() but exclude the main match. */ -static void copy_sub_off(to, from) -regsub_T *to; -regsub_T *from; +static void copy_sub_off(regsub_T *to, regsub_T *from) { if (to->in_use < from->in_use) to->in_use = from->in_use; @@ -3633,9 +3585,7 @@ regsub_T *from; /* * Like copy_sub() but only do the end of the main match if \ze is present. */ -static void copy_ze_off(to, from) -regsub_T *to; -regsub_T *from; +static void copy_ze_off(regsub_T *to, regsub_T *from) { if (nfa_has_zend) { if (REG_MULTI) { @@ -3651,9 +3601,7 @@ regsub_T *from; /* * Return TRUE if "sub1" and "sub2" have the same start positions. */ -static int sub_equal(sub1, sub2) -regsub_T *sub1; -regsub_T *sub2; +static int sub_equal(regsub_T *sub1, regsub_T *sub2) { int i; int todo; @@ -3723,11 +3671,13 @@ static void report_state(char *action, * Return TRUE if the same state is already in list "l" with the same * positions as "subs". */ -static int has_state_with_pos(l, state, subs, pim) -nfa_list_T *l; /* runtime state list */ -nfa_state_T *state; /* state to update */ -regsubs_T *subs; /* pointers to subexpressions */ -nfa_pim_T *pim; /* postponed match or NULL */ +static int +has_state_with_pos ( + nfa_list_T *l, /* runtime state list */ + nfa_state_T *state, /* state to update */ + regsubs_T *subs, /* pointers to subexpressions */ + nfa_pim_T *pim /* postponed match or NULL */ +) { nfa_thread_T *thread; int i; @@ -3748,9 +3698,7 @@ nfa_pim_T *pim; /* postponed match or NULL */ * Return TRUE if "one" and "two" are equal. That includes when both are not * set. */ -static int pim_equal(one, two) -nfa_pim_T *one; -nfa_pim_T *two; +static int pim_equal(nfa_pim_T *one, nfa_pim_T *two) { int one_unused = (one == NULL || one->result == NFA_PIM_UNUSED); int two_unused = (two == NULL || two->result == NFA_PIM_UNUSED); @@ -3774,9 +3722,7 @@ nfa_pim_T *two; /* * Return TRUE if "state" leads to a NFA_MATCH without advancing the input. */ -static int match_follows(startstate, depth) -nfa_state_T *startstate; -int depth; +static int match_follows(nfa_state_T *startstate, int depth) { nfa_state_T *state = startstate; @@ -3865,10 +3811,12 @@ int depth; /* * Return TRUE if "state" is already in list "l". */ -static int state_in_list(l, state, subs) -nfa_list_T *l; /* runtime state list */ -nfa_state_T *state; /* state to update */ -regsubs_T *subs; /* pointers to subexpressions */ +static int +state_in_list ( + nfa_list_T *l, /* runtime state list */ + nfa_state_T *state, /* state to update */ + regsubs_T *subs /* pointers to subexpressions */ +) { if (state->lastlist[nfa_ll_index] == l->id) { if (!nfa_has_backref || has_state_with_pos(l, state, subs, NULL)) @@ -3882,12 +3830,14 @@ regsubs_T *subs; /* pointers to subexpressions */ * Returns "subs_arg", possibly copied into temp_subs. */ -static regsubs_T * addstate(l, state, subs_arg, pim, off) -nfa_list_T *l; /* runtime state list */ -nfa_state_T *state; /* state to update */ -regsubs_T *subs_arg; /* pointers to subexpressions */ -nfa_pim_T *pim; /* postponed look-behind match */ -int off; /* byte offset, when -1 go to next line */ +static regsubs_T * +addstate ( + nfa_list_T *l, /* runtime state list */ + nfa_state_T *state, /* state to update */ + regsubs_T *subs_arg, /* pointers to subexpressions */ + nfa_pim_T *pim, /* postponed look-behind match */ + int off /* byte offset, when -1 go to next line */ +) { int subidx; nfa_thread_T *thread; @@ -4226,12 +4176,14 @@ skip_add: * This makes sure the order of states to be tried does not change, which * matters for alternatives. */ -static void addstate_here(l, state, subs, pim, ip) -nfa_list_T *l; /* runtime state list */ -nfa_state_T *state; /* state to update */ -regsubs_T *subs; /* pointers to subexpressions */ -nfa_pim_T *pim; /* postponed look-behind match */ -int *ip; +static void +addstate_here ( + nfa_list_T *l, /* runtime state list */ + nfa_state_T *state, /* state to update */ + regsubs_T *subs, /* pointers to subexpressions */ + nfa_pim_T *pim, /* postponed look-behind match */ + int *ip +) { int tlen = l->n; int count; @@ -4290,9 +4242,7 @@ int *ip; /* * Check character class "class" against current character c. */ -static int check_char_class(class, c) -int class; -int c; +static int check_char_class(int class, int c) { switch (class) { case NFA_CLASS_ALNUM: @@ -4372,10 +4322,12 @@ int c; * Check for a match with subexpression "subidx". * Return TRUE if it matches. */ -static int match_backref(sub, subidx, bytelen) -regsub_T *sub; /* pointers to subexpressions */ -int subidx; -int *bytelen; /* out: length of match in bytes */ +static int +match_backref ( + regsub_T *sub, /* pointers to subexpressions */ + int subidx, + int *bytelen /* out: length of match in bytes */ +) { int len; @@ -4428,9 +4380,11 @@ static int match_zref __ARGS((int subidx, int *bytelen)); * Check for a match with \z subexpression "subidx". * Return TRUE if it matches. */ -static int match_zref(subidx, bytelen) -int subidx; -int *bytelen; /* out: length of match in bytes */ +static int +match_zref ( + int subidx, + int *bytelen /* out: length of match in bytes */ +) { int len; @@ -4454,9 +4408,7 @@ int *bytelen; /* out: length of match in bytes */ * Also reset the IDs to zero. * Only used for the recursive value lastlist[1]. */ -static void nfa_save_listids(prog, list) -nfa_regprog_T *prog; -int *list; +static void nfa_save_listids(nfa_regprog_T *prog, int *list) { int i; nfa_state_T *p; @@ -4473,9 +4425,7 @@ int *list; /* * Restore list IDs from "list" to all NFA states. */ -static void nfa_restore_listids(prog, list) -nfa_regprog_T *prog; -int *list; +static void nfa_restore_listids(nfa_regprog_T *prog, int *list) { int i; nfa_state_T *p; @@ -4487,10 +4437,7 @@ int *list; } } -static int nfa_re_num_cmp(val, op, pos) -long_u val; -int op; -long_u pos; +static int nfa_re_num_cmp(long_u val, int op, long_u pos) { if (op == 1) return pos > val; if (op == 2) return pos < val; @@ -4510,13 +4457,7 @@ static int nfa_regmatch __ARGS((nfa_regprog_T *prog, nfa_state_T *start, * "pim" is NULL or contains info about a Postponed Invisible Match (start * position). */ -static int recursive_regmatch(state, pim, prog, submatch, m, listids) -nfa_state_T *state; -nfa_pim_T *pim; -nfa_regprog_T *prog; -regsubs_T *submatch; -regsubs_T *m; -int **listids; +static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T *prog, regsubs_T *submatch, regsubs_T *m, int **listids) { int save_reginput_col = (int)(reginput - regline); int save_reglnum = reglnum; @@ -4666,9 +4607,7 @@ static long find_match_text __ARGS((colnr_T startcol, int regstart, * NFA_ANY: 1 * specific character: 99 */ -static int failure_chance(state, depth) -nfa_state_T *state; -int depth; +static int failure_chance(nfa_state_T *state, int depth) { int c = state->c; int l, r; @@ -4821,9 +4760,7 @@ int depth; /* * Skip until the char "c" we know a match must start with. */ -static int skip_to_start(c, colp) -int c; -colnr_T *colp; +static int skip_to_start(int c, colnr_T *colp) { char_u *s; @@ -4845,10 +4782,7 @@ colnr_T *colp; * Called after skip_to_start() has found regstart. * Returns zero for no match, 1 for a match. */ -static long find_match_text(startcol, regstart, match_text) -colnr_T startcol; -int regstart; -char_u *match_text; +static long find_match_text(colnr_T startcol, int regstart, char_u *match_text) { colnr_T col = startcol; int c1, c2; @@ -4904,11 +4838,7 @@ char_u *match_text; * When there is a match "submatch" contains the positions. * Note: Caller must ensure that: start != NULL. */ -static int nfa_regmatch(prog, start, submatch, m) -nfa_regprog_T *prog; -nfa_state_T *start; -regsubs_T *submatch; -regsubs_T *m; +static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *submatch, regsubs_T *m) { int result; int size = 0; @@ -6116,9 +6046,7 @@ theend: * Try match of "prog" with at regline["col"]. * Returns 0 for failure, number of lines contained in the match otherwise. */ -static long nfa_regtry(prog, col) -nfa_regprog_T *prog; -colnr_T col; +static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) { int i; regsubs_T subs, m; @@ -6221,9 +6149,11 @@ colnr_T col; * * Returns 0 for failure, number of lines contained in the match otherwise. */ -static long nfa_regexec_both(line, startcol) -char_u *line; -colnr_T startcol; /* column to start looking for match */ +static long +nfa_regexec_both ( + char_u *line, + colnr_T startcol /* column to start looking for match */ +) { nfa_regprog_T *prog; long retval = 0L; @@ -6319,9 +6249,7 @@ theend: * Compile a regular expression into internal code for the NFA matcher. * Returns the program in allocated space. Returns NULL for an error. */ -static regprog_T * nfa_regcomp(expr, re_flags) -char_u *expr; -int re_flags; +static regprog_T *nfa_regcomp(char_u *expr, int re_flags) { nfa_regprog_T *prog = NULL; size_t prog_size; @@ -6435,8 +6363,7 @@ fail: /* * Free a compiled regexp program, returned by nfa_regcomp(). */ -static void nfa_regfree(prog) -regprog_T *prog; +static void nfa_regfree(regprog_T *prog) { if (prog != NULL) { vim_free(((nfa_regprog_T *)prog)->match_text); @@ -6454,10 +6381,12 @@ regprog_T *prog; * * Return TRUE if there is a match, FALSE if not. */ -static int nfa_regexec(rmp, line, col) -regmatch_T *rmp; -char_u *line; /* string to match against */ -colnr_T col; /* column to start looking for match */ +static int +nfa_regexec ( + regmatch_T *rmp, + char_u *line, /* string to match against */ + colnr_T col /* column to start looking for match */ +) { reg_match = rmp; reg_mmatch = NULL; @@ -6479,10 +6408,12 @@ static int nfa_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); /* * Like nfa_regexec(), but consider a "\n" in "line" to be a line break. */ -static int nfa_regexec_nl(rmp, line, col) -regmatch_T *rmp; -char_u *line; /* string to match against */ -colnr_T col; /* column to start looking for match */ +static int +nfa_regexec_nl ( + regmatch_T *rmp, + char_u *line, /* string to match against */ + colnr_T col /* column to start looking for match */ +) { reg_match = rmp; reg_mmatch = NULL; @@ -6529,7 +6460,7 @@ win_T *win; /* window in which to search or NULL */ buf_T *buf; /* buffer in which to search */ linenr_T lnum; /* nr of line to start looking for match */ colnr_T col; /* column to start looking for match */ -proftime_T *tm UNUSED; /* timeout limit or NULL */ +proftime_T *tm; /* timeout limit or NULL */ { reg_match = NULL; reg_mmatch = rmp; diff --git a/src/screen.c b/src/screen.c index cb04ab6964..3f544ad423 100644 --- a/src/screen.c +++ b/src/screen.c @@ -163,15 +163,12 @@ static int screen_char_attr = 0; * Set must_redraw only if not already set to a higher value. * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. */ -void redraw_later(type) -int type; +void redraw_later(int type) { redraw_win_later(curwin, type); } -void redraw_win_later(wp, type) -win_T *wp; -int type; +void redraw_win_later(win_T *wp, int type) { if (wp->w_redr_type < type) { wp->w_redr_type = type; @@ -186,7 +183,7 @@ int type; * Force a complete redraw later. Also resets the highlighting. To be used * after executing a shell command that messes up the screen. */ -void redraw_later_clear() { +void redraw_later_clear(void) { redraw_all_later(CLEAR); /* Use attributes that is very unlikely to appear in text. */ screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE; @@ -195,8 +192,7 @@ void redraw_later_clear() { /* * Mark all windows to be redrawn later. */ -void redraw_all_later(type) -int type; +void redraw_all_later(int type) { win_T *wp; @@ -209,15 +205,12 @@ int type; /* * Mark all windows that are editing the current buffer to be updated later. */ -void redraw_curbuf_later(type) -int type; +void redraw_curbuf_later(int type) { redraw_buf_later(curbuf, type); } -void redraw_buf_later(buf, type) -buf_T *buf; -int type; +void redraw_buf_later(buf_T *buf, int type) { win_T *wp; @@ -233,8 +226,7 @@ int type; * right away and restore what was on the command line. * Return a code indicating what happened. */ -int redraw_asap(type) -int type; +int redraw_asap(int type) { int rows; int r; @@ -360,9 +352,11 @@ int type; * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot * may become invalid and the whole window will have to be redrawn. */ -void redrawWinline(lnum, invalid) -linenr_T lnum; -int invalid UNUSED; /* window line height is invalid now */ +void +redrawWinline ( + linenr_T lnum, + int invalid /* window line height is invalid now */ +) { int i; @@ -385,8 +379,7 @@ int invalid UNUSED; /* window line height is invalid now */ /* * update all windows that are editing the current buffer */ -void update_curbuf(type) -int type; +void update_curbuf(int type) { redraw_curbuf_later(type); update_screen(type); @@ -399,8 +392,7 @@ int type; * Based on the current value of curwin->w_topline, transfer a screenfull * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. */ -void update_screen(type) -int type; +void update_screen(int type) { win_T *wp; static int did_intro = FALSE; @@ -591,8 +583,7 @@ int type; * Return TRUE if the cursor line in window "wp" may be concealed, according * to the 'concealcursor' option. */ -int conceal_cursor_line(wp) -win_T *wp; +int conceal_cursor_line(win_T *wp) { int c; @@ -614,7 +605,7 @@ win_T *wp; /* * Check if the cursor line needs to be redrawn because of 'concealcursor'. */ -void conceal_check_cursur_line() { +void conceal_check_cursur_line(void) { if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)) { need_cursor_line_redraw = TRUE; /* Need to recompute cursor column, e.g., when starting Visual mode @@ -623,9 +614,7 @@ void conceal_check_cursur_line() { } } -void update_single_line(wp, lnum) -win_T *wp; -linenr_T lnum; +void update_single_line(win_T *wp, linenr_T lnum) { int row; int j; @@ -680,8 +669,7 @@ linenr_T lnum; * mid: from mid_start to mid_end (update inversion or changed text) * bot: from bot_start to last row (when scrolled up) */ -static void win_update(wp) -win_T *wp; +static void win_update(win_T *wp) { buf_T *buf = wp->w_buffer; int type; @@ -1633,13 +1621,7 @@ win_T *wp; * Clear the rest of the window and mark the unused lines with "c1". use "c2" * as the filler character. */ -static void win_draw_end(wp, c1, c2, row, endrow, hl) -win_T *wp; -int c1; -int c2; -int row; -int endrow; -hlf_T hl; +static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl) { int n = 0; # define FDC_OFF n @@ -1695,9 +1677,7 @@ static int advance_color_col __ARGS((int vcol, int **color_cols)); /* * Advance **color_cols and return TRUE when there are columns to draw. */ -static int advance_color_col(vcol, color_cols) -int vcol; -int **color_cols; +static int advance_color_col(int vcol, int **color_cols) { while (**color_cols >= 0 && vcol > **color_cols) ++*color_cols; @@ -1707,12 +1687,7 @@ int **color_cols; /* * Display one folded line. */ -static void fold_line(wp, fold_count, foldinfo, lnum, row) -win_T *wp; -long fold_count; -foldinfo_T *foldinfo; -linenr_T lnum; -int row; +static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row) { char_u buf[51]; pos_T *top, *bot; @@ -2018,11 +1993,7 @@ int row; /* * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". */ -static void copy_text_attr(off, buf, len, attr) -int off; -char_u *buf; -int len; -int attr; +static void copy_text_attr(int off, char_u *buf, int len, int attr) { int i; @@ -2037,11 +2008,13 @@ int attr; * Fill the foldcolumn at "p" for window "wp". * Only to be called when 'foldcolumn' > 0. */ -static void fill_foldcolumn(p, wp, closed, lnum) -char_u *p; -win_T *wp; -int closed; /* TRUE of FALSE */ -linenr_T lnum; /* current line number */ +static void +fill_foldcolumn ( + char_u *p, + win_T *wp, + int closed, /* TRUE of FALSE */ + linenr_T lnum /* current line number */ +) { int i = 0; int level; @@ -2087,12 +2060,14 @@ linenr_T lnum; /* current line number */ * * Return the number of last row the line occupies. */ -static int win_line(wp, lnum, startrow, endrow, nochange) -win_T *wp; -linenr_T lnum; -int startrow; -int endrow; -int nochange UNUSED; /* not updating for changed text */ +static int +win_line ( + win_T *wp, + linenr_T lnum, + int startrow, + int endrow, + int nochange /* not updating for changed text */ +) { int col; /* visual column on screen */ unsigned off; /* offset in ScreenLines/ScreenAttrs */ @@ -4056,9 +4031,7 @@ static int comp_char_differs __ARGS((int, int)); * Return if the composing characters at "off_from" and "off_to" differ. * Only to be used when ScreenLinesUC[off_from] != 0. */ -static int comp_char_differs(off_from, off_to) -int off_from; -int off_to; +static int comp_char_differs(int off_from, int off_to) { int i; @@ -4078,10 +4051,7 @@ int off_to; * - the character is multi-byte and the next byte is different * - the character is two cells wide and the second cell differs. */ -static int char_needs_redraw(off_from, off_to, cols) -int off_from; -int off_to; -int cols; +static int char_needs_redraw(int off_from, int off_to, int cols) { if (cols > 0 && ((ScreenLines[off_from] != ScreenLines[off_to] @@ -4116,13 +4086,7 @@ int cols; * When TRUE and "clear_width" > 0, clear columns 0 to "endcol" * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" */ -static void screen_line(row, coloff, endcol, clear_width - , rlflag ) -int row; -int coloff; -int endcol; -int clear_width; -int rlflag; +static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag) { unsigned off_from; unsigned off_to; @@ -4376,8 +4340,7 @@ int rlflag; * Mirror text "str" for right-left displaying. * Only works for single-byte characters (e.g., numbers). */ -void rl_mirror(str) -char_u *str; +void rl_mirror(char_u *str) { char_u *p1, *p2; int t; @@ -4392,7 +4355,7 @@ char_u *str; /* * mark all status lines for redraw; used after first :cd */ -void status_redraw_all() { +void status_redraw_all(void) { win_T *wp; for (wp = firstwin; wp; wp = wp->w_next) @@ -4405,7 +4368,7 @@ void status_redraw_all() { /* * mark all status lines of the current buffer for redraw */ -void status_redraw_curbuf() { +void status_redraw_curbuf(void) { win_T *wp; for (wp = firstwin; wp; wp = wp->w_next) @@ -4418,7 +4381,7 @@ void status_redraw_curbuf() { /* * Redraw all status lines that need to be redrawn. */ -void redraw_statuslines() { +void redraw_statuslines(void) { win_T *wp; for (wp = firstwin; wp; wp = wp->w_next) @@ -4431,8 +4394,7 @@ void redraw_statuslines() { /* * Redraw all status lines at the bottom of frame "frp". */ -void win_redraw_last_status(frp) -frame_T *frp; +void win_redraw_last_status(frame_T *frp) { if (frp->fr_layout == FR_LEAF) frp->fr_win->w_redr_status = TRUE; @@ -4450,9 +4412,7 @@ frame_T *frp; /* * Draw the verticap separator right of window "wp" starting with line "row". */ -static void draw_vsep_win(wp, row) -win_T *wp; -int row; +static void draw_vsep_win(win_T *wp, int row) { int hl; int c; @@ -4472,9 +4432,7 @@ static int skip_status_match_char __ARGS((expand_T *xp, char_u *s)); /* * Get the length of an item as it will be shown in the status line. */ -static int status_match_len(xp, s) -expand_T *xp; -char_u *s; +static int status_match_len(expand_T *xp, char_u *s) { int len = 0; @@ -4498,9 +4456,7 @@ char_u *s; * Return the number of characters that should be skipped in a status match. * These are backslashes used for escaping. Do show backslashes in help tags. */ -static int skip_status_match_char(xp, s) -expand_T *xp; -char_u *s; +static int skip_status_match_char(expand_T *xp, char_u *s) { if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) || ((xp->xp_context == EXPAND_MENUS @@ -4523,12 +4479,14 @@ char_u *s; * * If inversion is possible we use it. Else '=' characters are used. */ -void win_redr_status_matches(xp, num_matches, matches, match, showtail) -expand_T *xp; -int num_matches; -char_u **matches; /* list of matches */ -int match; -int showtail; +void +win_redr_status_matches ( + expand_T *xp, + int num_matches, + char_u **matches, /* list of matches */ + int match, + int showtail +) { #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m]) int row; @@ -4702,8 +4660,7 @@ int showtail; * * If inversion is possible we use it. Else '=' characters are used. */ -void win_redr_status(wp) -win_T *wp; +void win_redr_status(win_T *wp) { int row; char_u *p; @@ -4823,8 +4780,7 @@ win_T *wp; * Redraw the status line according to 'statusline' and take care of any * errors encountered. */ -static void redraw_custom_statusline(wp) -win_T *wp; +static void redraw_custom_statusline(win_T *wp) { static int entered = FALSE; int save_called_emsg = called_emsg; @@ -4854,8 +4810,7 @@ win_T *wp; * line of the window right of it. If not, then it's a vertical separator. * Only call if (wp->w_vsep_width != 0). */ -int stl_connected(wp) -win_T *wp; +int stl_connected(win_T *wp) { frame_T *fr; @@ -4877,10 +4832,12 @@ win_T *wp; /* * Get the value to show for the language mappings, active 'keymap'. */ -int get_keymap_str(wp, buf, len) -win_T *wp; -char_u *buf; /* buffer for the result */ -int len; /* length of buffer */ +int +get_keymap_str ( + win_T *wp, + char_u *buf, /* buffer for the result */ + int len /* length of buffer */ +) { char_u *p; @@ -4919,9 +4876,11 @@ int len; /* length of buffer */ * Redraw the status line or ruler of window "wp". * When "wp" is NULL redraw the tab pages line from 'tabline'. */ -static void win_redr_custom(wp, draw_ruler) -win_T *wp; -int draw_ruler; /* TRUE or FALSE */ +static void +win_redr_custom ( + win_T *wp, + int draw_ruler /* TRUE or FALSE */ +) { static int entered = FALSE; int attr; @@ -5079,10 +5038,7 @@ theend: /* * Output a single character directly to the screen and update ScreenLines. */ -void screen_putchar(c, row, col, attr) -int c; -int row, col; -int attr; +void screen_putchar(int c, int row, int col, int attr) { char_u buf[MB_MAXBYTES + 1]; @@ -5099,10 +5055,7 @@ int attr; * Get a single character directly from ScreenLines into "bytes[]". * Also return its attribute in *attrp; */ -void screen_getbytes(row, col, bytes, attrp) -int row, col; -char_u *bytes; -int *attrp; +void screen_getbytes(int row, int col, char_u *bytes, int *attrp) { unsigned off; @@ -5133,9 +5086,7 @@ static int screen_comp_differs __ARGS((int, int*)); * composing characters in "u8cc". * Only to be used when ScreenLinesUC[off] != 0. */ -static int screen_comp_differs(off, u8cc) -int off; -int *u8cc; +static int screen_comp_differs(int off, int *u8cc) { int i; @@ -5154,11 +5105,7 @@ int *u8cc; * Note: only outputs within one row, message is truncated at screen boundary! * Note: if ScreenLines[], row and/or col is invalid, nothing is done. */ -void screen_puts(text, row, col, attr) -char_u *text; -int row; -int col; -int attr; +void screen_puts(char_u *text, int row, int col, int attr) { screen_puts_len(text, -1, row, col, attr); } @@ -5167,12 +5114,7 @@ int attr; * Like screen_puts(), but output "text[len]". When "len" is -1 output up to * a NUL. */ -void screen_puts_len(text, len, row, col, attr) -char_u *text; -int len; -int row; -int col; -int attr; +void screen_puts_len(char_u *text, int len, int row, int col, int attr) { unsigned off; char_u *ptr = text; @@ -5383,7 +5325,7 @@ int attr; /* * Prepare for 'hlsearch' highlighting. */ -static void start_search_hl() { +static void start_search_hl(void) { if (p_hls && !no_hlsearch) { last_pat_prog(&search_hl.rm); search_hl.attr = hl_attr(HLF_L); @@ -5395,7 +5337,7 @@ static void start_search_hl() { /* * Clean up for 'hlsearch' highlighting. */ -static void end_search_hl() { +static void end_search_hl(void) { if (search_hl.rm.regprog != NULL) { vim_regfree(search_hl.rm.regprog); search_hl.rm.regprog = NULL; @@ -5405,8 +5347,7 @@ static void end_search_hl() { /* * Init for calling prepare_search_hl(). */ -static void init_search_hl(wp) -win_T *wp; +static void init_search_hl(win_T *wp) { matchitem_T *cur; @@ -5435,9 +5376,7 @@ win_T *wp; /* * Advance to the match in window "wp" line "lnum" or past it. */ -static void prepare_search_hl(wp, lnum) -win_T *wp; -linenr_T lnum; +static void prepare_search_hl(win_T *wp, linenr_T lnum) { matchitem_T *cur; /* points to the match list */ match_T *shl; /* points to search_hl or a match */ @@ -5495,11 +5434,13 @@ linenr_T lnum; * shl->lnum is zero. * Careful: Any pointers for buffer lines will become invalid. */ -static void next_search_hl(win, shl, lnum, mincol) -win_T *win; -match_T *shl; /* points to search_hl or a match */ -linenr_T lnum; -colnr_T mincol; /* minimal column for a match */ +static void +next_search_hl ( + win_T *win, + match_T *shl, /* points to search_hl or a match */ + linenr_T lnum, + colnr_T mincol /* minimal column for a match */ +) { linenr_T l; colnr_T matchcol; @@ -5586,8 +5527,7 @@ colnr_T mincol; /* minimal column for a match */ } } -static void screen_start_highlight(attr) -int attr; +static void screen_start_highlight(int attr) { attrentry_T *aep = NULL; @@ -5641,7 +5581,7 @@ int attr; } } -void screen_stop_highlight() { +void screen_stop_highlight(void) { int do_ME = FALSE; /* output T_ME code */ if (screen_attr != 0 @@ -5716,7 +5656,7 @@ void screen_stop_highlight() { * Reset the colors for a cterm. Used when leaving Vim. * The machine specific code may override this again. */ -void reset_cterm_colors() { +void reset_cterm_colors(void) { if (t_colors > 1) { /* set Normal cterm colors */ if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0) { @@ -5734,10 +5674,7 @@ void reset_cterm_colors() { * Put character ScreenLines["off"] on the screen at position "row" and "col", * using the attributes from ScreenAttrs["off"]. */ -static void screen_char(off, row, col) -unsigned off; -int row; -int col; +static void screen_char(unsigned off, int row, int col) { int attr; @@ -5799,10 +5736,7 @@ int col; * The attributes of the first byte is used for all. This is required to * output the two bytes of a double-byte character with nothing in between. */ -static void screen_char_2(off, row, col) -unsigned off; -int row; -int col; +static void screen_char_2(unsigned off, int row, int col) { /* Check for illegal values (could be wrong when screen was resized). */ if (off + 1 >= (unsigned)(screen_Rows * screen_Columns)) @@ -5826,12 +5760,7 @@ int col; * Draw a rectangle of the screen, inverted when "invert" is TRUE. * This uses the contents of ScreenLines[] and doesn't change it. */ -void screen_draw_rectangle(row, col, height, width, invert) -int row; -int col; -int height; -int width; -int invert; +void screen_draw_rectangle(int row, int col, int height, int width, int invert) { int r, c; int off; @@ -5863,10 +5792,7 @@ int invert; /* * Redraw the characters for a vertically split window. */ -static void redraw_block(row, end, wp) -int row; -int end; -win_T *wp; +static void redraw_block(int row, int end, win_T *wp) { int col; int width; @@ -5887,11 +5813,7 @@ win_T *wp; * with character 'c1' in first column followed by 'c2' in the other columns. * Use attributes 'attr'. */ -void screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr) -int start_row, end_row; -int start_col, end_col; -int c1, c2; -int attr; +void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, int c2, int attr) { int row; int col; @@ -6042,8 +5964,7 @@ int attr; * Check if there should be a delay. Used before clearing or redrawing the * screen or the command line. */ -void check_for_delay(check_msg_scroll) -int check_msg_scroll; +void check_for_delay(int check_msg_scroll) { if ((emsg_on_display || (check_msg_scroll && msg_scroll)) && !did_wait_return @@ -6062,8 +5983,7 @@ int check_msg_scroll; * Returns TRUE if there is a valid screen to write to. * Returns FALSE when starting up and screen not initialized yet. */ -int screen_valid(doclear) -int doclear; +int screen_valid(int doclear) { screenalloc(doclear); /* allocate screen buffers if size changed */ return ScreenLines != NULL; @@ -6079,8 +5999,7 @@ int doclear; * in ScreenLines[]. Use Rows and Columns for positioning text etc. where the * final size of the shell is needed. */ -void screenalloc(doclear) -int doclear; +void screenalloc(int doclear) { int new_row, old_row; win_T *wp; @@ -6327,7 +6246,7 @@ give_up: } } -void free_screenlines() { +void free_screenlines(void) { int i; vim_free(ScreenLinesUC); @@ -6341,13 +6260,13 @@ void free_screenlines() { vim_free(TabPageIdxs); } -void screenclear() { +void screenclear(void) { check_for_delay(FALSE); screenalloc(FALSE); /* allocate screen buffers if size changed */ screenclear2(); /* clear the screen */ } -static void screenclear2() { +static void screenclear2(void) { int i; if (starting == NO_SCREEN || ScreenLines == NULL @@ -6394,9 +6313,7 @@ static void screenclear2() { /* * Clear one line in ScreenLines. */ -static void lineclear(off, width) -unsigned off; -int width; +static void lineclear(unsigned off, int width) { (void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T)); if (enc_utf8) @@ -6409,9 +6326,7 @@ int width; * Mark one line in ScreenLines invalid by setting the attributes to an * invalid value. */ -static void lineinvalid(off, width) -unsigned off; -int width; +static void lineinvalid(unsigned off, int width) { (void)vim_memset(ScreenAttrs + off, -1, (size_t)width * sizeof(sattr_T)); } @@ -6419,10 +6334,7 @@ int width; /* * Copy part of a Screenline for vertically split window "wp". */ -static void linecopy(to, from, wp) -int to; -int from; -win_T *wp; +static void linecopy(int to, int from, win_T *wp) { unsigned off_to = LineOffset[to] + wp->w_wincol; unsigned off_from = LineOffset[from] + wp->w_wincol; @@ -6449,8 +6361,7 @@ win_T *wp; * Return TRUE if clearing with term string "p" would work. * It can't work when the string is empty or it won't set the right background. */ -int can_clear(p) -char_u *p; +int can_clear(char_u *p) { return *p != NUL && (t_colors <= 1 || cterm_normal_bg_color == 0 || *T_UT != NUL); @@ -6461,7 +6372,7 @@ char_u *p; * something directly to the screen (shell commands) or a terminal control * code. */ -void screen_start() { +void screen_start(void) { screen_cur_row = screen_cur_col = 9999; } @@ -6470,9 +6381,7 @@ void screen_start() { * This tries to find the most efficient way to move, minimizing the number of * characters sent to the terminal. */ -void windgoto(row, col) -int row; -int col; +void windgoto(int row, int col) { sattr_T *p; int i; @@ -6685,7 +6594,7 @@ int col; /* * Set cursor to its position in the current window. */ -void setcursor() { +void setcursor(void) { if (redrawing()) { validate_cursor(); windgoto(W_WINROW(curwin) + curwin->w_wrow, @@ -6708,12 +6617,7 @@ void setcursor() { * scrolling. * Returns FAIL if the lines are not inserted, OK for success. */ -int win_ins_lines(wp, row, line_count, invalid, mayclear) -win_T *wp; -int row; -int line_count; -int invalid; -int mayclear; +int win_ins_lines(win_T *wp, int row, int line_count, int invalid, int mayclear) { int did_delete; int nextrow; @@ -6782,12 +6686,7 @@ int mayclear; * scrolling * Return OK for success, FAIL if the lines are not deleted. */ -int win_del_lines(wp, row, line_count, invalid, mayclear) -win_T *wp; -int row; -int line_count; -int invalid; -int mayclear; +int win_del_lines(win_T *wp, int row, int line_count, int invalid, int mayclear) { int retval; @@ -6830,12 +6729,7 @@ int mayclear; * Returns OK or FAIL when the work has been done. * Returns MAYBE when not finished yet. */ -static int win_do_lines(wp, row, line_count, mayclear, del) -win_T *wp; -int row; -int line_count; -int mayclear; -int del; +static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del) { int retval; @@ -6900,8 +6794,7 @@ int del; /* * window 'wp' and everything after it is messed up, mark it for redraw */ -static void win_rest_invalid(wp) -win_T *wp; +static void win_rest_invalid(win_T *wp) { while (wp != NULL) { redraw_win_later(wp, NOT_VALID); @@ -6942,12 +6835,14 @@ win_T *wp; * * return FAIL for failure, OK for success. */ -int screen_ins_lines(off, row, line_count, end, wp) -int off; -int row; -int line_count; -int end; -win_T *wp; /* NULL or window to use width from */ +int +screen_ins_lines ( + int off, + int row, + int line_count, + int end, + win_T *wp /* NULL or window to use width from */ +) { int i; int j; @@ -7113,13 +7008,15 @@ win_T *wp; /* NULL or window to use width from */ * * Return OK for success, FAIL if the lines are not deleted. */ -int screen_del_lines(off, row, line_count, end, force, wp) -int off; -int row; -int line_count; -int end; -int force; /* even when line_count > p_ttyscroll */ -win_T *wp UNUSED; /* NULL or window to use width from */ +int +screen_del_lines ( + int off, + int row, + int line_count, + int end, + int force, /* even when line_count > p_ttyscroll */ + win_T *wp /* NULL or window to use width from */ +) { int j; int i; @@ -7292,7 +7189,7 @@ win_T *wp UNUSED; /* NULL or window to use width from */ * cleared only if a mode is shown. * Return the length of the message (0 if no message). */ -int showmode() { +int showmode(void) { int need_clear; int length = 0; int do_mode; @@ -7443,7 +7340,7 @@ int showmode() { /* * Position for a mode message. */ -static void msg_pos_mode() { +static void msg_pos_mode(void) { msg_col = 0; msg_row = Rows - 1; } @@ -7453,8 +7350,7 @@ static void msg_pos_mode() { * Insert mode (but Insert mode didn't end yet!). * Caller should check "mode_displayed". */ -void unshowmode(force) -int force; +void unshowmode(int force) { /* * Don't delete it right now, when not redrawing or inside a mapping. @@ -7472,7 +7368,7 @@ int force; /* * Draw the tab pages line at the top of the Vim window. */ -static void draw_tabline() { +static void draw_tabline(void) { int tabcount = 0; tabpage_T *tp; int tabwidth; @@ -7622,8 +7518,7 @@ static void draw_tabline() { * Get buffer name for "buf" into NameBuff[]. * Takes care of special buffer names and translates special characters. */ -void get_trans_bufname(buf) -buf_T *buf; +void get_trans_bufname(buf_T *buf) { if (buf_spname(buf) != NULL) vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1); @@ -7635,9 +7530,7 @@ buf_T *buf; /* * Get the character to use in a status line. Get its attributes in "*attr". */ -static int fillchar_status(attr, is_curwin) -int *attr; -int is_curwin; +static int fillchar_status(int *attr, int is_curwin) { int fill; if (is_curwin) { @@ -7663,8 +7556,7 @@ int is_curwin; * Get the character to use in a separator between vertically split windows. * Get its attributes in "*attr". */ -static int fillchar_vsep(attr) -int *attr; +static int fillchar_vsep(int *attr) { *attr = hl_attr(HLF_C); if (*attr == 0 && fill_vert == ' ') @@ -7676,7 +7568,7 @@ int *attr; /* * Return TRUE if redrawing should currently be done. */ -int redrawing() { +int redrawing(void) { return !RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped && !do_redraw); } @@ -7684,7 +7576,7 @@ int redrawing() { /* * Return TRUE if printing messages should currently be done. */ -int messaging() { +int messaging(void) { return !(p_lz && char_avail() && !KeyTyped); } @@ -7692,8 +7584,7 @@ int messaging() { * Show current status info in ruler and various other places * If always is FALSE, only show ruler if position has changed. */ -void showruler(always) -int always; +void showruler(int always) { if (!always && !redrawing()) return; @@ -7717,9 +7608,7 @@ int always; draw_tabline(); } -static void win_redr_ruler(wp, always) -win_T *wp; -int always; +static void win_redr_ruler(win_T *wp, int always) { #define RULER_BUF_LEN 70 char_u buffer[RULER_BUF_LEN]; @@ -7887,8 +7776,7 @@ int always; * Caller may need to check if 'number' or 'relativenumber' is set. * Otherwise it depends on 'numberwidth' and the line count. */ -int number_width(wp) -win_T *wp; +int number_width(win_T *wp) { int n; linenr_T lnum; @@ -7922,7 +7810,7 @@ win_T *wp; * Return the current cursor column. This is the actual position on the * screen. First column is 0. */ -int screen_screencol() { +int screen_screencol(void) { return screen_cur_col; } @@ -7930,7 +7818,7 @@ int screen_screencol() { * Return the current cursor row. This is the actual position on the screen. * First row is 0. */ -int screen_screenrow() { +int screen_screenrow(void) { return screen_cur_row; } diff --git a/src/search.c b/src/search.c index 6007b53375..a46637efdb 100644 --- a/src/search.c +++ b/src/search.c @@ -113,12 +113,14 @@ typedef struct SearchedFile { * * returns FAIL if failed, OK otherwise. */ -int search_regcomp(pat, pat_save, pat_use, options, regmatch) -char_u *pat; -int pat_save; -int pat_use; -int options; -regmmatch_T *regmatch; /* return: pattern and ignore-case flag */ +int +search_regcomp ( + char_u *pat, + int pat_save, + int pat_use, + int options, + regmmatch_T *regmatch /* return: pattern and ignore-case flag */ +) { int magic; int i; @@ -190,7 +192,7 @@ regmmatch_T *regmatch; /* return: pattern and ignore-case flag */ /* * Get search pattern used by search_regcomp(). */ -char_u * get_search_pat() { +char_u *get_search_pat(void) { return mr_pattern; } @@ -198,8 +200,7 @@ char_u * get_search_pat() { * Reverse text into allocated memory. * Returns the allocated string, NULL when out of memory. */ -char_u * reverse_text(s) -char_u *s; +char_u *reverse_text(char_u *s) { unsigned len; unsigned s_i, rev_i; @@ -229,10 +230,7 @@ char_u *s; return rev; } -static void save_re_pat(idx, pat, magic) -int idx; -char_u *pat; -int magic; +static void save_re_pat(int idx, char_u *pat, int magic) { if (spats[idx].pat != pat) { vim_free(spats[idx].pat); @@ -253,7 +251,7 @@ int magic; */ static int save_level = 0; -void save_search_patterns() { +void save_search_patterns(void) { if (save_level++ == 0) { saved_spats[0] = spats[0]; if (spats[0].pat != NULL) @@ -266,7 +264,7 @@ void save_search_patterns() { } } -void restore_search_patterns() { +void restore_search_patterns(void) { if (--save_level == 0) { vim_free(spats[0].pat); spats[0] = saved_spats[0]; @@ -279,7 +277,7 @@ void restore_search_patterns() { } #if defined(EXITFREE) || defined(PROTO) -void free_search_patterns() { +void free_search_patterns(void) { vim_free(spats[0].pat); vim_free(spats[1].pat); @@ -296,8 +294,7 @@ void free_search_patterns() { * Return TRUE when case should be ignored for search pattern "pat". * Uses the 'ignorecase' and 'smartcase' options. */ -int ignorecase(pat) -char_u *pat; +int ignorecase(char_u *pat) { int ic = p_ic; @@ -313,8 +310,7 @@ char_u *pat; /* * Return TRUE if patter "pat" has an uppercase character. */ -int pat_has_uppercase(pat) -char_u *pat; +int pat_has_uppercase(char_u *pat) { char_u *p = pat; @@ -342,14 +338,14 @@ char_u *pat; return FALSE; } -char_u * last_search_pat() { +char_u *last_search_pat(void) { return spats[last_idx].pat; } /* * Reset search direction to forward. For "gd" and "gD" commands. */ -void reset_search_dir() { +void reset_search_dir(void) { spats[0].off.dir = '/'; set_vv_searchforward(); } @@ -358,11 +354,7 @@ void reset_search_dir() { * Set the last search pattern. For ":let @/ =" and viminfo. * Also set the saved search pattern, so that this works in an autocommand. */ -void set_last_search_pat(s, idx, magic, setlast) -char_u *s; -int idx; -int magic; -int setlast; +void set_last_search_pat(char_u *s, int idx, int magic, int setlast) { vim_free(spats[idx].pat); /* An empty string means that nothing should be matched. */ @@ -398,8 +390,7 @@ int setlast; * This is used for highlighting all matches in a window. * Values returned in regmatch->regprog and regmatch->rmm_ic. */ -void last_pat_prog(regmatch) -regmmatch_T *regmatch; +void last_pat_prog(regmmatch_T *regmatch) { if (spats[last_idx].pat == NULL) { regmatch->regprog = NULL; @@ -440,7 +431,7 @@ long count; int options; int pat_use; /* which pattern to use when "pat" is empty */ linenr_T stop_lnum; /* stop after this line number when != 0 */ -proftime_T *tm UNUSED; /* timeout limit or NULL */ +proftime_T *tm; /* timeout limit or NULL */ { int found; linenr_T lnum; /* no init to shut up Apollo cc */ @@ -827,21 +818,19 @@ proftime_T *tm UNUSED; /* timeout limit or NULL */ return submatch + 1; } -void set_search_direction(cdir) -int cdir; +void set_search_direction(int cdir) { spats[0].off.dir = cdir; } -static void set_vv_searchforward() { +static void set_vv_searchforward(void) { set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/')); } /* * Return the number of the first subpat that matched. */ -static int first_submatch(rp) -regmmatch_T *rp; +static int first_submatch(regmmatch_T *rp) { int submatch; @@ -1208,11 +1197,7 @@ end_do_search: * ADDING is set. if p_ic is set then the pattern must be in lowercase. * Return OK for success, or FAIL if no line found. */ -int search_for_exact_line(buf, pos, dir, pat) -buf_T *buf; -pos_T *pos; -int dir; -char_u *pat; +int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) { linenr_T start = 0; char_u *ptr; @@ -1275,9 +1260,7 @@ char_u *pat; * Do this "cap->count1" times. * Return FAIL or OK. */ -int searchc(cap, t_cmd) -cmdarg_T *cap; -int t_cmd; +int searchc(cmdarg_T *cap, int t_cmd) { int c = cap->nchar; /* char to search for */ int dir = cap->arg; /* TRUE for searching forward */ @@ -1389,9 +1372,7 @@ int t_cmd; * * Improvement over vi: Braces inside quotes are ignored. */ -pos_T * findmatch(oap, initc) -oparg_T *oap; -int initc; +pos_T *findmatch(oparg_T *oap, int initc) { return findmatchlimit(oap, initc, 0, 0); } @@ -1403,11 +1384,7 @@ int initc; * is NULL. * Handles multibyte string correctly. */ -static int check_prevcol(linep, col, ch, prevcol) -char_u *linep; -int col; -int ch; -int *prevcol; +static int check_prevcol(char_u *linep, int col, int ch, int *prevcol) { --col; if (col > 0 && has_mbyte) @@ -1434,11 +1411,7 @@ int *prevcol; * NULL */ -pos_T * findmatchlimit(oap, initc, flags, maxtravel) -oparg_T *oap; -int initc; -int flags; -int maxtravel; +pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int maxtravel) { static pos_T pos; /* current search position */ int findc = 0; /* matching brace */ @@ -1945,8 +1918,7 @@ int maxtravel; * Return MAXCOL if not, otherwise return the column. * TODO: skip strings. */ -static int check_linecomment(line) -char_u *line; +static int check_linecomment(char_u *line) { char_u *p; @@ -1993,8 +1965,10 @@ char_u *line; * Show the match only if it is visible on the screen. * If there isn't a match, then beep. */ -void showmatch(c) -int c; /* char to show match for */ +void +showmatch ( + int c /* char to show match for */ +) { pos_T *lpos, save_cursor; pos_T mpos; @@ -2085,9 +2059,7 @@ int c; /* char to show match for */ * space or a line break. Also stop at an empty line. * Return OK if the next sentence was found. */ -int findsent(dir, count) -int dir; -long count; +int findsent(int dir, long count) { pos_T pos, tpos; int c; @@ -2201,12 +2173,14 @@ found: * If 'both' is TRUE also stop at '}'. * Return TRUE if the next paragraph or section was found. */ -int findpar(pincl, dir, count, what, both) -int *pincl; /* Return: TRUE if last char is to be included */ -int dir; -long count; -int what; -int both; +int +findpar ( + int *pincl, /* Return: TRUE if last char is to be included */ + int dir, + long count, + int what, + int both +) { linenr_T curr; int did_skip; /* TRUE after separating lines have been skipped */ @@ -2267,9 +2241,7 @@ int both; /* * check if the string 's' is a nroff macro that is in option 'opt' */ -static int inmacro(opt, s) -char_u *opt; -char_u *s; +static int inmacro(char_u *opt, char_u *s) { char_u *macro; @@ -2296,10 +2268,7 @@ char_u *s; * If 'para' is '{' or '}' only check for sections. * If 'both' is TRUE also stop at '}' */ -int startPS(lnum, para, both) -linenr_T lnum; -int para; -int both; +int startPS(linenr_T lnum, int para, int both) { char_u *s; @@ -2337,7 +2306,7 @@ static int cls_bigword; /* TRUE for "W", "B" or "E" */ * from class 2 and higher are reported as class 1 since only white space * boundaries are of interest. */ -static int cls() { +static int cls(void) { int c; c = gchar_cursor(); @@ -2375,10 +2344,12 @@ static int cls() { * Returns FAIL if the cursor was already at the end of the file. * If eol is TRUE, last word stops at end of line (for operators). */ -int fwd_word(count, bigword, eol) -long count; -int bigword; /* "W", "E" or "B" */ -int eol; +int +fwd_word ( + long count, + int bigword, /* "W", "E" or "B" */ + int eol +) { int sclass; /* starting class */ int i; @@ -2439,10 +2410,7 @@ int eol; * * Returns FAIL if top of the file was reached. */ -int bck_word(count, bigword, stop) -long count; -int bigword; -int stop; +int bck_word(long count, int bigword, int stop) { int sclass; /* starting class */ @@ -2499,11 +2467,7 @@ finished: * If stop is TRUE and we are already on the end of a word, move one less. * If empty is TRUE stop on an empty line. */ -int end_word(count, bigword, stop, empty) -long count; -int bigword; -int stop; -int empty; +int end_word(long count, int bigword, int stop, int empty) { int sclass; /* starting class */ @@ -2559,10 +2523,12 @@ finished: * * Returns FAIL if start of the file was reached. */ -int bckend_word(count, bigword, eol) -long count; -int bigword; /* TRUE for "B" */ -int eol; /* TRUE: stop at end of line. */ +int +bckend_word ( + long count, + int bigword, /* TRUE for "B" */ + int eol /* TRUE: stop at end of line. */ +) { int sclass; /* starting class */ int i; @@ -2602,9 +2568,7 @@ int eol; /* TRUE: stop at end of line. */ * Skip a row of characters of the same class. * Return TRUE when end-of-file reached, FALSE otherwise. */ -static int skip_chars(cclass, dir) -int cclass; -int dir; +static int skip_chars(int cclass, int dir) { while (cls() == cclass) if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) @@ -2615,7 +2579,7 @@ int dir; /* * Go back to the start of the word or the start of white space */ -static void back_in_line() { +static void back_in_line(void) { int sclass; /* starting class */ sclass = cls(); @@ -2630,8 +2594,7 @@ static void back_in_line() { } } -static void find_first_blank(posp) -pos_T *posp; +static void find_first_blank(pos_T *posp) { int c; @@ -2647,9 +2610,11 @@ pos_T *posp; /* * Skip count/2 sentences and count/2 separating white spaces. */ -static void findsent_forward(count, at_start_sent) -long count; -int at_start_sent; /* cursor is at start of sentence */ +static void +findsent_forward ( + long count, + int at_start_sent /* cursor is at start of sentence */ +) { while (count--) { findsent(FORWARD, 1L); @@ -2665,11 +2630,13 @@ int at_start_sent; /* cursor is at start of sentence */ * Find word under cursor, cursor at end. * Used while an operator is pending, and in Visual mode. */ -int current_word(oap, count, include, bigword) -oparg_T *oap; -long count; -int include; /* TRUE: include word and white space */ -int bigword; /* FALSE == word, TRUE == WORD */ +int +current_word ( + oparg_T *oap, + long count, + int include, /* TRUE: include word and white space */ + int bigword /* FALSE == word, TRUE == WORD */ +) { pos_T start_pos; pos_T pos; @@ -2815,10 +2782,7 @@ int bigword; /* FALSE == word, TRUE == WORD */ * Find sentence(s) under the cursor, cursor at end. * When Visual active, extend it by one or more sentences. */ -int current_sent(oap, count, include) -oparg_T *oap; -long count; -int include; +int current_sent(oparg_T *oap, long count, int include) { pos_T start_pos; pos_T pos; @@ -2973,12 +2937,14 @@ extend: * Find block under the cursor, cursor at end. * "what" and "other" are two matching parenthesis/brace/etc. */ -int current_block(oap, count, include, what, other) -oparg_T *oap; -long count; -int include; /* TRUE == include white space */ -int what; /* '(', '{', etc. */ -int other; /* ')', '}', etc. */ +int +current_block ( + oparg_T *oap, + long count, + int include, /* TRUE == include white space */ + int what, /* '(', '{', etc. */ + int other /* ')', '}', etc. */ +) { pos_T old_pos; pos_T *pos = NULL; @@ -3106,8 +3072,7 @@ static int in_html_tag __ARGS((int)); * Return TRUE if the cursor is on a "" tag. Ignore "". * When "end_tag" is TRUE return TRUE if the cursor is on "". */ -static int in_html_tag(end_tag) -int end_tag; +static int in_html_tag(int end_tag) { char_u *line = ml_get_curline(); char_u *p; @@ -3169,10 +3134,12 @@ int end_tag; /* * Find tag block under the cursor, cursor at end. */ -int current_tagblock(oap, count_arg, include) -oparg_T *oap; -long count_arg; -int include; /* TRUE == include white space */ +int +current_tagblock ( + oparg_T *oap, + long count_arg, + int include /* TRUE == include white space */ +) { long count = count_arg; long n; @@ -3344,11 +3311,13 @@ theend: return retval; } -int current_par(oap, count, include, type) -oparg_T *oap; -long count; -int include; /* TRUE == include white space */ -int type; /* 'p' for paragraph, 'S' for section */ +int +current_par ( + oparg_T *oap, + long count, + int include, /* TRUE == include white space */ + int type /* 'p' for paragraph, 'S' for section */ +) { linenr_T start_lnum; linenr_T end_lnum; @@ -3509,11 +3478,13 @@ static int find_prev_quote __ARGS((char_u *line, int col_start, int quotechar, * as a quote. * Returns column number of "quotechar" or -1 when not found. */ -static int find_next_quote(line, col, quotechar, escape) -char_u *line; -int col; -int quotechar; -char_u *escape; /* escape characters, can be NULL */ +static int +find_next_quote ( + char_u *line, + int col, + int quotechar, + char_u *escape /* escape characters, can be NULL */ +) { int c; @@ -3539,11 +3510,13 @@ char_u *escape; /* escape characters, can be NULL */ * as a quote. * Return the found column or zero. */ -static int find_prev_quote(line, col_start, quotechar, escape) -char_u *line; -int col_start; -int quotechar; -char_u *escape; /* escape characters, can be NULL */ +static int +find_prev_quote ( + char_u *line, + int col_start, + int quotechar, + char_u *escape /* escape characters, can be NULL */ +) { int n; @@ -3567,11 +3540,13 @@ char_u *escape; /* escape characters, can be NULL */ * Find quote under the cursor, cursor at end. * Returns TRUE if found, else FALSE. */ -int current_quote(oap, count, include, quotechar) -oparg_T *oap; -long count; -int include; /* TRUE == include quote char */ -int quotechar; /* Quote character */ +int +current_quote ( + oparg_T *oap, + long count, + int include, /* TRUE == include quote char */ + int quotechar /* Quote character */ +) { char_u *line = ml_get_curline(); int col_end; @@ -3779,9 +3754,11 @@ static int is_one_char __ARGS((char_u *pattern)); * Used while an operator is pending, and in Visual mode. * TODO: redo only works when used in operator pending mode */ -int current_search(count, forward) -long count; -int forward; /* move forward or backwards */ +int +current_search ( + long count, + int forward /* move forward or backwards */ +) { pos_T start_pos; /* position before the pattern */ pos_T orig_pos; /* position of the cursor at beginning */ @@ -3909,8 +3886,7 @@ int forward; /* move forward or backwards */ * Check if the pattern is one character or zero-width. * Returns TRUE, FALSE or -1 for failure. */ -static int is_one_char(pattern) -char_u *pattern; +static int is_one_char(char_u *pattern) { regmmatch_T regmatch; int nmatched = 0; @@ -3951,8 +3927,7 @@ char_u *pattern; /* * return TRUE if line 'lnum' is empty or has white chars only. */ -int linewhite(lnum) -linenr_T lnum; +int linewhite(linenr_T lnum) { char_u *p; @@ -3965,19 +3940,20 @@ linenr_T lnum; * Find identifiers or defines in included files. * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase. */ -void find_pattern_in_path(ptr, dir, len, whole, skip_comments, - type, count, action, start_lnum, end_lnum) -char_u *ptr; /* pointer to search pattern */ -int dir UNUSED; /* direction of expansion */ -int len; /* length of search pattern */ -int whole; /* match whole words only */ -int skip_comments; /* don't match inside comments */ -int type; /* Type of search; are we looking for a type? +void +find_pattern_in_path ( + char_u *ptr, /* pointer to search pattern */ + int dir, /* direction of expansion */ + int len, /* length of search pattern */ + int whole, /* match whole words only */ + int skip_comments, /* don't match inside comments */ + int type, /* Type of search; are we looking for a type? a macro? */ -long count; -int action; /* What to do when we find it */ -linenr_T start_lnum; /* first line to start searching */ -linenr_T end_lnum; /* last line for searching */ + long count, + int action, /* What to do when we find it */ + linenr_T start_lnum, /* first line to start searching */ + linenr_T end_lnum /* last line for searching */ +) { SearchedFile *files; /* Stack of included files */ SearchedFile *bigger; /* When we need more space */ @@ -4554,14 +4530,7 @@ fpip_end: vim_regfree(def_regmatch.regprog); } -static void show_pat_in_path(line, type, did_show, action, fp, lnum, count) -char_u *line; -int type; -int did_show; -int action; -FILE *fp; -linenr_T *lnum; -long count; +static void show_pat_in_path(char_u *line, int type, int did_show, int action, FILE *fp, linenr_T *lnum, long count) { char_u *p; @@ -4609,9 +4578,7 @@ long count; } } -int read_viminfo_search_pattern(virp, force) -vir_T *virp; -int force; +int read_viminfo_search_pattern(vir_T *virp, int force) { char_u *lp; int idx = -1; @@ -4684,8 +4651,7 @@ int force; return viminfo_readline(virp); } -void write_viminfo_search_pattern(fp) -FILE *fp; +void write_viminfo_search_pattern(FILE *fp) { if (get_viminfo_parameter('/') != 0) { fprintf(fp, "\n# hlsearch on (H) or off (h):\n~%c", @@ -4695,11 +4661,13 @@ FILE *fp; } } -static void wvsp_one(fp, idx, s, sc) -FILE *fp; /* file to write to */ -int idx; /* spats[] index */ -char *s; /* search pat */ -int sc; /* dir char */ +static void +wvsp_one ( + FILE *fp, /* file to write to */ + int idx, /* spats[] index */ + char *s, /* search pat */ + int sc /* dir char */ +) { if (spats[idx].pat != NULL) { fprintf(fp, _("\n# Last %sSearch Pattern:\n~"), s); diff --git a/src/sha256.c b/src/sha256.c index 0761987ebe..16ee6cfad0 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -41,8 +41,7 @@ static void sha256_process __ARGS((context_sha256_T *ctx, char_u data[64])); (b)[(i) + 3] = (char_u)((n) ); \ } -void sha256_start(ctx) -context_sha256_T *ctx; +void sha256_start(context_sha256_T *ctx) { ctx->total[0] = 0; ctx->total[1] = 0; @@ -57,9 +56,7 @@ context_sha256_T *ctx; ctx->state[7] = 0x5BE0CD19; } -static void sha256_process(ctx, data) -context_sha256_T *ctx; -char_u data[64]; +static void sha256_process(context_sha256_T *ctx, char_u data[64]) { UINT32_T temp1, temp2, W[64]; UINT32_T A, B, C, D, E, F, G, H; @@ -190,10 +187,7 @@ char_u data[64]; ctx->state[7] += H; } -void sha256_update(ctx, input, length) -context_sha256_T *ctx; -char_u *input; -UINT32_T length; +void sha256_update(context_sha256_T *ctx, char_u *input, UINT32_T length) { UINT32_T left, fill; @@ -234,9 +228,7 @@ static char_u sha256_padding[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void sha256_finish(ctx, digest) -context_sha256_T *ctx; -char_u digest[32]; +void sha256_finish(context_sha256_T *ctx, char_u digest[32]) { UINT32_T last, padn; UINT32_T high, low; @@ -270,11 +262,7 @@ static unsigned int get_some_time __ARGS((void)); * Returns hex digest of "buf[buf_len]" in a static array. * if "salt" is not NULL also do "salt[salt_len]". */ -char_u * sha256_bytes(buf, buf_len, salt, salt_len) -char_u *buf; -int buf_len; -char_u *salt; -int salt_len; +char_u *sha256_bytes(char_u *buf, int buf_len, char_u *salt, int salt_len) { char_u sha256sum[32]; static char_u hexit[65]; @@ -297,10 +285,7 @@ int salt_len; /* * Returns sha256(buf) as 64 hex chars in static array. */ -char_u * sha256_key(buf, salt, salt_len) -char_u *buf; -char_u *salt; -int salt_len; +char_u *sha256_key(char_u *buf, char_u *salt, int salt_len) { /* No passwd means don't encrypt */ if (buf == NULL || *buf == NUL) @@ -332,7 +317,7 @@ static char *sha_self_test_vector[] = { * Perform a test on the SHA256 algorithm. * Return FAIL or OK. */ -int sha256_self_test() { +int sha256_self_test(void) { int i, j; char output[65]; context_sha256_T ctx; @@ -370,7 +355,7 @@ int sha256_self_test() { return failures > 0 ? FAIL : OK; } -static unsigned int get_some_time() { +static unsigned int get_some_time(void) { # ifdef HAVE_GETTIMEOFDAY struct timeval tv; @@ -386,11 +371,7 @@ static unsigned int get_some_time() { * Fill "header[header_len]" with random_data. * Also "salt[salt_len]" when "salt" is not NULL. */ -void sha2_seed(header, header_len, salt, salt_len) -char_u *header; -int header_len; -char_u *salt; -int salt_len; +void sha2_seed(char_u *header, int header_len, char_u *salt, int salt_len) { int i; static char_u random_data[1000]; diff --git a/src/spell.c b/src/spell.c index 05c6543ef6..941ac08b05 100644 --- a/src/spell.c +++ b/src/spell.c @@ -996,12 +996,14 @@ static char_u *repl_to = NULL; * Returns the length of the word in bytes, also when it's OK, so that the * caller can skip over the word. */ -int spell_check(wp, ptr, attrp, capcol, docount) -win_T *wp; /* current window */ -char_u *ptr; -hlf_T *attrp; -int *capcol; /* column to check for Capital */ -int docount; /* count good words */ +int +spell_check ( + win_T *wp, /* current window */ + char_u *ptr, + hlf_T *attrp, + int *capcol, /* column to check for Capital */ + int docount /* count good words */ +) { matchinf_T mi; /* Most things are put in "mi" so that it can be passed to functions quickly. */ @@ -1191,9 +1193,7 @@ int docount; /* count good words */ * * For a match mip->mi_result is updated. */ -static void find_word(mip, mode) -matchinf_T *mip; -int mode; +static void find_word(matchinf_T *mip, int mode) { idx_T arridx = 0; int endlen[MAXWLEN]; /* length at possible word endings */ @@ -1643,10 +1643,12 @@ int mode; * A match means that the first part of CHECKCOMPOUNDPATTERN matches at the * end of ptr[wlen] and the second part matches after it. */ -static int match_checkcompoundpattern(ptr, wlen, gap) -char_u *ptr; -int wlen; -garray_T *gap; /* &sl_comppat */ +static int +match_checkcompoundpattern ( + char_u *ptr, + int wlen, + garray_T *gap /* &sl_comppat */ +) { int i; char_u *p; @@ -1670,10 +1672,7 @@ garray_T *gap; /* &sl_comppat */ * Return TRUE if "flags" is a valid sequence of compound flags and "word" * does not have too many syllables. */ -static int can_compound(slang, word, flags) -slang_T *slang; -char_u *word; -char_u *flags; +static int can_compound(slang_T *slang, char_u *word, char_u *flags) { regmatch_T regmatch; char_u uflags[MAXWLEN * 2]; @@ -1710,11 +1709,7 @@ char_u *flags; * possibly form a valid compounded word. This also checks the COMPOUNDRULE * lines if they don't contain wildcards. */ -static int can_be_compound(sp, slang, compflags, flag) -trystate_T *sp; -slang_T *slang; -char_u *compflags; -int flag; +static int can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, int flag) { /* If the flag doesn't appear in sl_compstartflags or sl_compallflags * then it can't possibly compound. */ @@ -1745,9 +1740,7 @@ int flag; * collected so far can't possibly match any compound rule. * Caller must check that slang->sl_comprules is not NULL. */ -static int match_compoundrule(slang, compflags) -slang_T *slang; -char_u *compflags; +static int match_compoundrule(slang_T *slang, char_u *compflags) { char_u *p; int i; @@ -1795,13 +1788,15 @@ char_u *compflags; * ID in "flags" for the word "word". * The WF_RAREPFX flag is included in the return value for a rare prefix. */ -static int valid_word_prefix(totprefcnt, arridx, flags, word, slang, cond_req) -int totprefcnt; /* nr of prefix IDs */ -int arridx; /* idx in sl_pidxs[] */ -int flags; -char_u *word; -slang_T *slang; -int cond_req; /* only use prefixes with a condition */ +static int +valid_word_prefix ( + int totprefcnt, /* nr of prefix IDs */ + int arridx, /* idx in sl_pidxs[] */ + int flags, + char_u *word, + slang_T *slang, + int cond_req /* only use prefixes with a condition */ +) { int prefcnt; int pidx; @@ -1848,9 +1843,7 @@ int cond_req; /* only use prefixes with a condition */ * * For a match mip->mi_result is updated. */ -static void find_prefix(mip, mode) -matchinf_T *mip; -int mode; +static void find_prefix(matchinf_T *mip, int mode) { idx_T arridx = 0; int len; @@ -1960,8 +1953,7 @@ int mode; * for efficiency. Include the non-word character too. * Return the length of the folded chars in bytes. */ -static int fold_more(mip) -matchinf_T *mip; +static int fold_more(matchinf_T *mip) { int flen; char_u *p; @@ -1987,9 +1979,11 @@ matchinf_T *mip; * Check case flags for a word. Return TRUE if the word has the requested * case. */ -static int spell_valid_case(wordflags, treeflags) -int wordflags; /* flags for the checked word. */ -int treeflags; /* flags for the word in the spell tree */ +static int +spell_valid_case ( + int wordflags, /* flags for the checked word. */ + int treeflags /* flags for the word in the spell tree */ +) { return (wordflags == WF_ALLCAP && (treeflags & WF_FIXCAP) == 0) || ((treeflags & (WF_ALLCAP | WF_KEEPCAP)) == 0 @@ -2000,8 +1994,7 @@ int treeflags; /* flags for the word in the spell tree */ /* * Return TRUE if spell checking is not enabled. */ -static int no_spell_checking(wp) -win_T *wp; +static int no_spell_checking(win_T *wp) { if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL || wp->w_s->b_langp.ga_len == 0) { @@ -2019,13 +2012,15 @@ win_T *wp; * to after badly spelled word before the cursor. * Return 0 if not found, length of the badly spelled word otherwise. */ -int spell_move_to(wp, dir, allwords, curline, attrp) -win_T *wp; -int dir; /* FORWARD or BACKWARD */ -int allwords; /* TRUE for "[s"/"]s", FALSE for "[S"/"]S" */ -int curline; -hlf_T *attrp; /* return: attributes of bad word or NULL +int +spell_move_to ( + win_T *wp, + int dir, /* FORWARD or BACKWARD */ + int allwords, /* TRUE for "[s"/"]s", FALSE for "[S"/"]S" */ + int curline, + hlf_T *attrp /* return: attributes of bad word or NULL (only when "dir" is FORWARD) */ +) { linenr_T lnum; pos_T found_pos; @@ -2240,10 +2235,7 @@ hlf_T *attrp; /* return: attributes of bad word or NULL * Keep the blanks at the start of the next line, this is used in win_line() * to skip those bytes if the word was OK. */ -void spell_cat_line(buf, line, maxlen) -char_u *buf; -char_u *line; -int maxlen; +void spell_cat_line(char_u *buf, char_u *line, int maxlen) { char_u *p; int n; @@ -2276,8 +2268,7 @@ typedef struct spelload_S { * Load word list(s) for "lang" from Vim spell file(s). * "lang" must be the language without the region: e.g., "en". */ -static void spell_load_lang(lang) -char_u *lang; +static void spell_load_lang(char_u *lang) { char_u fname_enc[85]; int r; @@ -2332,7 +2323,7 @@ char_u *lang; * Return the encoding used for spell checking: Use 'encoding', except that we * use "latin1" for "latin9". And limit to 60 characters (just in case). */ -static char_u * spell_enc() { +static char_u *spell_enc(void) { if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) return p_enc; @@ -2343,8 +2334,7 @@ static char_u * spell_enc() { * Get the name of the .spl file for the internal wordlist into * "fname[MAXPATHL]". */ -static void int_wordlist_spl(fname) -char_u *fname; +static void int_wordlist_spl(char_u *fname) { vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL, int_wordlist, spell_enc()); @@ -2354,8 +2344,7 @@ char_u *fname; * Allocate a new slang_T for language "lang". "lang" can be NULL. * Caller must fill "sl_next". */ -static slang_T * slang_alloc(lang) -char_u *lang; +static slang_T *slang_alloc(char_u *lang) { slang_T *lp; @@ -2376,8 +2365,7 @@ char_u *lang; /* * Free the contents of an slang_T and the structure itself. */ -static void slang_free(lp) -slang_T *lp; +static void slang_free(slang_T *lp) { vim_free(lp->sl_name); vim_free(lp->sl_fname); @@ -2388,8 +2376,7 @@ slang_T *lp; /* * Clear an slang_T so that the file can be reloaded. */ -static void slang_clear(lp) -slang_T *lp; +static void slang_clear(slang_T *lp) { garray_T *gap; fromto_T *ftp; @@ -2485,8 +2472,7 @@ slang_T *lp; /* * Clear the info from the .sug file in "lp". */ -static void slang_clear_sug(lp) -slang_T *lp; +static void slang_clear_sug(slang_T *lp) { vim_free(lp->sl_sbyts); lp->sl_sbyts = NULL; @@ -2502,9 +2488,7 @@ slang_T *lp; * Load one spell file and store the info into a slang_T. * Invoked through do_in_runtimepath(). */ -static void spell_load_cb(fname, cookie) -char_u *fname; -void *cookie; +static void spell_load_cb(char_u *fname, void *cookie) { spelload_T *slp = (spelload_T *)cookie; slang_T *slang; @@ -2535,11 +2519,13 @@ void *cookie; * * Returns the slang_T the spell file was loaded into. NULL for error. */ -static slang_T * spell_load_file(fname, lang, old_lp, silent) -char_u *fname; -char_u *lang; -slang_T *old_lp; -int silent; /* no error if file doesn't exist */ +static slang_T * +spell_load_file ( + char_u *fname, + char_u *lang, + slang_T *old_lp, + int silent /* no error if file doesn't exist */ +) { FILE *fd; char_u buf[VIMSPELLMAGICL]; @@ -2773,10 +2759,7 @@ endOK: * Sets "*cntp" to SP_*ERROR when there is an error, length of the result * otherwise. */ -static char_u * read_cnt_string(fd, cnt_bytes, cntp) -FILE *fd; -int cnt_bytes; -int *cntp; +static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp) { int cnt = 0; int i; @@ -2803,10 +2786,7 @@ int *cntp; * Read SN_REGION: ... * Return SP_*ERROR flags. */ -static int read_region_section(fd, lp, len) -FILE *fd; -slang_T *lp; -int len; +static int read_region_section(FILE *fd, slang_T *lp, int len) { int i; @@ -2823,8 +2803,7 @@ int len; * * Return SP_*ERROR flags. */ -static int read_charflags_section(fd) -FILE *fd; +static int read_charflags_section(FILE *fd) { char_u *flags; char_u *fol; @@ -2859,9 +2838,7 @@ FILE *fd; * Read SN_PREFCOND section. * Return SP_*ERROR flags. */ -static int read_prefcond_section(fd, lp) -FILE *fd; -slang_T *lp; +static int read_prefcond_section(FILE *fd, slang_T *lp) { int cnt; int i; @@ -2904,10 +2881,7 @@ slang_T *lp; * Read REP or REPSAL items section from "fd": ... * Return SP_*ERROR flags. */ -static int read_rep_section(fd, gap, first) -FILE *fd; -garray_T *gap; -short *first; +static int read_rep_section(FILE *fd, garray_T *gap, short *first) { int cnt; fromto_T *ftp; @@ -2952,9 +2926,7 @@ short *first; * Read SN_SAL section: ... * Return SP_*ERROR flags. */ -static int read_sal_section(fd, slang) -FILE *fd; -slang_T *slang; +static int read_sal_section(FILE *fd, slang_T *slang) { int i; int cnt; @@ -3090,10 +3062,7 @@ slang_T *slang; * Read SN_WORDS: ... * Return SP_*ERROR flags. */ -static int read_words_section(fd, lp, len) -FILE *fd; -slang_T *lp; -int len; +static int read_words_section(FILE *fd, slang_T *lp, int len) { int done = 0; int i; @@ -3124,11 +3093,13 @@ int len; * Add a word to the hashtable of common words. * If it's already there then the counter is increased. */ -static void count_common_word(lp, word, len, count) -slang_T *lp; -char_u *word; -int len; /* word length, -1 for upto NUL */ -int count; /* 1 to count once, 10 to init */ +static void +count_common_word ( + slang_T *lp, + char_u *word, + int len, /* word length, -1 for upto NUL */ + int count /* 1 to count once, 10 to init */ +) { hash_T hash; hashitem_T *hi; @@ -3162,11 +3133,13 @@ int count; /* 1 to count once, 10 to init */ /* * Adjust the score of common words. */ -static int score_wordcount_adj(slang, score, word, split) -slang_T *slang; -int score; -char_u *word; -int split; /* word was split, less bonus */ +static int +score_wordcount_adj ( + slang_T *slang, + int score, + char_u *word, + int split /* word was split, less bonus */ +) { hashitem_T *hi; wordcount_T *wc; @@ -3197,9 +3170,7 @@ int split; /* word was split, less bonus */ * SN_SOFO: * Return SP_*ERROR flags. */ -static int read_sofo_section(fd, slang) -FILE *fd; -slang_T *slang; +static int read_sofo_section(FILE *fd, slang_T *slang) { int cnt; char_u *from, *to; @@ -3237,10 +3208,7 @@ slang_T *slang; * * Returns SP_*ERROR flags. */ -static int read_compound(fd, slang, len) -FILE *fd; -slang_T *slang; -int len; +static int read_compound(FILE *fd, slang_T *slang, int len) { int todo = len; int c; @@ -3416,9 +3384,7 @@ int len; * Return TRUE if byte "n" appears in "str". * Like strchr() but independent of locale. */ -static int byte_in_str(str, n) -char_u *str; -int n; +static int byte_in_str(char_u *str, int n) { char_u *p; @@ -3438,8 +3404,7 @@ typedef struct syl_item_S { * Truncate "slang->sl_syllable" at the first slash and put the following items * in "slang->sl_syl_items". */ -static int init_syl_tab(slang) -slang_T *slang; +static int init_syl_tab(slang_T *slang) { char_u *p; char_u *s; @@ -3475,9 +3440,7 @@ slang_T *slang; * When "word" contains spaces the syllables after the last space are counted. * Returns zero if syllables are not defines. */ -static int count_syllables(slang, word) -slang_T *slang; -char_u *word; +static int count_syllables(slang_T *slang, char_u *word) { int cnt = 0; int skip = FALSE; @@ -3528,10 +3491,7 @@ char_u *word; * Set the SOFOFROM and SOFOTO items in language "lp". * Returns SP_*ERROR flags when there is something wrong. */ -static int set_sofo(lp, from, to) -slang_T *lp; -char_u *from; -char_u *to; +static int set_sofo(slang_T *lp, char_u *from, char_u *to) { int i; @@ -3609,8 +3569,7 @@ char_u *to; /* * Fill the first-index table for "lp". */ -static void set_sal_first(lp) -slang_T *lp; +static void set_sal_first(slang_T *lp) { salfirst_T *sfirst; int i; @@ -3665,8 +3624,7 @@ slang_T *lp; * Turn a multi-byte string into a wide character string. * Return it in allocated memory (NULL for out-of-memory) */ -static int * mb_str2wide(s) -char_u *s; +static int *mb_str2wide(char_u *s) { int *res; char_u *p; @@ -3687,12 +3645,14 @@ char_u *s; * This is skipped when the tree has zero length. * Returns zero when OK, SP_ value for an error. */ -static int spell_read_tree(fd, bytsp, idxsp, prefixtree, prefixcnt) -FILE *fd; -char_u **bytsp; -idx_T **idxsp; -int prefixtree; /* TRUE for the prefix tree */ -int prefixcnt; /* when "prefixtree" is TRUE: prefix count */ +static int +spell_read_tree ( + FILE *fd, + char_u **bytsp, + idx_T **idxsp, + int prefixtree, /* TRUE for the prefix tree */ + int prefixcnt /* when "prefixtree" is TRUE: prefix count */ +) { int len; int idx; @@ -3735,15 +3695,16 @@ int prefixcnt; /* when "prefixtree" is TRUE: prefix count */ * Returns SP_TRUNCERROR if the file is shorter than expected. * Returns SP_FORMERROR if there is a format error. */ -static idx_T read_tree_node(fd, byts, idxs, maxidx, startidx, prefixtree, - maxprefcondnr) -FILE *fd; -char_u *byts; -idx_T *idxs; -int maxidx; /* size of arrays */ -idx_T startidx; /* current index in "byts" and "idxs" */ -int prefixtree; /* TRUE for reading PREFIXTREE */ -int maxprefcondnr; /* maximum for */ +static idx_T +read_tree_node ( + FILE *fd, + char_u *byts, + idx_T *idxs, + int maxidx, /* size of arrays */ + idx_T startidx, /* current index in "byts" and "idxs" */ + int prefixtree, /* TRUE for reading PREFIXTREE */ + int maxprefcondnr /* maximum for */ +) { int len; int i; @@ -3839,8 +3800,7 @@ int maxprefcondnr; /* maximum for */ * Parse 'spelllang' and set w_s->b_langp accordingly. * Returns NULL if it's OK, an error message otherwise. */ -char_u * did_set_spelllang(wp) -win_T *wp; +char_u *did_set_spelllang(win_T *wp) { garray_T ga; char_u *splp; @@ -4120,8 +4080,7 @@ theend: /* * Clear the midword characters for buffer "buf". */ -static void clear_midword(wp) -win_T *wp; +static void clear_midword(win_T *wp) { vim_memset(wp->w_s->b_spell_ismw, 0, 256); vim_free(wp->w_s->b_spell_ismw_mb); @@ -4132,9 +4091,7 @@ win_T *wp; * Use the "sl_midword" field of language "lp" for buffer "buf". * They add up to any currently used midword characters. */ -static void use_midword(lp, wp) -slang_T *lp; -win_T *wp; +static void use_midword(slang_T *lp, win_T *wp) { char_u *p; @@ -4173,9 +4130,7 @@ win_T *wp; * Each region is simply stored as the two characters of it's name. * Returns the index if found (first is 0), REGION_ALL if not found. */ -static int find_region(rp, region) -char_u *rp; -char_u *region; +static int find_region(char_u *rp, char_u *region) { int i; @@ -4195,9 +4150,11 @@ char_u *region; * W WORD WF_ALLCAP * WoRd wOrd WF_KEEPCAP */ -static int captype(word, end) -char_u *word; -char_u *end; /* When NULL use up to NUL byte. */ +static int +captype ( + char_u *word, + char_u *end /* When NULL use up to NUL byte. */ +) { char_u *p; int c; @@ -4245,9 +4202,7 @@ char_u *end; /* When NULL use up to NUL byte. */ * capital. So that make_case_word() can turn WOrd into Word. * Add ALLCAP for "WOrD". */ -static int badword_captype(word, end) -char_u *word; -char_u *end; +static int badword_captype(char_u *word, char_u *end) { int flags = captype(word, end); int c; @@ -4287,7 +4242,7 @@ char_u *end; /* * Delete the internal wordlist and its .spl file. */ -void spell_delete_wordlist() { +void spell_delete_wordlist(void) { char_u fname[MAXPATHL]; if (int_wordlist != NULL) { @@ -4302,7 +4257,7 @@ void spell_delete_wordlist() { /* * Free all languages. */ -void spell_free_all() { +void spell_free_all(void) { slang_T *slang; buf_T *buf; @@ -4328,7 +4283,7 @@ void spell_free_all() { * Clear all spelling tables and reload them. * Used after 'encoding' is set and when ":mkspell" was used. */ -void spell_reload() { +void spell_reload(void) { win_T *wp; /* Initialize the table for spell_iswordp(). */ @@ -4353,9 +4308,11 @@ void spell_reload() { /* * Reload the spell file "fname" if it's loaded. */ -static void spell_reload_one(fname, added_word) -char_u *fname; -int added_word; /* invoked through "zg" */ +static void +spell_reload_one ( + char_u *fname, + int added_word /* invoked through "zg" */ +) { slang_T *slang; int didit = FALSE; @@ -4756,9 +4713,7 @@ static void spell_print_tree(wordnode_T *root) { * Read the affix file "fname". * Returns an afffile_T, NULL for complete failure. */ -static afffile_T * spell_read_aff(spin, fname) -spellinfo_T *spin; -char_u *fname; +static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) { FILE *fd; afffile_T *aff; @@ -5536,11 +5491,7 @@ char_u *fname; * Return TRUE when items[0] equals "rulename", there are "mincount" items or * a comment is following after item "mincount". */ -static int is_aff_rule(items, itemcnt, rulename, mincount) -char_u **items; -int itemcnt; -char *rulename; -int mincount; +static int is_aff_rule(char_u **items, int itemcnt, char *rulename, int mincount) { return STRCMP(items[0], rulename) == 0 && (itemcnt == mincount @@ -5551,9 +5502,7 @@ int mincount; * For affix "entry" move COMPOUNDFORBIDFLAG and COMPOUNDPERMITFLAG from * ae_flags to ae_comppermit and ae_compforbid. */ -static void aff_process_flags(affile, entry) -afffile_T *affile; -affentry_T *entry; +static void aff_process_flags(afffile_T *affile, affentry_T *entry) { char_u *p; char_u *prevp; @@ -5583,8 +5532,7 @@ affentry_T *entry; /* * Return TRUE if "s" is the name of an info item in the affix file. */ -static int spell_info_item(s) -char_u *s; +static int spell_info_item(char_u *s) { return STRCMP(s, "NAME") == 0 || STRCMP(s, "HOME") == 0 @@ -5598,11 +5546,7 @@ char_u *s; * Turn an affix flag name into a number, according to the FLAG type. * returns zero for failure. */ -static unsigned affitem2flag(flagtype, item, fname, lnum) -int flagtype; -char_u *item; -char_u *fname; -int lnum; +static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum) { unsigned res; char_u *p = item; @@ -5628,9 +5572,7 @@ int lnum; * Get one affix name from "*pp" and advance the pointer. * Returns zero for an error, still advances the pointer then. */ -static unsigned get_affitem(flagtype, pp) -int flagtype; -char_u **pp; +static unsigned get_affitem(int flagtype, char_u **pp) { int res; @@ -5658,10 +5600,7 @@ char_u **pp; * The processing involves changing the affix names to ID numbers, so that * they fit in one byte. */ -static void process_compflags(spin, aff, compflags) -spellinfo_T *spin; -afffile_T *aff; -char_u *compflags; +static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compflags) { char_u *p; char_u *prevp; @@ -5735,8 +5674,7 @@ char_u *compflags; * using two bytes for utf-8. When the 0-127 range is used up go to 128-255. * When that is used up an error message is given. */ -static void check_renumber(spin) -spellinfo_T *spin; +static void check_renumber(spellinfo_T *spin) { if (spin->si_newprefID == spin->si_newcompID && spin->si_newcompID < 128) { spin->si_newprefID = 127; @@ -5747,10 +5685,7 @@ spellinfo_T *spin; /* * Return TRUE if flag "flag" appears in affix list "afflist". */ -static int flag_in_afflist(flagtype, afflist, flag) -int flagtype; -char_u *afflist; -unsigned flag; +static int flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) { char_u *p; unsigned n; @@ -5787,10 +5722,7 @@ unsigned flag; /* * Give a warning when "spinval" and "affval" numbers are set and not the same. */ -static void aff_check_number(spinval, affval, name) -int spinval; -int affval; -char *name; +static void aff_check_number(int spinval, int affval, char *name) { if (spinval != 0 && spinval != affval) smsg((char_u *)_( @@ -5800,10 +5732,7 @@ char *name; /* * Give a warning when "spinval" and "affval" strings are set and not the same. */ -static void aff_check_string(spinval, affval, name) -char_u *spinval; -char_u *affval; -char *name; +static void aff_check_string(char_u *spinval, char_u *affval, char *name) { if (spinval != NULL && STRCMP(spinval, affval) != 0) smsg((char_u *)_( @@ -5814,9 +5743,7 @@ char *name; * Return TRUE if strings "s1" and "s2" are equal. Also consider both being * NULL as equal. */ -static int str_equal(s1, s2) -char_u *s1; -char_u *s2; +static int str_equal(char_u *s1, char_u *s2) { if (s1 == NULL || s2 == NULL) return s1 == s2; @@ -5827,11 +5754,7 @@ char_u *s2; * Add a from-to item to "gap". Used for REP and SAL items. * They are stored case-folded. */ -static void add_fromto(spin, gap, from, to) -spellinfo_T *spin; -garray_T *gap; -char_u *from; -char_u *to; +static void add_fromto(spellinfo_T *spin, garray_T *gap, char_u *from, char_u *to) { fromto_T *ftp; char_u word[MAXWLEN]; @@ -5849,8 +5772,7 @@ char_u *to; /* * Convert a boolean argument in a SAL line to TRUE or FALSE; */ -static int sal_to_bool(s) -char_u *s; +static int sal_to_bool(char_u *s) { return STRCMP(s, "1") == 0 || STRCMP(s, "true") == 0; } @@ -5858,8 +5780,7 @@ char_u *s; /* * Free the structure filled by spell_read_aff(). */ -static void spell_free_aff(aff) -afffile_T *aff; +static void spell_free_aff(afffile_T *aff) { hashtab_T *ht; hashitem_T *hi; @@ -5893,10 +5814,7 @@ afffile_T *aff; * Read dictionary file "fname". * Returns OK or FAIL; */ -static int spell_read_dic(spin, fname, affile) -spellinfo_T *spin; -char_u *fname; -afffile_T *affile; +static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) { hashtab_T ht; char_u line[MAXLINELEN]; @@ -6092,9 +6010,7 @@ afffile_T *affile; * Check for affix flags in "afflist" that are turned into word flags. * Return WF_ flags. */ -static int get_affix_flags(affile, afflist) -afffile_T *affile; -char_u *afflist; +static int get_affix_flags(afffile_T *affile, char_u *afflist) { int flags = 0; @@ -6125,10 +6041,7 @@ char_u *afflist; * Put the resulting flags in "store_afflist[MAXWLEN]" with a terminating NUL * and return the number of affixes. */ -static int get_pfxlist(affile, afflist, store_afflist) -afffile_T *affile; -char_u *afflist; -char_u *store_afflist; +static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist) { char_u *p; char_u *prevp; @@ -6163,10 +6076,7 @@ char_u *store_afflist; * for compound words. * Puts the flags in "store_afflist[]". */ -static void get_compflags(affile, afflist, store_afflist) -afffile_T *affile; -char_u *afflist; -char_u *store_afflist; +static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_afflist) { char_u *p; char_u *prevp; @@ -6199,19 +6109,20 @@ char_u *store_afflist; * * Returns FAIL when out of memory. */ -static int store_aff_word(spin, word, afflist, affile, ht, xht, condit, flags, - pfxlist, pfxlen) -spellinfo_T *spin; /* spell info */ -char_u *word; /* basic word start */ -char_u *afflist; /* list of names of supported affixes */ -afffile_T *affile; -hashtab_T *ht; -hashtab_T *xht; -int condit; /* CONDIT_SUF et al. */ -int flags; /* flags for the word */ -char_u *pfxlist; /* list of prefix IDs */ -int pfxlen; /* nr of flags in "pfxlist" for prefixes, rest +static int +store_aff_word ( + spellinfo_T *spin, /* spell info */ + char_u *word, /* basic word start */ + char_u *afflist, /* list of names of supported affixes */ + afffile_T *affile, + hashtab_T *ht, + hashtab_T *xht, + int condit, /* CONDIT_SUF et al. */ + int flags, /* flags for the word */ + char_u *pfxlist, /* list of prefix IDs */ + int pfxlen /* nr of flags in "pfxlist" for prefixes, rest * is compound flags */ +) { int todo; hashitem_T *hi; @@ -6442,9 +6353,7 @@ int pfxlen; /* nr of flags in "pfxlist" for prefixes, rest /* * Read a file with a list of words. */ -static int spell_read_wordfile(spin, fname) -spellinfo_T *spin; -char_u *fname; +static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) { FILE *fd; long lnum = 0; @@ -6626,10 +6535,12 @@ char_u *fname; * The memory is cleared to all zeros. * Returns NULL when out of memory. */ -static void * getroom(spin, len, align) -spellinfo_T *spin; -size_t len; /* length needed */ -int align; /* align for pointer */ +static void * +getroom ( + spellinfo_T *spin, + size_t len, /* length needed */ + int align /* align for pointer */ +) { char_u *p; sblock_T *bl = spin->si_blocks; @@ -6670,9 +6581,7 @@ int align; /* align for pointer */ * Make a copy of a string into memory allocated with getroom(). * Returns NULL when out of memory. */ -static char_u * getroom_save(spin, s) -spellinfo_T *spin; -char_u *s; +static char_u *getroom_save(spellinfo_T *spin, char_u *s) { char_u *sc; @@ -6686,8 +6595,7 @@ char_u *s; /* * Free the list of allocated sblock_T. */ -static void free_blocks(bl) -sblock_T *bl; +static void free_blocks(sblock_T *bl) { sblock_T *next; @@ -6702,8 +6610,7 @@ sblock_T *bl; * Allocate the root of a word tree. * Returns NULL when out of memory. */ -static wordnode_T * wordtree_alloc(spin) -spellinfo_T *spin; +static wordnode_T *wordtree_alloc(spellinfo_T *spin) { return (wordnode_T *)getroom(spin, sizeof(wordnode_T), TRUE); } @@ -6717,13 +6624,15 @@ spellinfo_T *spin; * When "pfxlist" is not NULL store the word for each postponed prefix ID and * compound flag. */ -static int store_word(spin, word, flags, region, pfxlist, need_affix) -spellinfo_T *spin; -char_u *word; -int flags; /* extra flags, WF_BANNED */ -int region; /* supported region(s) */ -char_u *pfxlist; /* list of prefix IDs or NULL */ -int need_affix; /* only store word with affix ID */ +static int +store_word ( + spellinfo_T *spin, + char_u *word, + int flags, /* extra flags, WF_BANNED */ + int region, /* supported region(s) */ + char_u *pfxlist, /* list of prefix IDs or NULL */ + int need_affix /* only store word with affix ID */ +) { int len = (int)STRLEN(word); int ct = captype(word, word + len); @@ -6760,13 +6669,7 @@ int need_affix; /* only store word with affix ID */ * "rare" and "region" is the condition nr. * Returns FAIL when out of memory. */ -static int tree_add_word(spin, word, root, flags, region, affixID) -spellinfo_T *spin; -char_u *word; -wordnode_T *root; -int flags; -int region; -int affixID; +static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int flags, int region, int affixID) { wordnode_T *node = root; wordnode_T *np; @@ -6929,7 +6832,7 @@ int affixID; * Check the 'mkspellmem' option. Return FAIL if it's wrong. * Sets "sps_flags". */ -int spell_check_msm() { +int spell_check_msm(void) { char_u *p = p_msm; long start = 0; long incr = 0; @@ -6968,8 +6871,7 @@ int spell_check_msm() { * allocate a new one. * Returns NULL when out of memory. */ -static wordnode_T * get_wordnode(spin) -spellinfo_T *spin; +static wordnode_T *get_wordnode(spellinfo_T *spin) { wordnode_T *n; @@ -6994,9 +6896,7 @@ spellinfo_T *spin; * siblings. * Returns the number of nodes actually freed. */ -static int deref_wordnode(spin, node) -spellinfo_T *spin; -wordnode_T *node; +static int deref_wordnode(spellinfo_T *spin, wordnode_T *node) { wordnode_T *np; int cnt = 0; @@ -7017,9 +6917,7 @@ wordnode_T *node; * Free a wordnode_T for re-use later. * Only the "wn_child" field becomes invalid. */ -static void free_wordnode(spin, n) -spellinfo_T *spin; -wordnode_T *n; +static void free_wordnode(spellinfo_T *spin, wordnode_T *n) { n->wn_child = spin->si_first_free; spin->si_first_free = n; @@ -7029,9 +6927,7 @@ wordnode_T *n; /* * Compress a tree: find tails that are identical and can be shared. */ -static void wordtree_compress(spin, root) -spellinfo_T *spin; -wordnode_T *root; +static void wordtree_compress(spellinfo_T *spin, wordnode_T *root) { hashtab_T ht; int n; @@ -7070,12 +6966,14 @@ wordnode_T *root; * Compress a node, its siblings and its children, depth first. * Returns the number of compressed nodes. */ -static int node_compress(spin, node, ht, tot) -spellinfo_T *spin; -wordnode_T *node; -hashtab_T *ht; -int *tot; /* total count of nodes before compressing, +static int +node_compress ( + spellinfo_T *spin, + wordnode_T *node, + hashtab_T *ht, + int *tot /* total count of nodes before compressing, incremented while going through the tree */ +) { wordnode_T *np; wordnode_T *tp; @@ -7168,9 +7066,7 @@ int *tot; /* total count of nodes before compressing, /* * Return TRUE when two nodes have identical siblings and children. */ -static int node_equal(n1, n2) -wordnode_T *n1; -wordnode_T *n2; +static int node_equal(wordnode_T *n1, wordnode_T *n2) { wordnode_T *p1; wordnode_T *p2; @@ -7194,9 +7090,7 @@ rep_compare __ARGS((const void *s1, const void *s2)); /* * Function given to qsort() to sort the REP items on "from" string. */ -static int rep_compare(s1, s2) -const void *s1; -const void *s2; +static int rep_compare(const void *s1, const void *s2) { fromto_T *p1 = (fromto_T *)s1; fromto_T *p2 = (fromto_T *)s2; @@ -7208,9 +7102,7 @@ const void *s2; * Write the Vim .spl file "fname". * Return FAIL or OK; */ -static int write_vim_spell(spin, fname) -spellinfo_T *spin; -char_u *fname; +static int write_vim_spell(spellinfo_T *spin, char_u *fname) { FILE *fd; int regionmask; @@ -7589,8 +7481,7 @@ theend: * children. This is needed because they are a union with other items to save * space. */ -static void clear_node(node) -wordnode_T *node; +static void clear_node(wordnode_T *node) { wordnode_T *np; @@ -7617,12 +7508,14 @@ wordnode_T *node; * * Returns the number of nodes used. */ -static int put_node(fd, node, idx, regionmask, prefixtree) -FILE *fd; /* NULL when only counting */ -wordnode_T *node; -int idx; -int regionmask; -int prefixtree; /* TRUE for PREFIXTREE */ +static int +put_node ( + FILE *fd, /* NULL when only counting */ + wordnode_T *node, + int idx, + int regionmask, + int prefixtree /* TRUE for PREFIXTREE */ +) { int newindex = idx; int siblingcount = 0; @@ -7727,8 +7620,7 @@ int prefixtree; /* TRUE for PREFIXTREE */ * ":mkspell [-ascii] outfile infile ..." * ":mkspell [-ascii] addfile" */ -void ex_mkspell(eap) -exarg_T *eap; +void ex_mkspell(exarg_T *eap) { int fcount; char_u **fnames; @@ -7752,9 +7644,7 @@ exarg_T *eap; * Uses the soundfold info in "spin". * Writes the file with the name "wfname", with ".spl" changed to ".sug". */ -static void spell_make_sugfile(spin, wfname) -spellinfo_T *spin; -char_u *wfname; +static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname) { char_u *fname = NULL; int len; @@ -7839,9 +7729,7 @@ theend: /* * Build the soundfold trie for language "slang". */ -static int sug_filltree(spin, slang) -spellinfo_T *spin; -slang_T *slang; +static int sug_filltree(spellinfo_T *spin, slang_T *slang) { char_u *byts; idx_T *idxs; @@ -7938,8 +7826,7 @@ slang_T *slang; * the table efficiently. * Returns FAIL when out of memory. */ -static int sug_maketable(spin) -spellinfo_T *spin; +static int sug_maketable(spellinfo_T *spin) { garray_T ga; int res = OK; @@ -7967,11 +7854,13 @@ spellinfo_T *spin; * Returns the wordnr at the start of the node. * Returns -1 when out of memory. */ -static int sug_filltable(spin, node, startwordnr, gap) -spellinfo_T *spin; -wordnode_T *node; -int startwordnr; -garray_T *gap; /* place to store line of numbers */ +static int +sug_filltable ( + spellinfo_T *spin, + wordnode_T *node, + int startwordnr, + garray_T *gap /* place to store line of numbers */ +) { wordnode_T *p, *np; int wordnr = startwordnr; @@ -8028,9 +7917,7 @@ garray_T *gap; /* place to store line of numbers */ * Similar to utf_char2byters, but use 8 bits in followup bytes and avoid NUL * bytes. */ -static int offset2bytes(nr, buf) -int nr; -char_u *buf; +static int offset2bytes(int nr, char_u *buf) { int rem; int b1, b2, b3, b4; @@ -8071,8 +7958,7 @@ char_u *buf; * "pp" points to the bytes and is advanced over it. * Returns the offset. */ -static int bytes2offset(pp) -char_u **pp; +static int bytes2offset(char_u **pp) { char_u *p = *pp; int nr; @@ -8102,9 +7988,7 @@ char_u **pp; /* * Write the .sug file in "fname". */ -static void sug_write(spin, fname) -spellinfo_T *spin; -char_u *fname; +static void sug_write(spellinfo_T *spin, char_u *fname) { FILE *fd; wordnode_T *tree; @@ -8196,7 +8080,7 @@ theend: * NULL and there is no undo info. * Returns NULL when out of memory. */ -static buf_T * open_spellbuf() { +static buf_T *open_spellbuf(void) { buf_T *buf; buf = (buf_T *)alloc_clear(sizeof(buf_T)); @@ -8213,8 +8097,7 @@ static buf_T * open_spellbuf() { /* * Close the buffer used for spell info. */ -static void close_spellbuf(buf) -buf_T *buf; +static void close_spellbuf(buf_T *buf) { if (buf != NULL) { ml_close(buf, TRUE); @@ -8230,12 +8113,14 @@ buf_T *buf; * Exception: when "fnames[0]" ends in ".add" it's used as the input file name * and ".spl" is appended to make the output file name. */ -static void mkspell(fcount, fnames, ascii, over_write, added_word) -int fcount; -char_u **fnames; -int ascii; /* -ascii argument given */ -int over_write; /* overwrite existing output file */ -int added_word; /* invoked through "zg" */ +static void +mkspell ( + int fcount, + char_u **fnames, + int ascii, /* -ascii argument given */ + int over_write, /* overwrite existing output file */ + int added_word /* invoked through "zg" */ +) { char_u *fname = NULL; char_u *wfname; @@ -8466,9 +8351,7 @@ theend: * Display a message for spell file processing when 'verbose' is set or using * ":mkspell". "str" can be IObuff. */ -static void spell_message(spin, str) -spellinfo_T *spin; -char_u *str; +static void spell_message(spellinfo_T *spin, char_u *str) { if (spin->si_verbose || p_verbose > 2) { if (!spin->si_verbose) @@ -8485,8 +8368,7 @@ char_u *str; * ":[count]spellwrong {word}" * ":[count]spellundo {word}" */ -void ex_spell(eap) -exarg_T *eap; +void ex_spell(exarg_T *eap) { spell_add_word(eap->arg, (int)STRLEN(eap->arg), eap->cmdidx == CMD_spellwrong, eap->forceit ? 0 : (int)eap->line2, @@ -8496,13 +8378,15 @@ exarg_T *eap; /* * Add "word[len]" to 'spellfile' as a good or bad word. */ -void spell_add_word(word, len, bad, idx, undo) -char_u *word; -int len; -int bad; -int idx; /* "zG" and "zW": zero, otherwise index in +void +spell_add_word ( + char_u *word, + int len, + int bad, + int idx, /* "zG" and "zW": zero, otherwise index in 'spellfile' */ -int undo; /* TRUE for "zug", "zuG", "zuw" and "zuW" */ + int undo /* TRUE for "zug", "zuG", "zuw" and "zuW" */ +) { FILE *fd = NULL; buf_T *buf = NULL; @@ -8644,7 +8528,7 @@ int undo; /* TRUE for "zug", "zuG", "zuw" and "zuW" */ /* * Initialize 'spellfile' for the current buffer. */ -static void init_spellfile() { +static void init_spellfile(void) { char_u *buf; int l; char_u *fname; @@ -8717,8 +8601,7 @@ static void init_spellfile() { * Init the chartab used for spelling for ASCII. * EBCDIC is not supported! */ -static void clear_spell_chartab(sp) -spelltab_T *sp; +static void clear_spell_chartab(spelltab_T *sp) { int i; @@ -8752,7 +8635,7 @@ spelltab_T *sp; * characters to make it possible that 'encoding' differs from the current * locale. For utf-8 we don't use isalpha() but our own functions. */ -void init_spell_chartab() { +void init_spell_chartab(void) { int i; did_set_spelltab = FALSE; @@ -8793,10 +8676,7 @@ void init_spell_chartab() { /* * Set the spell character tables from strings in the affix file. */ -static int set_spell_chartab(fol, low, upp) -char_u *fol; -char_u *low; -char_u *upp; +static int set_spell_chartab(char_u *fol, char_u *low, char_u *upp) { /* We build the new tables here first, so that we can compare with the * previous one. */ @@ -8857,10 +8737,12 @@ char_u *upp; /* * Set the spell character tables from strings in the .spl file. */ -static void set_spell_charflags(flags, cnt, fol) -char_u *flags; -int cnt; /* length of "flags" */ -char_u *fol; +static void +set_spell_charflags ( + char_u *flags, + int cnt, /* length of "flags" */ + char_u *fol +) { /* We build the new tables here first, so that we can compare with the * previous one. */ @@ -8888,8 +8770,7 @@ char_u *fol; (void)set_spell_finish(&new_st); } -static int set_spell_finish(new_st) -spelltab_T *new_st; +static int set_spell_finish(spelltab_T *new_st) { int i; @@ -8919,9 +8800,11 @@ spelltab_T *new_st; * followed by a word character. This finds they'there but not 'they there'. * Thus this only works properly when past the first character of the word. */ -static int spell_iswordp(p, wp) -char_u *p; -win_T *wp; /* buffer used */ +static int +spell_iswordp ( + char_u *p, + win_T *wp /* buffer used */ +) { char_u *s; int l; @@ -8955,9 +8838,7 @@ win_T *wp; /* buffer used */ * Return TRUE if "p" points to a word character. * Unlike spell_iswordp() this doesn't check for "midword" characters. */ -static int spell_iswordp_nmw(p, wp) -char_u *p; -win_T *wp; +static int spell_iswordp_nmw(char_u *p, win_T *wp) { int c; @@ -8976,9 +8857,7 @@ win_T *wp; * Unicode subscript and superscript are not considered word characters. * See also dbcs_class() and utf_class() in mbyte.c. */ -static int spell_mb_isword_class(cl, wp) -int cl; -win_T *wp; +static int spell_mb_isword_class(int cl, win_T *wp) { if (wp->w_s->b_cjk) /* East Asian characters are not considered word characters. */ @@ -8990,9 +8869,7 @@ win_T *wp; * Return TRUE if "p" points to a word character. * Wide version of spell_iswordp(). */ -static int spell_iswordp_w(p, wp) -int *p; -win_T *wp; +static int spell_iswordp_w(int *p, win_T *wp) { int *s; @@ -9018,9 +8895,7 @@ win_T *wp; * Write the table with prefix conditions to the .spl file. * When "fd" is NULL only count the length of what is written. */ -static int write_spell_prefcond(fd, gap) -FILE *fd; -garray_T *gap; +static int write_spell_prefcond(FILE *fd, garray_T *gap) { int i; char_u *p; @@ -9056,11 +8931,7 @@ garray_T *gap; * When using a multi-byte 'encoding' the length may change! * Returns FAIL when something wrong. */ -static int spell_casefold(str, len, buf, buflen) -char_u *str; -int len; -char_u *buf; -int buflen; +static int spell_casefold(char_u *str, int len, char_u *buf, int buflen) { int i; @@ -9106,7 +8977,7 @@ static int sps_limit = 9999; /* max nr of suggestions given */ * Check the 'spellsuggest' option. Return FAIL if it's wrong. * Sets "sps_flags" and "sps_limit". */ -int spell_check_sps() { +int spell_check_sps(void) { char_u *p; char_u *s; char_u buf[MAXPATHL]; @@ -9155,8 +9026,7 @@ int spell_check_sps() { * In Visual mode use the highlighted word as the bad word. * When "count" is non-zero use that suggestion. */ -void spell_suggest(count) -int count; +void spell_suggest(int count) { char_u *line; pos_T prev_cursor = curwin->w_cursor; @@ -9370,9 +9240,7 @@ skip: * Check if the word at line "lnum" column "col" is required to start with a * capital. This uses 'spellcapcheck' of the current buffer. */ -static int check_need_cap(lnum, col) -linenr_T lnum; -colnr_T col; +static int check_need_cap(linenr_T lnum, colnr_T col) { int need_cap = FALSE; char_u *line; @@ -9431,8 +9299,7 @@ colnr_T col; /* * ":spellrepall" */ -void ex_spellrepall(eap) -exarg_T *eap UNUSED; +void ex_spellrepall(exarg_T *eap) { pos_T pos = curwin->w_cursor; char_u *frompat; @@ -9499,12 +9366,14 @@ exarg_T *eap UNUSED; * Find spell suggestions for "word". Return them in the growarray "*gap" as * a list of allocated strings. */ -void spell_suggest_list(gap, word, maxcount, need_cap, interactive) -garray_T *gap; -char_u *word; -int maxcount; /* maximum nr of suggestions */ -int need_cap; /* 'spellcapcheck' matched */ -int interactive; +void +spell_suggest_list ( + garray_T *gap, + char_u *word, + int maxcount, /* maximum nr of suggestions */ + int need_cap, /* 'spellcapcheck' matched */ + int interactive +) { suginfo_T sug; int i; @@ -9541,16 +9410,16 @@ int interactive; * Note: does use info for the current window. * This is based on the mechanisms of Aspell, but completely reimplemented. */ -static void spell_find_suggest(badptr, badlen, su, maxcount, banbadword, - need_cap, - interactive) -char_u *badptr; -int badlen; /* length of bad word or 0 if unknown */ -suginfo_T *su; -int maxcount; -int banbadword; /* don't include badword in suggestions */ -int need_cap; /* word should start with capital */ -int interactive; +static void +spell_find_suggest ( + char_u *badptr, + int badlen, /* length of bad word or 0 if unknown */ + suginfo_T *su, + int maxcount, + int banbadword, /* don't include badword in suggestions */ + int need_cap, /* word should start with capital */ + int interactive +) { hlf_T attr = HLF_COUNT; char_u buf[MAXPATHL]; @@ -9662,9 +9531,7 @@ int interactive; /* * Find suggestions by evaluating expression "expr". */ -static void spell_suggest_expr(su, expr) -suginfo_T *su; -char_u *expr; +static void spell_suggest_expr(suginfo_T *su, char_u *expr) { list_T *list; listitem_T *li; @@ -9696,9 +9563,7 @@ char_u *expr; /* * Find suggestions in file "fname". Used for "file:" in 'spellsuggest'. */ -static void spell_suggest_file(su, fname) -suginfo_T *su; -char_u *fname; +static void spell_suggest_file(suginfo_T *su, char_u *fname) { FILE *fd; char_u line[MAXWLEN * 2]; @@ -9749,9 +9614,7 @@ char_u *fname; /* * Find suggestions for the internal method indicated by "sps_flags". */ -static void spell_suggest_intern(su, interactive) -suginfo_T *su; -int interactive; +static void spell_suggest_intern(suginfo_T *su, int interactive) { /* * Load the .sug file(s) that are available and not done yet. @@ -9837,7 +9700,7 @@ int interactive; /* * Load the .sug files for languages that have one and weren't loaded yet. */ -static void suggest_load_files() { +static void suggest_load_files(void) { langp_T *lp; int lpi; slang_T *slang; @@ -9965,9 +9828,7 @@ nextone: * Fill in the wordcount fields for a trie. * Returns the total number of words. */ -static void tree_count_words(byts, idxs) -char_u *byts; -idx_T *idxs; +static void tree_count_words(char_u *byts, idx_T *idxs) { int depth; idx_T arridx[MAXWLEN]; @@ -10019,8 +9880,7 @@ idx_T *idxs; /* * Free the info put in "*su" by spell_find_suggest(). */ -static void spell_find_cleanup(su) -suginfo_T *su; +static void spell_find_cleanup(suginfo_T *su) { int i; @@ -10041,10 +9901,12 @@ suginfo_T *su; * "wcopy[MAXWLEN]". "word" must not be empty. * The result is NUL terminated. */ -static void onecap_copy(word, wcopy, upper) -char_u *word; -char_u *wcopy; -int upper; /* TRUE: first letter made upper case */ +static void +onecap_copy ( + char_u *word, + char_u *wcopy, + int upper /* TRUE: first letter made upper case */ +) { char_u *p; int c; @@ -10072,9 +9934,7 @@ int upper; /* TRUE: first letter made upper case */ * Make a copy of "word" with all the letters upper cased into * "wcopy[MAXWLEN]". The result is NUL terminated. */ -static void allcap_copy(word, wcopy) -char_u *word; -char_u *wcopy; +static void allcap_copy(char_u *word, char_u *wcopy) { char_u *s; char_u *d; @@ -10113,8 +9973,7 @@ char_u *wcopy; /* * Try finding suggestions by recognizing specific situations. */ -static void suggest_try_special(su) -suginfo_T *su; +static void suggest_try_special(suginfo_T *su) { char_u *p; size_t len; @@ -10145,8 +10004,7 @@ suginfo_T *su; /* * Try finding suggestions by adding/removing/swapping letters. */ -static void suggest_try_change(su) -suginfo_T *su; +static void suggest_try_change(suginfo_T *su) { char_u fword[MAXWLEN]; /* copy of the bad word, case-folded */ int n; @@ -10210,11 +10068,7 @@ suginfo_T *su; * "similar_chars()" * use "slang->sl_repsal" instead of "lp->lp_replang->sl_rep" */ -static void suggest_trie_walk(su, lp, fword, soundfold) -suginfo_T *su; -langp_T *lp; -char_u *fword; -int soundfold; +static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, int soundfold) { char_u tword[MAXWLEN]; /* good word collected so far */ trystate_T stack[MAXWLEN]; @@ -11484,10 +11338,7 @@ int soundfold; /* * Go one level deeper in the tree. */ -static void go_deeper(stack, depth, score_add) -trystate_T *stack; -int depth; -int score_add; +static void go_deeper(trystate_T *stack, int depth, int score_add) { stack[depth + 1] = stack[depth]; stack[depth + 1].ts_state = STATE_START; @@ -11500,10 +11351,7 @@ int score_add; * Case-folding may change the number of bytes: Count nr of chars in * fword[flen] and return the byte length of that many chars in "word". */ -static int nofold_len(fword, flen, word) -char_u *fword; -int flen; -char_u *word; +static int nofold_len(char_u *fword, int flen, char_u *word) { char_u *p; int i = 0; @@ -11521,10 +11369,7 @@ char_u *word; * Theoretically there could be several keep-case words that result in the * same case-folded word, but we only find one... */ -static void find_keepcap_word(slang, fword, kword) -slang_T *slang; -char_u *fword; -char_u *kword; +static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword) { char_u uword[MAXWLEN]; /* "fword" in upper-case */ int depth; @@ -11657,8 +11502,7 @@ char_u *kword; * Compute the sound-a-like score for suggestions in su->su_ga and add them to * su->su_sga. */ -static void score_comp_sal(su) -suginfo_T *su; +static void score_comp_sal(suginfo_T *su) { langp_T *lp; char_u badsound[MAXWLEN]; @@ -11706,8 +11550,7 @@ suginfo_T *su; * Combine the list of suggestions in su->su_ga and su->su_sga. * They are entwined. */ -static void score_combine(su) -suginfo_T *su; +static void score_combine(suginfo_T *su) { int i; int j; @@ -11809,11 +11652,13 @@ suginfo_T *su; * For the goodword in "stp" compute the soundalike score compared to the * badword. */ -static int stp_sal_score(stp, su, slang, badsound) -suggest_T *stp; -suginfo_T *su; -slang_T *slang; -char_u *badsound; /* sound-folded badword */ +static int +stp_sal_score ( + suggest_T *stp, + suginfo_T *su, + slang_T *slang, + char_u *badsound /* sound-folded badword */ +) { char_u *p; char_u *pbad; @@ -11874,7 +11719,7 @@ static sftword_T dumsft; /* * Prepare for calling suggest_try_soundalike(). */ -static void suggest_try_soundalike_prep() { +static void suggest_try_soundalike_prep(void) { langp_T *lp; int lpi; slang_T *slang; @@ -11894,8 +11739,7 @@ static void suggest_try_soundalike_prep() { * Find suggestions by comparing the word in a sound-a-like form. * Note: This doesn't support postponed prefixes. */ -static void suggest_try_soundalike(su) -suginfo_T *su; +static void suggest_try_soundalike(suginfo_T *su) { char_u salword[MAXWLEN]; langp_T *lp; @@ -11922,7 +11766,7 @@ suginfo_T *su; /* * Finish up after calling suggest_try_soundalike(). */ -static void suggest_try_soundalike_finish() { +static void suggest_try_soundalike_finish(void) { langp_T *lp; int lpi; slang_T *slang; @@ -11954,11 +11798,13 @@ static void suggest_try_soundalike_finish() { * A match with a soundfolded word is found. Add the good word(s) that * produce this soundfolded word. */ -static void add_sound_suggest(su, goodword, score, lp) -suginfo_T *su; -char_u *goodword; -int score; /* soundfold score */ -langp_T *lp; +static void +add_sound_suggest ( + suginfo_T *su, + char_u *goodword, + int score, /* soundfold score */ + langp_T *lp +) { slang_T *slang = lp->lp_slang; /* language for sound folding */ int sfwordnr; @@ -12141,9 +11987,7 @@ badword: /* * Find word "word" in fold-case tree for "slang" and return the word number. */ -static int soundfold_find(slang, word) -slang_T *slang; -char_u *word; +static int soundfold_find(slang_T *slang, char_u *word) { idx_T arridx = 0; int len; @@ -12212,10 +12056,7 @@ char_u *word; /* * Copy "fword" to "cword", fixing case according to "flags". */ -static void make_case_word(fword, cword, flags) -char_u *fword; -char_u *cword; -int flags; +static void make_case_word(char_u *fword, char_u *cword, int flags) { if (flags & WF_ALLCAP) /* Make it all upper-case */ @@ -12231,9 +12072,7 @@ int flags; /* * Use map string "map" for languages "lp". */ -static void set_map_str(lp, map) -slang_T *lp; -char_u *map; +static void set_map_str(slang_T *lp, char_u *map) { char_u *p; int headc = 0; @@ -12301,10 +12140,7 @@ char_u *map; * Return TRUE if "c1" and "c2" are similar characters according to the MAP * lines in the .aff file. */ -static int similar_chars(slang, c1, c2) -slang_T *slang; -int c1; -int c2; +static int similar_chars(slang_T *slang, int c1, int c2) { int m1, m2; char_u buf[MB_MAXBYTES + 1]; @@ -12340,20 +12176,19 @@ int c2; * Add a suggestion to the list of suggestions. * For a suggestion that is already in the list the lowest score is remembered. */ -static void add_suggestion(su, gap, goodword, badlenarg, score, altscore, - had_bonus, - slang, - maxsf) -suginfo_T *su; -garray_T *gap; /* either su_ga or su_sga */ -char_u *goodword; -int badlenarg; /* len of bad word replaced with "goodword" */ -int score; -int altscore; -int had_bonus; /* value for st_had_bonus */ -slang_T *slang; /* language for sound folding */ -int maxsf; /* su_maxscore applies to soundfold score, +static void +add_suggestion ( + suginfo_T *su, + garray_T *gap, /* either su_ga or su_sga */ + char_u *goodword, + int badlenarg, /* len of bad word replaced with "goodword" */ + int score, + int altscore, + int had_bonus, /* value for st_had_bonus */ + slang_T *slang, /* language for sound folding */ + int maxsf /* su_maxscore applies to soundfold score, su_sfmaxscore to the total score. */ +) { int goodlen; /* len of goodword changed */ int badlen; /* len of bad word changed */ @@ -12464,9 +12299,11 @@ int maxsf; /* su_maxscore applies to soundfold score, * Suggestions may in fact be flagged as errors. Esp. for banned words and * for split words, such as "the the". Remove these from the list here. */ -static void check_suggestions(su, gap) -suginfo_T *su; -garray_T *gap; /* either su_ga or su_sga */ +static void +check_suggestions ( + suginfo_T *su, + garray_T *gap /* either su_ga or su_sga */ +) { suggest_T *stp; int i; @@ -12498,9 +12335,7 @@ garray_T *gap; /* either su_ga or su_sga */ /* * Add a word to be banned. */ -static void add_banned(su, word) -suginfo_T *su; -char_u *word; +static void add_banned(suginfo_T *su, char_u *word) { char_u *s; hash_T hash; @@ -12519,8 +12354,7 @@ char_u *word; * Recompute the score for all suggestions if sound-folding is possible. This * is slow, thus only done for the final results. */ -static void rescore_suggestions(su) -suginfo_T *su; +static void rescore_suggestions(suginfo_T *su) { int i; @@ -12532,9 +12366,7 @@ suginfo_T *su; /* * Recompute the score for one suggestion if sound-folding is possible. */ -static void rescore_one(su, stp) -suginfo_T *su; -suggest_T *stp; +static void rescore_one(suginfo_T *su, suggest_T *stp) { slang_T *slang = stp->st_slang; char_u sal_badword[MAXWLEN]; @@ -12565,9 +12397,7 @@ sug_compare __ARGS((const void *s1, const void *s2)); * Function given to qsort() to sort the suggestions on st_score. * First on "st_score", then "st_altscore" then alphabetically. */ -static int sug_compare(s1, s2) -const void *s1; -const void *s2; +static int sug_compare(const void *s1, const void *s2) { suggest_T *p1 = (suggest_T *)s1; suggest_T *p2 = (suggest_T *)s2; @@ -12587,10 +12417,12 @@ const void *s2; * - Remove words that won't be displayed. * Returns the maximum score in the list or "maxscore" unmodified. */ -static int cleanup_suggestions(gap, maxscore, keep) -garray_T *gap; -int maxscore; -int keep; /* nr of suggestions to keep */ +static int +cleanup_suggestions ( + garray_T *gap, + int maxscore, + int keep /* nr of suggestions to keep */ +) { suggest_T *stp = &SUG(*gap, 0); int i; @@ -12612,8 +12444,7 @@ int keep; /* nr of suggestions to keep */ * Soundfold a string, for soundfold(). * Result is in allocated memory, NULL for an error. */ -char_u * eval_soundfold(word) -char_u *word; +char_u *eval_soundfold(char_u *word) { langp_T *lp; char_u sound[MAXWLEN]; @@ -12646,11 +12477,13 @@ char_u *word; * 1. SOFOFROM/SOFOTO do a simple character mapping. * 2. SAL items define a more advanced sound-folding (and much slower). */ -static void spell_soundfold(slang, inword, folded, res) -slang_T *slang; -char_u *inword; -int folded; /* "inword" is already case-folded */ -char_u *res; +static void +spell_soundfold ( + slang_T *slang, + char_u *inword, + int folded, /* "inword" is already case-folded */ + char_u *res +) { char_u fword[MAXWLEN]; char_u *word; @@ -12678,10 +12511,7 @@ char_u *res; * Perform sound folding of "inword" into "res" according to SOFOFROM and * SOFOTO lines. */ -static void spell_soundfold_sofo(slang, inword, res) -slang_T *slang; -char_u *inword; -char_u *res; +static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) { char_u *s; int ri = 0; @@ -12739,10 +12569,7 @@ char_u *res; res[ri] = NUL; } -static void spell_soundfold_sal(slang, inword, res) -slang_T *slang; -char_u *inword; -char_u *res; +static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res) { salitem_T *smp; char_u word[MAXWLEN]; @@ -12986,10 +12813,7 @@ char_u *res; * Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]". * Multi-byte version of spell_soundfold(). */ -static void spell_soundfold_wsal(slang, inword, res) -slang_T *slang; -char_u *inword; -char_u *res; +static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) { salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN]; @@ -13271,9 +13095,11 @@ char_u *res; * Instead of a generic loop we write out the code. That keeps it fast by * avoiding checks that will not be possible. */ -static int soundalike_score(goodstart, badstart) -char_u *goodstart; /* sound-folded good word */ -char_u *badstart; /* sound-folded bad word */ +static int +soundalike_score ( + char_u *goodstart, /* sound-folded good word */ + char_u *badstart /* sound-folded bad word */ +) { char_u *goodsound = goodstart; char_u *badsound = badstart; @@ -13486,10 +13312,7 @@ char_u *badstart; /* sound-folded bad word */ * edit_distance(). It has been converted from C++ to C and modified to * support multi-byte characters. */ -static int spell_edit_score(slang, badword, goodword) -slang_T *slang; -char_u *badword; -char_u *goodword; +static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword) { int *cnt; int badlen, goodlen; /* lengths including NUL */ @@ -13595,11 +13418,7 @@ typedef struct { * The idea comes from Aspell leditdist.cpp. Rewritten in C and added support * for multi-byte characters. */ -static int spell_edit_score_limit(slang, badword, goodword, limit) -slang_T *slang; -char_u *badword; -char_u *goodword; -int limit; +static int spell_edit_score_limit(slang_T *slang, char_u *badword, char_u *goodword, int limit) { limitscore_T stack[10]; /* allow for over 3 * 2 edits */ int stackidx; @@ -13752,11 +13571,7 @@ pop: * Multi-byte version of spell_edit_score_limit(). * Keep it in sync with the above! */ -static int spell_edit_score_limit_w(slang, badword, goodword, limit) -slang_T *slang; -char_u *badword; -char_u *goodword; -int limit; +static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goodword, int limit) { limitscore_T stack[10]; /* allow for over 3 * 2 edits */ int stackidx; @@ -13918,8 +13733,7 @@ pop: /* * ":spellinfo" */ -void ex_spellinfo(eap) -exarg_T *eap UNUSED; +void ex_spellinfo(exarg_T *eap) { int lpi; langp_T *lp; @@ -13952,8 +13766,7 @@ exarg_T *eap UNUSED; /* * ":spelldump" */ -void ex_spelldump(eap) -exarg_T *eap; +void ex_spelldump(exarg_T *eap) { char_u *spl; long dummy; @@ -13988,11 +13801,13 @@ exarg_T *eap; * "ic" and "dir" are not used. * 2. When "pat" is not NULL: add matching words to insert mode completion. */ -void spell_dump_compl(pat, ic, dir, dumpflags_arg) -char_u *pat; /* leading part of the word */ -int ic; /* ignore case */ -int *dir; /* direction for adding matches */ -int dumpflags_arg; /* DUMPFLAG_* */ +void +spell_dump_compl ( + char_u *pat, /* leading part of the word */ + int ic, /* ignore case */ + int *dir, /* direction for adding matches */ + int dumpflags_arg /* DUMPFLAG_* */ +) { langp_T *lp; slang_T *slang; @@ -14161,14 +13976,7 @@ int dumpflags_arg; /* DUMPFLAG_* */ * Dump one word: apply case modifications and append a line to the buffer. * When "lnum" is zero add insert mode completion. */ -static void dump_word(slang, word, pat, dir, dumpflags, wordflags, lnum) -slang_T *slang; -char_u *word; -char_u *pat; -int *dir; -int dumpflags; -int wordflags; -linenr_T lnum; +static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int dumpflags, int wordflags, linenr_T lnum) { int keepcap = FALSE; char_u *p; @@ -14242,15 +14050,16 @@ linenr_T lnum; * When "lnum" is zero add insert mode completion. * Return the updated line number. */ -static linenr_T dump_prefixes(slang, word, pat, dir, dumpflags, flags, - startlnum) -slang_T *slang; -char_u *word; /* case-folded word */ -char_u *pat; -int *dir; -int dumpflags; -int flags; /* flags with prefix ID */ -linenr_T startlnum; +static linenr_T +dump_prefixes ( + slang_T *slang, + char_u *word, /* case-folded word */ + char_u *pat, + int *dir, + int dumpflags, + int flags, /* flags with prefix ID */ + linenr_T startlnum +) { idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; @@ -14346,9 +14155,7 @@ linenr_T startlnum; * Move "p" to the end of word "start". * Uses the spell-checking word characters. */ -char_u * spell_to_word_end(start, win) -char_u *start; -win_T *win; +char_u *spell_to_word_end(char_u *start, win_T *win) { char_u *p = start; @@ -14364,8 +14171,7 @@ win_T *win; * the word in front of the cursor. * Returns the column number of the word. */ -int spell_word_start(startcol) -int startcol; +int spell_word_start(int startcol) { char_u *line; char_u *p; @@ -14400,8 +14206,7 @@ int startcol; */ static int spell_expand_need_cap; -void spell_expand_check_cap(col) -colnr_T col; +void spell_expand_check_cap(colnr_T col) { spell_expand_need_cap = check_need_cap(curwin->w_cursor.lnum, col); } @@ -14412,10 +14217,7 @@ colnr_T col; * Returns the number of matches. The matches are in "matchp[]", array of * allocated strings. */ -int expand_spelling(lnum, pat, matchp) -linenr_T lnum UNUSED; -char_u *pat; -char_u ***matchp; +int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp) { garray_T ga; diff --git a/src/syntax.c b/src/syntax.c index 375f16cd0d..c600b2f2a1 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -448,9 +448,7 @@ static void syn_incl_toplevel __ARGS((int id, int *flagsp)); * it. Careful: curbuf and curwin are likely to point to another buffer and * window. */ -void syntax_start(wp, lnum) -win_T *wp; -linenr_T lnum; +void syntax_start(win_T *wp, linenr_T lnum) { synstate_T *p; synstate_T *last_valid = NULL; @@ -610,8 +608,7 @@ linenr_T lnum; * We cannot simply discard growarrays full of state_items or buf_states; we * have to manually release their extmatch pointers first. */ -static void clear_syn_state(p) -synstate_T *p; +static void clear_syn_state(synstate_T *p) { int i; garray_T *gap; @@ -630,7 +627,7 @@ synstate_T *p; /* * Cleanup the current_state stack. */ -static void clear_current_state() { +static void clear_current_state(void) { int i; stateitem_T *sip; @@ -649,10 +646,7 @@ static void clear_current_state() { * 2. Search backwards for given sync patterns. * 3. Simply start on a given number of lines above "lnum". */ -static void syn_sync(wp, start_lnum, last_valid) -win_T *wp; -linenr_T start_lnum; -synstate_T *last_valid; +static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) { buf_T *curbuf_save; win_T *curwin_save; @@ -901,8 +895,7 @@ synstate_T *last_valid; /* * Return TRUE if the line-continuation pattern matches in line "lnum". */ -static int syn_match_linecont(lnum) -linenr_T lnum; +static int syn_match_linecont(linenr_T lnum) { regmmatch_T regmatch; @@ -918,7 +911,7 @@ linenr_T lnum; /* * Prepare the current state for the start of a line. */ -static void syn_start_line() { +static void syn_start_line(void) { current_finished = FALSE; current_col = 0; @@ -940,8 +933,7 @@ static void syn_start_line() { * When "startofline" is TRUE the last item is always updated. * When "startofline" is FALSE the item with "keepend" is forcefully updated. */ -static void syn_update_ends(startofline) -int startofline; +static void syn_update_ends(int startofline) { stateitem_T *cur_si; int i; @@ -1035,8 +1027,7 @@ int startofline; * number of entries SST_MAX_ENTRIES, and the distance is computed. */ -static void syn_stack_free_block(block) -synblock_T *block; +static void syn_stack_free_block(synblock_T *block) { synstate_T *p; @@ -1052,8 +1043,7 @@ synblock_T *block; * Free b_sst_array[] for buffer "buf". * Used when syntax items changed to force resyncing everywhere. */ -void syn_stack_free_all(block) -synblock_T *block; +void syn_stack_free_all(synblock_T *block) { win_T *wp; @@ -1074,7 +1064,7 @@ synblock_T *block; * small, reallocate it. * Also used to allocate b_sst_array[] for the first time. */ -static void syn_stack_alloc() { +static void syn_stack_alloc(void) { long len; synstate_T *to, *from; synstate_T *sstp; @@ -1144,8 +1134,7 @@ static void syn_stack_alloc() { * Called from update_screen(), before screen is being updated, once for each * displayed buffer. */ -void syn_stack_apply_changes(buf) -buf_T *buf; +void syn_stack_apply_changes(buf_T *buf) { win_T *wp; @@ -1158,9 +1147,7 @@ buf_T *buf; } } -static void syn_stack_apply_changes_block(block, buf) -synblock_T *block; -buf_T *buf; +static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf) { synstate_T *p, *prev, *np; linenr_T n; @@ -1207,7 +1194,7 @@ buf_T *buf; * Reduce the number of entries in the state stack for syn_buf. * Returns TRUE if at least one entry was freed. */ -static int syn_stack_cleanup() { +static int syn_stack_cleanup(void) { synstate_T *p, *prev; disptick_T tick; int above; @@ -1263,9 +1250,7 @@ static int syn_stack_cleanup() { * Free the allocated memory for a syn_state item. * Move the entry into the free list. */ -static void syn_stack_free_entry(block, p) -synblock_T *block; -synstate_T *p; +static void syn_stack_free_entry(synblock_T *block, synstate_T *p) { clear_syn_state(p); p->sst_next = block->b_sst_firstfree; @@ -1277,8 +1262,7 @@ synstate_T *p; * Find an entry in the list of state stacks at or before "lnum". * Returns NULL when there is no entry or the first entry is after "lnum". */ -static synstate_T * syn_stack_find_entry(lnum) -linenr_T lnum; +static synstate_T *syn_stack_find_entry(linenr_T lnum) { synstate_T *p, *prev; @@ -1296,7 +1280,7 @@ linenr_T lnum; * Try saving the current state in b_sst_array[]. * The current state must be valid for the start of the current_lnum line! */ -static synstate_T * store_current_state() { +static synstate_T *store_current_state(void) { int i; synstate_T *p; bufstate_T *bp; @@ -1400,8 +1384,7 @@ static synstate_T * store_current_state() { /* * Copy a state stack from "from" in b_sst_array[] to current_state; */ -static void load_current_state(from) -synstate_T *from; +static void load_current_state(synstate_T *from) { int i; bufstate_T *bp; @@ -1443,8 +1426,7 @@ synstate_T *from; * Compare saved state stack "*sp" with the current state. * Return TRUE when they are equal. */ -static int syn_stack_equal(sp) -synstate_T *sp; +static int syn_stack_equal(synstate_T *sp) { int i, j; bufstate_T *bp; @@ -1510,8 +1492,7 @@ synstate_T *sp; * displayed line * lnum -> line below window */ -void syntax_end_parsing(lnum) -linenr_T lnum; +void syntax_end_parsing(linenr_T lnum) { synstate_T *sp; @@ -1527,14 +1508,14 @@ linenr_T lnum; * End of handling of the state stack. ****************************************/ -static void invalidate_current_state() { +static void invalidate_current_state(void) { clear_current_state(); current_state.ga_itemsize = 0; /* mark current_state invalid */ current_next_list = NULL; keepend_level = -1; } -static void validate_current_state() { +static void validate_current_state(void) { current_state.ga_itemsize = sizeof(stateitem_T); current_state.ga_growsize = 3; } @@ -1544,8 +1525,7 @@ static void validate_current_state() { * This will only be called just after get_syntax_attr() for the previous * line, to check if the next line needs to be redrawn too. */ -int syntax_check_changed(lnum) -linenr_T lnum; +int syntax_check_changed(linenr_T lnum) { int retval = TRUE; synstate_T *sp; @@ -1590,8 +1570,10 @@ linenr_T lnum; * the line. It can start anywhere in the line, as long as the current state * is valid. */ -static int syn_finish_line(syncing) -int syncing; /* called for syncing */ +static int +syn_finish_line ( + int syncing /* called for syncing */ +) { stateitem_T *cur_si; colnr_T prev_current_col; @@ -1636,10 +1618,12 @@ int syncing; /* called for syncing */ * When "can_spell" is not NULL set it to TRUE when spell-checking should be * done. */ -int get_syntax_attr(col, can_spell, keep_state) -colnr_T col; -int *can_spell; -int keep_state; /* keep state of char at "col" */ +int +get_syntax_attr ( + colnr_T col, + int *can_spell, + int keep_state /* keep state of char at "col" */ +) { int attr = 0; @@ -1682,11 +1666,13 @@ int keep_state; /* keep state of char at "col" */ /* * Get syntax attributes for current_lnum, current_col. */ -static int syn_current_attr(syncing, displaying, can_spell, keep_state) -int syncing; /* When 1: called for syncing */ -int displaying; /* result will be displayed */ -int *can_spell; /* return: do spell checking */ -int keep_state; /* keep syntax stack afterwards */ +static int +syn_current_attr ( + int syncing, /* When 1: called for syncing */ + int displaying, /* result will be displayed */ + int *can_spell, /* return: do spell checking */ + int keep_state /* keep syntax stack afterwards */ +) { int syn_id; lpos_T endpos; /* was: char_u *endp; */ @@ -2203,9 +2189,7 @@ int keep_state; /* keep syntax stack afterwards */ /* * Check if we already matched pattern "idx" at the current column. */ -static int did_match_already(idx, gap) -int idx; -garray_T *gap; +static int did_match_already(int idx, garray_T *gap) { int i; @@ -2227,8 +2211,7 @@ garray_T *gap; /* * Push the next match onto the stack. */ -static stateitem_T * push_next_match(cur_si) -stateitem_T *cur_si; +static stateitem_T *push_next_match(stateitem_T *cur_si) { synpat_T *spp; int save_flags; @@ -2307,7 +2290,7 @@ stateitem_T *cur_si; /* * Check for end of current state (and the states before it). */ -static void check_state_ends() { +static void check_state_ends(void) { stateitem_T *cur_si; int had_extend; @@ -2400,8 +2383,7 @@ static void check_state_ends() { * Update an entry in the current_state stack for a match or region. This * fills in si_attr, si_next_list and si_cont_list. */ -static void update_si_attr(idx) -int idx; +static void update_si_attr(int idx) { stateitem_T *sip = &CUR_STATE(idx); synpat_T *spp; @@ -2450,7 +2432,7 @@ int idx; * Check the current stack for patterns with "keepend" flag. * Propagate the match-end to contained items, until a "skipend" item is found. */ -static void check_keepend() { +static void check_keepend(void) { int i; lpos_T maxpos; lpos_T maxpos_h; @@ -2505,10 +2487,12 @@ static void check_keepend() { * * Return the flags for the matched END. */ -static void update_si_end(sip, startcol, force) -stateitem_T *sip; -int startcol; /* where to start searching for the end */ -int force; /* when TRUE overrule a previous end */ +static void +update_si_end ( + stateitem_T *sip, + int startcol, /* where to start searching for the end */ + int force /* when TRUE overrule a previous end */ +) { lpos_T startpos; lpos_T endpos; @@ -2564,8 +2548,7 @@ int force; /* when TRUE overrule a previous end */ * It is cleared and the index set to "idx". * Return FAIL if it's not possible (out of memory). */ -static int push_current_state(idx) -int idx; +static int push_current_state(int idx) { if (ga_grow(¤t_state, 1) == FAIL) return FAIL; @@ -2578,7 +2561,7 @@ int idx; /* * Remove a state from the current_state stack. */ -static void pop_current_state() { +static void pop_current_state(void) { if (current_state.ga_len) { unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch); --current_state.ga_len; @@ -2600,16 +2583,17 @@ static void pop_current_state() { * If found, the end of the region and the end of the highlighting is * computed. */ -static void find_endpos(idx, startpos, m_endpos, hl_endpos, flagsp, end_endpos, - end_idx, start_ext) -int idx; /* index of the pattern */ -lpos_T *startpos; /* where to start looking for an END match */ -lpos_T *m_endpos; /* return: end of match */ -lpos_T *hl_endpos; /* return: end of highlighting */ -long *flagsp; /* return: flags of matching END */ -lpos_T *end_endpos; /* return: end of end pattern match */ -int *end_idx; /* return: group ID for end pat. match, or 0 */ -reg_extmatch_T *start_ext; /* submatches from the start pattern */ +static void +find_endpos ( + int idx, /* index of the pattern */ + lpos_T *startpos, /* where to start looking for an END match */ + lpos_T *m_endpos, /* return: end of match */ + lpos_T *hl_endpos, /* return: end of highlighting */ + long *flagsp, /* return: flags of matching END */ + lpos_T *end_endpos, /* return: end of end pattern match */ + int *end_idx, /* return: group ID for end pat. match, or 0 */ + reg_extmatch_T *start_ext /* submatches from the start pattern */ +) { colnr_T matchcol; synpat_T *spp, *spp_skip; @@ -2806,9 +2790,7 @@ reg_extmatch_T *start_ext; /* submatches from the start pattern */ /* * Limit "pos" not to be after "limit". */ -static void limit_pos(pos, limit) -lpos_T *pos; -lpos_T *limit; +static void limit_pos(lpos_T *pos, lpos_T *limit) { if (pos->lnum > limit->lnum) *pos = *limit; @@ -2819,9 +2801,7 @@ lpos_T *limit; /* * Limit "pos" not to be after "limit", unless pos->lnum is zero. */ -static void limit_pos_zero(pos, limit) -lpos_T *pos; -lpos_T *limit; +static void limit_pos_zero(lpos_T *pos, lpos_T *limit) { if (pos->lnum == 0) *pos = *limit; @@ -2832,12 +2812,14 @@ lpos_T *limit; /* * Add offset to matched text for end of match or highlight. */ -static void syn_add_end_off(result, regmatch, spp, idx, extra) -lpos_T *result; /* returned position */ -regmmatch_T *regmatch; /* start/end of match */ -synpat_T *spp; /* matched pattern */ -int idx; /* index of offset */ -int extra; /* extra chars for offset to start */ +static void +syn_add_end_off ( + lpos_T *result, /* returned position */ + regmmatch_T *regmatch, /* start/end of match */ + synpat_T *spp, /* matched pattern */ + int idx, /* index of offset */ + int extra /* extra chars for offset to start */ +) { int col; int off; @@ -2876,12 +2858,14 @@ int extra; /* extra chars for offset to start */ * Add offset to matched text for start of match or highlight. * Avoid resulting column to become negative. */ -static void syn_add_start_off(result, regmatch, spp, idx, extra) -lpos_T *result; /* returned position */ -regmmatch_T *regmatch; /* start/end of match */ -synpat_T *spp; -int idx; -int extra; /* extra chars for offset to end */ +static void +syn_add_start_off ( + lpos_T *result, /* returned position */ + regmmatch_T *regmatch, /* start/end of match */ + synpat_T *spp, + int idx, + int extra /* extra chars for offset to end */ +) { int col; int off; @@ -2920,7 +2904,7 @@ int extra; /* extra chars for offset to end */ /* * Get current line in syntax buffer. */ -static char_u * syn_getcurline() { +static char_u *syn_getcurline(void) { return ml_get_buf(syn_buf, current_lnum, FALSE); } @@ -2928,11 +2912,7 @@ static char_u * syn_getcurline() { * Call vim_regexec() to find a match with "rmp" in "syn_buf". * Returns TRUE when there is a match. */ -static int syn_regexec(rmp, lnum, col, st) -regmmatch_T *rmp; -linenr_T lnum; -colnr_T col; -syn_time_T *st UNUSED; +static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T *st) { int r; proftime_T pt; @@ -2966,15 +2946,16 @@ syn_time_T *st UNUSED; * The caller must check if a keyword can start at startcol. * Return it's ID if found, 0 otherwise. */ -static int check_keyword_id(line, startcol, endcolp, flagsp, next_listp, cur_si, - ccharp) -char_u *line; -int startcol; /* position in line to check for keyword */ -int *endcolp; /* return: character after found keyword */ -long *flagsp; /* return: flags of matching keyword */ -short **next_listp; /* return: next_list of matching keyword */ -stateitem_T *cur_si; /* item at the top of the stack */ -int *ccharp UNUSED; /* conceal substitution char */ +static int +check_keyword_id ( + char_u *line, + int startcol, /* position in line to check for keyword */ + int *endcolp, /* return: character after found keyword */ + long *flagsp, /* return: flags of matching keyword */ + short **next_listp, /* return: next_list of matching keyword */ + stateitem_T *cur_si, /* item at the top of the stack */ + int *ccharp /* conceal substitution char */ +) { keyentry_T *kp; char_u *kwp; @@ -3046,9 +3027,7 @@ int *ccharp UNUSED; /* conceal substitution char */ /* * Handle ":syntax conceal" command. */ -static void syn_cmd_conceal(eap, syncing) -exarg_T *eap UNUSED; -int syncing UNUSED; +static void syn_cmd_conceal(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *next; @@ -3069,9 +3048,7 @@ int syncing UNUSED; /* * Handle ":syntax case" command. */ -static void syn_cmd_case(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_case(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *next; @@ -3092,9 +3069,7 @@ int syncing UNUSED; /* * Handle ":syntax spell" command. */ -static void syn_cmd_spell(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_spell(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *next; @@ -3117,8 +3092,7 @@ int syncing UNUSED; /* * Clear all syntax info for one buffer. */ -void syntax_clear(block) -synblock_T *block; +void syntax_clear(synblock_T *block) { int i; @@ -3165,8 +3139,7 @@ synblock_T *block; /* * Get rid of ownsyntax for window "wp". */ -void reset_synblock(wp) -win_T *wp; +void reset_synblock(win_T *wp) { if (wp->w_s != &wp->w_buffer->b_s) { syntax_clear(wp->w_s); @@ -3178,7 +3151,7 @@ win_T *wp; /* * Clear syncing info for one buffer. */ -static void syntax_sync_clear() { +static void syntax_sync_clear(void) { int i; /* free the syntax patterns */ @@ -3202,9 +3175,7 @@ static void syntax_sync_clear() { /* * Remove one pattern from the buffer's pattern list. */ -static void syn_remove_pattern(block, idx) -synblock_T *block; -int idx; +static void syn_remove_pattern(synblock_T *block, int idx) { synpat_T *spp; @@ -3221,9 +3192,7 @@ int idx; * Clear and free one syntax pattern. When clearing all, must be called from * last to first! */ -static void syn_clear_pattern(block, i) -synblock_T *block; -int i; +static void syn_clear_pattern(synblock_T *block, int i) { vim_free(SYN_ITEMS(block)[i].sp_pattern); vim_regfree(SYN_ITEMS(block)[i].sp_prog); @@ -3238,9 +3207,7 @@ int i; /* * Clear and free one syntax cluster. */ -static void syn_clear_cluster(block, i) -synblock_T *block; -int i; +static void syn_clear_cluster(synblock_T *block, int i) { vim_free(SYN_CLSTR(block)[i].scl_name); vim_free(SYN_CLSTR(block)[i].scl_name_u); @@ -3250,9 +3217,7 @@ int i; /* * Handle ":syntax clear" command. */ -static void syn_cmd_clear(eap, syncing) -exarg_T *eap; -int syncing; +static void syn_cmd_clear(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *arg_end; @@ -3323,9 +3288,7 @@ int syncing; /* * Clear one syntax group for the current buffer. */ -static void syn_clear_one(id, syncing) -int id; -int syncing; +static void syn_clear_one(int id, int syncing) { synpat_T *spp; int idx; @@ -3348,9 +3311,7 @@ int syncing; /* * Handle ":syntax on" command. */ -static void syn_cmd_on(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_on(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "syntax"); } @@ -3358,9 +3319,7 @@ int syncing UNUSED; /* * Handle ":syntax enable" command. */ -static void syn_cmd_enable(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_enable(exarg_T *eap, int syncing) { set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"enable"); syn_cmd_onoff(eap, "syntax"); @@ -3370,9 +3329,7 @@ int syncing UNUSED; /* * Handle ":syntax reset" command. */ -static void syn_cmd_reset(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_reset(exarg_T *eap, int syncing) { eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { @@ -3385,9 +3342,7 @@ int syncing UNUSED; /* * Handle ":syntax manual" command. */ -static void syn_cmd_manual(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_manual(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "manual"); } @@ -3395,16 +3350,12 @@ int syncing UNUSED; /* * Handle ":syntax off" command. */ -static void syn_cmd_off(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_off(exarg_T *eap, int syncing) { syn_cmd_onoff(eap, "nosyntax"); } -static void syn_cmd_onoff(eap, name) -exarg_T *eap; -char *name; +static void syn_cmd_onoff(exarg_T *eap, char *name) { char_u buf[100]; @@ -3419,9 +3370,11 @@ char *name; /* * Handle ":syntax [list]" command: list current syntax words. */ -static void syn_cmd_list(eap, syncing) -exarg_T *eap; -int syncing; /* when TRUE: list syncing items */ +static void +syn_cmd_list ( + exarg_T *eap, + int syncing /* when TRUE: list syncing items */ +) { char_u *arg = eap->arg; int id; @@ -3496,7 +3449,7 @@ int syncing; /* when TRUE: list syncing items */ eap->nextcmd = check_nextcmd(arg); } -static void syn_lines_msg() { +static void syn_lines_msg(void) { if (curwin->w_s->b_syn_sync_maxlines > 0 || curwin->w_s->b_syn_sync_minlines > 0) { MSG_PUTS("; "); @@ -3514,7 +3467,7 @@ static void syn_lines_msg() { } } -static void syn_match_msg() { +static void syn_match_msg(void) { if (curwin->w_s->b_syn_sync_linebreaks > 0) { MSG_PUTS(_("; match ")); msg_outnum(curwin->w_s->b_syn_sync_linebreaks); @@ -3534,10 +3487,12 @@ static void syn_list_flags __ARGS((struct name_list *nl, int flags, int attr)); /* * List one syntax item, for ":syntax" or "syntax list syntax_name". */ -static void syn_list_one(id, syncing, link_only) -int id; -int syncing; /* when TRUE: list syncing items */ -int link_only; /* when TRUE; list link-only too */ +static void +syn_list_one ( + int id, + int syncing, /* when TRUE: list syncing items */ + int link_only /* when TRUE; list link-only too */ +) { int attr; int idx; @@ -3634,10 +3589,7 @@ int link_only; /* when TRUE; list link-only too */ } } -static void syn_list_flags(nlist, flags, attr) -struct name_list *nlist; -int flags; -int attr; +static void syn_list_flags(struct name_list *nlist, int flags, int attr) { int i; @@ -3651,8 +3603,7 @@ int attr; /* * List one syntax cluster, for ":syntax" or "syntax list syntax_name". */ -static void syn_list_cluster(id) -int id; +static void syn_list_cluster(int id) { int endcol = 15; @@ -3675,10 +3626,7 @@ int id; } } -static void put_id_list(name, list, attr) -char_u *name; -short *list; -int attr; +static void put_id_list(char_u *name, short *list, int attr) { short *p; @@ -3707,11 +3655,7 @@ int attr; msg_putchar(' '); } -static void put_pattern(s, c, spp, attr) -char *s; -int c; -synpat_T *spp; -int attr; +static void put_pattern(char *s, int c, synpat_T *spp, int attr) { long n; int mask; @@ -3774,11 +3718,13 @@ int attr; * List or clear the keywords for one syntax group. * Return TRUE if the header has been printed. */ -static int syn_list_keywords(id, ht, did_header, attr) -int id; -hashtab_T *ht; -int did_header; /* header has already been printed */ -int attr; +static int +syn_list_keywords ( + int id, + hashtab_T *ht, + int did_header, /* header has already been printed */ + int attr +) { int outlen; hashitem_T *hi; @@ -3860,9 +3806,7 @@ int attr; return did_header; } -static void syn_clear_keyword(id, ht) -int id; -hashtab_T *ht; +static void syn_clear_keyword(int id, hashtab_T *ht) { hashitem_T *hi; keyentry_T *kp; @@ -3903,8 +3847,7 @@ hashtab_T *ht; /* * Clear a whole keyword table. */ -static void clear_keywtab(ht) -hashtab_T *ht; +static void clear_keywtab(hashtab_T *ht) { hashitem_T *hi; int todo; @@ -3930,13 +3873,15 @@ hashtab_T *ht; /* * Add a keyword to the list of keywords. */ -static void add_keyword(name, id, flags, cont_in_list, next_list, conceal_char) -char_u *name; /* name of keyword */ -int id; /* group ID for this keyword */ -int flags; /* flags for this keyword */ -short *cont_in_list; /* containedin for this keyword */ -short *next_list; /* nextgroup for this keyword */ -int conceal_char; +static void +add_keyword ( + char_u *name, /* name of keyword */ + int id, /* group ID for this keyword */ + int flags, /* flags for this keyword */ + short *cont_in_list, /* containedin for this keyword */ + short *next_list, /* nextgroup for this keyword */ + int conceal_char +) { keyentry_T *kp; hashtab_T *ht; @@ -3986,9 +3931,11 @@ int conceal_char; * Return a pointer to the first argument. * Return NULL if the end of the command was found instead of further args. */ -static char_u * get_group_name(arg, name_end) -char_u *arg; /* start of the argument */ -char_u **name_end; /* pointer to end of the name */ +static char_u * +get_group_name ( + char_u *arg, /* start of the argument */ + char_u **name_end /* pointer to end of the name */ +) { char_u *rest; @@ -4012,10 +3959,12 @@ char_u **name_end; /* pointer to end of the name */ * Return a pointer to the next argument (which isn't an option). * Return NULL for any error; */ -static char_u * get_syn_options(arg, opt, conceal_char) -char_u *arg; /* next argument to be checked */ -syn_opt_arg_T *opt; /* various things */ -int *conceal_char UNUSED; +static char_u * +get_syn_options ( + char_u *arg, /* next argument to be checked */ + syn_opt_arg_T *opt, /* various things */ + int *conceal_char +) { char_u *gname_start, *gname; int syn_id; @@ -4161,9 +4110,7 @@ int *conceal_char UNUSED; * Set the contained flag, and if the item is not already contained, add it * to the specified top-level group, if any. */ -static void syn_incl_toplevel(id, flagsp) -int id; -int *flagsp; +static void syn_incl_toplevel(int id, int *flagsp) { if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0) return; @@ -4185,9 +4132,7 @@ int *flagsp; /* * Handle ":syntax include [@{group-name}] filename" command. */ -static void syn_cmd_include(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_include(exarg_T *eap, int syncing) { char_u *arg = eap->arg; int sgl_id = 1; @@ -4256,9 +4201,7 @@ int syncing UNUSED; /* * Handle ":syntax keyword {group-name} [{option}] keyword .." command. */ -static void syn_cmd_keyword(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_keyword(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *group_name_end; @@ -4365,9 +4308,11 @@ int syncing UNUSED; * * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .." */ -static void syn_cmd_match(eap, syncing) -exarg_T *eap; -int syncing; /* TRUE for ":syntax sync match .. " */ +static void +syn_cmd_match ( + exarg_T *eap, + int syncing /* TRUE for ":syntax sync match .. " */ +) { char_u *arg = eap->arg; char_u *group_name_end; @@ -4462,9 +4407,11 @@ int syncing; /* TRUE for ":syntax sync match .. " */ * Handle ":syntax region {group-name} [matchgroup={group-name}] * start {start} .. [skip {skip}] end {end} .. [{options}]". */ -static void syn_cmd_region(eap, syncing) -exarg_T *eap; -int syncing; /* TRUE for ":syntax sync region .." */ +static void +syn_cmd_region ( + exarg_T *eap, + int syncing /* TRUE for ":syntax sync region .." */ +) { char_u *arg = eap->arg; char_u *group_name_end; @@ -4699,9 +4646,7 @@ int syncing; /* TRUE for ":syntax sync region .." */ /* * A simple syntax group ID comparison function suitable for use in qsort() */ -static int syn_compare_stub(v1, v2) -const void *v1; -const void *v2; +static int syn_compare_stub(const void *v1, const void *v2) { const short *s1 = v1; const short *s2 = v2; @@ -4713,10 +4658,7 @@ const void *v2; * Combines lists of syntax clusters. * *clstr1 and *clstr2 must both be allocated memory; they will be consumed. */ -static void syn_combine_list(clstr1, clstr2, list_op) -short **clstr1; -short **clstr2; -int list_op; +static void syn_combine_list(short **clstr1, short **clstr2, int list_op) { int count1 = 0; int count2 = 0; @@ -4832,8 +4774,7 @@ int list_op; * Lookup a syntax cluster name and return it's ID. * If it is not found, 0 is returned. */ -static int syn_scl_name2id(name) -char_u *name; +static int syn_scl_name2id(char_u *name) { int i; char_u *name_u; @@ -4853,9 +4794,7 @@ char_u *name; /* * Like syn_scl_name2id(), but take a pointer + length argument. */ -static int syn_scl_namen2id(linep, len) -char_u *linep; -int len; +static int syn_scl_namen2id(char_u *linep, int len) { char_u *name; int id = 0; @@ -4874,9 +4813,7 @@ int len; * If it doesn't exist yet, a new entry is created. * Return 0 for failure. */ -static int syn_check_cluster(pp, len) -char_u *pp; -int len; +static int syn_check_cluster(char_u *pp, int len) { int id; char_u *name; @@ -4898,8 +4835,7 @@ int len; * "name" must be an allocated string, it will be consumed. * Return 0 for failure. */ -static int syn_add_cluster(name) -char_u *name; +static int syn_add_cluster(char_u *name) { int len; @@ -4944,9 +4880,7 @@ char_u *name; * Handle ":syntax cluster {cluster-name} [contains={groupname},..] * [add={groupname},..] [remove={groupname},..]". */ -static void syn_cmd_cluster(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_cluster(exarg_T *eap, int syncing) { char_u *arg = eap->arg; char_u *group_name_end; @@ -5010,7 +4944,7 @@ int syncing UNUSED; /* * On first call for current buffer: Init growing array. */ -static void init_syn_patterns() { +static void init_syn_patterns(void) { curwin->w_s->b_syn_patterns.ga_itemsize = sizeof(synpat_T); curwin->w_s->b_syn_patterns.ga_growsize = 10; } @@ -5020,9 +4954,7 @@ static void init_syn_patterns() { * Stores the pattern and program in a synpat_T. * Returns a pointer to the next argument, or NULL in case of an error. */ -static char_u * get_syn_pattern(arg, ci) -char_u *arg; -synpat_T *ci; +static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) { char_u *end; int *p; @@ -5108,9 +5040,7 @@ synpat_T *ci; /* * Handle ":syntax sync .." command. */ -static void syn_cmd_sync(eap, syncing) -exarg_T *eap; -int syncing UNUSED; +static void syn_cmd_sync(exarg_T *eap, int syncing) { char_u *arg_start = eap->arg; char_u *arg_end; @@ -5239,11 +5169,13 @@ int syncing UNUSED; * Careful: the argument is modified (NULs added). * returns FAIL for some error, OK for success. */ -static int get_id_list(arg, keylen, list) -char_u **arg; -int keylen; /* length of keyword */ -short **list; /* where to store the resulting list, if not +static int +get_id_list ( + char_u **arg, + int keylen, /* length of keyword */ + short **list /* where to store the resulting list, if not NULL, the list is silently skipped! */ +) { char_u *p = NULL; char_u *end; @@ -5409,8 +5341,7 @@ short **list; /* where to store the resulting list, if not /* * Make a copy of an ID list. */ -static short * copy_id_list(list) -short *list; +static short *copy_id_list(short *list) { int len; int count; @@ -5436,11 +5367,13 @@ short *list; * the current item. * This function is called very often, keep it fast!! */ -static int in_id_list(cur_si, list, ssp, contained) -stateitem_T *cur_si; /* current item or NULL */ -short *list; /* id list */ -struct sp_syn *ssp; /* group id and ":syn include" tag of group */ -int contained; /* group id is contained */ +static int +in_id_list ( + stateitem_T *cur_si, /* current item or NULL */ + short *list, /* id list */ + struct sp_syn *ssp, /* group id and ":syn include" tag of group */ + int contained /* group id is contained */ +) { int retval; short *scl_list; @@ -5554,8 +5487,7 @@ static struct subcommand subcommands[] = * This searches the subcommands[] table for the subcommand name, and calls a * syntax_subcommand() function to do the rest. */ -void ex_syntax(eap) -exarg_T *eap; +void ex_syntax(exarg_T *eap) { char_u *arg = eap->arg; char_u *subcmd_end; @@ -5588,8 +5520,7 @@ exarg_T *eap; } } -void ex_ownsyntax(eap) -exarg_T *eap; +void ex_ownsyntax(exarg_T *eap) { char_u *old_value; char_u *new_value; @@ -5628,8 +5559,7 @@ exarg_T *eap; } } -int syntax_present(win) -win_T *win; +int syntax_present(win_T *win) { return win->w_s->b_syn_patterns.ga_len != 0 || win->w_s->b_syn_clusters.ga_len != 0 @@ -5647,7 +5577,7 @@ static enum { * Reset include_link, include_default, include_none to 0. * Called when we are done expanding. */ -void reset_expand_highlight() { +void reset_expand_highlight(void) { include_link = include_default = include_none = 0; } @@ -5655,9 +5585,7 @@ void reset_expand_highlight() { * Handle command line completion for :match and :echohl command: Add "None" * as highlight group. */ -void set_context_in_echohl_cmd(xp, arg) -expand_T *xp; -char_u *arg; +void set_context_in_echohl_cmd(expand_T *xp, char_u *arg) { xp->xp_context = EXPAND_HIGHLIGHT; xp->xp_pattern = arg; @@ -5667,9 +5595,7 @@ char_u *arg; /* * Handle command line completion for :syntax command. */ -void set_context_in_syntax_cmd(xp, arg) -expand_T *xp; -char_u *arg; +void set_context_in_syntax_cmd(expand_T *xp, char_u *arg) { char_u *p; @@ -5706,9 +5632,7 @@ static char *(case_args[]) = {"match", "ignore", NULL}; * Function given to ExpandGeneric() to obtain the list syntax names for * expansion. */ -char_u * get_syntax_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_syntax_name(expand_T *xp, int idx) { if (expand_what == EXP_SUBCMD) return (char_u *)subcommands[idx].name; @@ -5719,13 +5643,15 @@ int idx; /* * Function called for expression evaluation: get syntax ID at file position. */ -int syn_get_id(wp, lnum, col, trans, spellp, keep_state) -win_T *wp; -long lnum; -colnr_T col; -int trans; /* remove transparency */ -int *spellp; /* return: can do spell checking */ -int keep_state; /* keep state of char at "col" */ +int +syn_get_id ( + win_T *wp, + long lnum, + colnr_T col, + int trans, /* remove transparency */ + int *spellp, /* return: can do spell checking */ + int keep_state /* keep state of char at "col" */ +) { /* When the position is not after the current position and in the same * line of the same buffer, need to restart parsing. */ @@ -5745,8 +5671,7 @@ int keep_state; /* keep state of char at "col" */ * Stores the current item sequence nr in "*seqnrp". * Returns the current flags. */ -int get_syntax_info(seqnrp) -int *seqnrp; +int get_syntax_info(int *seqnrp) { *seqnrp = current_seqnr; return current_flags; @@ -5755,7 +5680,7 @@ int *seqnrp; /* * Return conceal substitution character */ -int syn_get_sub_char() { +int syn_get_sub_char(void) { return current_sub_char; } @@ -5764,8 +5689,7 @@ int syn_get_sub_char() { * The caller must have called syn_get_id() before to fill the stack. * Returns -1 when "i" is out of range. */ -int syn_get_stack_item(i) -int i; +int syn_get_stack_item(int i) { if (i >= current_state.ga_len) { /* Need to invalidate the state, because we didn't properly finish it @@ -5780,9 +5704,7 @@ int i; /* * Function called to get folding level for line "lnum" in window "wp". */ -int syn_get_foldlevel(wp, lnum) -win_T *wp; -long lnum; +int syn_get_foldlevel(win_T *wp, long lnum) { int level = 0; int i; @@ -5806,8 +5728,7 @@ long lnum; /* * ":syntime". */ -void ex_syntime(eap) -exarg_T *eap; +void ex_syntime(exarg_T *eap) { if (STRCMP(eap->arg, "on") == 0) syn_time_on = TRUE; @@ -5821,8 +5742,7 @@ exarg_T *eap; EMSG2(_(e_invarg2), eap->arg); } -static void syn_clear_time(st) -syn_time_T *st; +static void syn_clear_time(syn_time_T *st) { profile_zero(&st->total); profile_zero(&st->slowest); @@ -5833,7 +5753,7 @@ syn_time_T *st; /* * Clear the syntax timing for the current buffer. */ -static void syntime_clear() { +static void syntime_clear(void) { int idx; synpat_T *spp; @@ -5851,9 +5771,7 @@ static void syntime_clear() { * Function given to ExpandGeneric() to obtain the possible arguments of the * ":syntime {on,off,clear,report}" command. */ -char_u * get_syntime_arg(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_syntime_arg(expand_T *xp, int idx) { switch (idx) { case 0: return (char_u *)"on"; @@ -5874,9 +5792,7 @@ typedef struct { char_u *pattern; } time_entry_T; -static int syn_compare_syntime(v1, v2) -const void *v1; -const void *v2; +static int syn_compare_syntime(const void *v1, const void *v2) { const time_entry_T *s1 = v1; const time_entry_T *s2 = v2; @@ -5887,7 +5803,7 @@ const void *v2; /* * Clear the syntax timing for the current buffer. */ -static void syntime_report() { +static void syntime_report(void) { int idx; synpat_T *spp; proftime_T tm; @@ -6151,9 +6067,11 @@ static char *(highlight_init_dark[]) = NULL }; -void init_highlight(both, reset) -int both; /* include groups where 'bg' doesn't matter */ -int reset; /* clear group first */ +void +init_highlight ( + int both, /* include groups where 'bg' doesn't matter */ + int reset /* clear group first */ +) { int i; char **pp; @@ -6227,8 +6145,7 @@ int reset; /* clear group first */ * Load color file "name". * Return OK for success, FAIL for failure. */ -int load_colors(name) -char_u *name; +int load_colors(char_u *name) { char_u *buf; int retval = FAIL; @@ -6258,10 +6175,12 @@ char_u *name; * When using ":hi clear" this is called recursively for each group with * "forceit" and "init" both TRUE. */ -void do_highlight(line, forceit, init) -char_u *line; -int forceit; -int init; /* TRUE when called for initializing */ +void +do_highlight ( + char_u *line, + int forceit, + int init /* TRUE when called for initializing */ +) { char_u *name_end; char_u *p; @@ -6871,7 +6790,7 @@ int init; /* TRUE when called for initializing */ } #if defined(EXITFREE) || defined(PROTO) -void free_highlight() { +void free_highlight(void) { int i; for (i = 0; i < highlight_ga.ga_len; ++i) { @@ -6888,7 +6807,7 @@ void free_highlight() { * Reset the cterm colors to what they were before Vim was started, if * possible. Otherwise reset them to zero. */ -void restore_cterm_colors() { +void restore_cterm_colors(void) { cterm_normal_fg_color = 0; cterm_normal_fg_bold = 0; cterm_normal_bg_color = 0; @@ -6898,9 +6817,7 @@ void restore_cterm_colors() { * Return TRUE if highlight group "idx" has any settings. * When "check_link" is TRUE also check for an existing link. */ -static int hl_has_settings(idx, check_link) -int idx; -int check_link; +static int hl_has_settings(int idx, int check_link) { return HL_TABLE()[idx].sg_term_attr != 0 || HL_TABLE()[idx].sg_cterm_attr != 0 @@ -6910,8 +6827,7 @@ int check_link; /* * Clear highlighting for one group. */ -static void highlight_clear(idx) -int idx; +static void highlight_clear(int idx) { HL_TABLE()[idx].sg_term = 0; vim_free(HL_TABLE()[idx].sg_start); @@ -6958,9 +6874,7 @@ static garray_T cterm_attr_table = {0, 0, 0, 0, NULL}; * if the combination is new. * Return 0 for error (no more room). */ -static int get_attr_entry(table, aep) -garray_T *table; -attrentry_T *aep; +static int get_attr_entry(garray_T *table, attrentry_T *aep) { int i; attrentry_T *taep; @@ -7051,7 +6965,7 @@ attrentry_T *aep; /* * Clear all highlight tables. */ -void clear_hl_tables() { +void clear_hl_tables(void) { int i; attrentry_T *taep; @@ -7073,9 +6987,7 @@ void clear_hl_tables() { * result. * Return the resulting attributes. */ -int hl_combine_attr(char_attr, prim_attr) -int char_attr; -int prim_attr; +int hl_combine_attr(int char_attr, int prim_attr) { attrentry_T *char_aep = NULL; attrentry_T *spell_aep; @@ -7142,8 +7054,7 @@ int prim_attr; * Get the highlight attributes (HL_BOLD etc.) from an attribute nr. * Only to be used when "attr" > HL_ALL. */ -int syn_attr2attr(attr) -int attr; +int syn_attr2attr(int attr) { attrentry_T *aep; @@ -7158,8 +7069,7 @@ int attr; } -attrentry_T * syn_term_attr2entry(attr) -int attr; +attrentry_T *syn_term_attr2entry(int attr) { attr -= ATTR_OFF; if (attr >= term_attr_table.ga_len) /* did ":syntax clear" */ @@ -7167,8 +7077,7 @@ int attr; return &(TERM_ATTR_ENTRY(attr)); } -attrentry_T * syn_cterm_attr2entry(attr) -int attr; +attrentry_T *syn_cterm_attr2entry(int attr) { attr -= ATTR_OFF; if (attr >= cterm_attr_table.ga_len) /* did ":syntax clear" */ @@ -7180,8 +7089,7 @@ int attr; #define LIST_STRING 2 #define LIST_INT 3 -static void highlight_list_one(id) -int id; +static void highlight_list_one(int id) { struct hl_group *sgp; int didh = FALSE; @@ -7225,13 +7133,7 @@ int id; last_set_msg(sgp->sg_scriptID); } -static int highlight_list_arg(id, didh, type, iarg, sarg, name) -int id; -int didh; -int type; -int iarg; -char_u *sarg; -char *name; +static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name) { char_u buf[100]; char_u *ts; @@ -7275,10 +7177,12 @@ char *name; * Return "1" if highlight group "id" has attribute "flag". * Return NULL otherwise. */ -char_u * highlight_has_attr(id, flag, modec) -int id; -int flag; -int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */ +char_u * +highlight_has_attr ( + int id, + int flag, + int modec /* 'g' for GUI, 'c' for cterm, 't' for term */ +) { int attr; @@ -7300,10 +7204,12 @@ int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */ /* * Return color name of highlight group "id". */ -char_u * highlight_color(id, what, modec) -int id; -char_u *what; /* "font", "fg", "bg", "sp", "fg#", "bg#" or "sp#" */ -int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */ +char_u * +highlight_color ( + int id, + char_u *what, /* "font", "fg", "bg", "sp", "fg#", "bg#" or "sp#" */ + int modec /* 'g' for GUI, 'c' for cterm, 't' for term */ +) { static char_u name[20]; int n; @@ -7349,9 +7255,11 @@ int modec; /* 'g' for GUI, 'c' for cterm, 't' for term */ /* * Return color name of highlight group "id" as RGB value. */ -long_u highlight_gui_color_rgb(id, fg) -int id; -int fg; /* TRUE = fg, FALSE = bg */ +long_u +highlight_gui_color_rgb ( + int id, + int fg /* TRUE = fg, FALSE = bg */ +) { guicolor_T color; @@ -7374,10 +7282,12 @@ int fg; /* TRUE = fg, FALSE = bg */ * Output the syntax list header. * Return TRUE when started a new line. */ -static int syn_list_header(did_header, outlen, id) -int did_header; /* did header already */ -int outlen; /* length of string that comes */ -int id; /* highlight group id */ +static int +syn_list_header ( + int did_header, /* did header already */ + int outlen, /* length of string that comes */ + int id /* highlight group id */ +) { int endcol = 19; int newline = TRUE; @@ -7417,8 +7327,10 @@ int id; /* highlight group id */ * Set the attribute numbers for a highlight group. * Called after one of the attributes has changed. */ -static void set_hl_attr(idx) -int idx; /* index in array */ +static void +set_hl_attr ( + int idx /* index in array */ +) { attrentry_T at_en; struct hl_group *sgp = HL_TABLE() + idx; @@ -7458,8 +7370,7 @@ int idx; /* index in array */ * Lookup a highlight group name and return it's ID. * If it is not found, 0 is returned. */ -int syn_name2id(name) -char_u *name; +int syn_name2id(char_u *name) { int i; char_u name_u[200]; @@ -7479,8 +7390,7 @@ char_u *name; /* * Return TRUE if highlight group "name" exists. */ -int highlight_exists(name) -char_u *name; +int highlight_exists(char_u *name) { return syn_name2id(name) > 0; } @@ -7489,8 +7399,7 @@ char_u *name; * Return the name of highlight group "id". * When not a valid ID return an empty string. */ -char_u * syn_id2name(id) -int id; +char_u *syn_id2name(int id) { if (id <= 0 || id > highlight_ga.ga_len) return (char_u *)""; @@ -7500,9 +7409,7 @@ int id; /* * Like syn_name2id(), but take a pointer + length argument. */ -int syn_namen2id(linep, len) -char_u *linep; -int len; +int syn_namen2id(char_u *linep, int len) { char_u *name; int id = 0; @@ -7521,9 +7428,7 @@ int len; * If it doesn't exist yet, a new entry is created. * Return 0 for failure. */ -int syn_check_group(pp, len) -char_u *pp; -int len; +int syn_check_group(char_u *pp, int len) { int id; char_u *name; @@ -7545,8 +7450,7 @@ int len; * "name" must be an allocated string, it will be consumed. * Return 0 for failure. */ -static int syn_add_group(name) -char_u *name; +static int syn_add_group(char_u *name) { char_u *p; @@ -7599,7 +7503,7 @@ char_u *name; * When, just after calling syn_add_group(), an error is discovered, this * function deletes the new name. */ -static void syn_unadd_group() { +static void syn_unadd_group(void) { --highlight_ga.ga_len; vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name); vim_free(HL_TABLE()[highlight_ga.ga_len].sg_name_u); @@ -7608,8 +7512,7 @@ static void syn_unadd_group() { /* * Translate a group ID to highlight attributes. */ -int syn_id2attr(hl_id) -int hl_id; +int syn_id2attr(int hl_id) { int attr; struct hl_group *sgp; @@ -7629,8 +7532,7 @@ int hl_id; /* * Translate a group ID to the final group ID (following links). */ -int syn_get_final_id(hl_id) -int hl_id; +int syn_get_final_id(int hl_id) { int count; struct hl_group *sgp; @@ -7661,7 +7563,7 @@ int hl_id; * screen redraw after any :highlight command. * Return FAIL when an invalid flag is found in 'highlight'. OK otherwise. */ -int highlight_changed() { +int highlight_changed(void) { int hlf; int i; char_u *p; @@ -7827,9 +7729,7 @@ static void highlight_list_two __ARGS((int cnt, int attr)); /* * Handle command line completion for :highlight command. */ -void set_context_in_highlight_cmd(xp, arg) -expand_T *xp; -char_u *arg; +void set_context_in_highlight_cmd(expand_T *xp, char_u *arg) { char_u *p; @@ -7872,7 +7772,7 @@ char_u *arg; /* * List highlighting matches in a nice way. */ -static void highlight_list() { +static void highlight_list(void) { int i; for (i = 10; --i >= 0; ) @@ -7881,9 +7781,7 @@ static void highlight_list() { highlight_list_two(99, 0); } -static void highlight_list_two(cnt, attr) -int cnt; -int attr; +static void highlight_list_two(int cnt, int attr) { msg_puts_attr((char_u *)&("N \bI \b! \b"[cnt / 11]), attr); msg_clr_eos(); @@ -7898,9 +7796,7 @@ int attr; * Function given to ExpandGeneric() to obtain the list of group names. * Also used for synIDattr() function. */ -char_u * get_highlight_name(xp, idx) -expand_T *xp UNUSED; -int idx; +char_u *get_highlight_name(expand_T *xp, int idx) { if (idx == highlight_ga.ga_len && include_none != 0) return (char_u *)"none"; diff --git a/src/tag.c b/src/tag.c index 3f144936c7..671f624ce8 100644 --- a/src/tag.c +++ b/src/tag.c @@ -107,12 +107,14 @@ static taggy_T ptag_entry = {NULL, {INIT_POS_T(0, 0, 0), 0}, 0, 0}; * * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise */ -int do_tag(tag, type, count, forceit, verbose) -char_u *tag; /* tag (pattern) to jump to */ -int type; -int count; -int forceit; /* :ta with ! */ -int verbose; /* print "tag not found" message */ +int +do_tag ( + char_u *tag, /* tag (pattern) to jump to */ + int type, + int count, + int forceit, /* :ta with ! */ + int verbose /* print "tag not found" message */ +) { taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; @@ -910,13 +912,12 @@ end_do_tag: /* * Free cached tags. */ -void tag_freematch() { +void tag_freematch(void) { vim_free(tagmatchname); tagmatchname = NULL; } -static void taglen_advance(l) -int l; +static void taglen_advance(int l) { if (l == MAXCOL) { msg_putchar('\n'); @@ -928,8 +929,7 @@ int l; /* * Print the tag stack */ -void do_tags(eap) -exarg_T *eap UNUSED; +void do_tags(exarg_T *eap) { int i; char_u *name; @@ -978,10 +978,7 @@ static int tag_strnicmp __ARGS((char_u *s1, char_u *s2, size_t len)); * return 0 for match, < 0 for smaller, > 0 for bigger * Make sure case is folded to uppercase in comparison (like for 'sort -f') */ -static int tag_strnicmp(s1, s2, len) -char_u *s1; -char_u *s2; -size_t len; +static int tag_strnicmp(char_u *s1, char_u *s2, size_t len) { int i; @@ -1014,9 +1011,7 @@ static void prepare_pats __ARGS((pat_T *pats, int has_re)); /* * Extract info from the tag search pattern "pats->pat". */ -static void prepare_pats(pats, has_re) -pat_T *pats; -int has_re; +static void prepare_pats(pat_T *pats, int has_re) { pats->head = pats->pat; pats->headlen = pats->len; @@ -1070,14 +1065,16 @@ int has_re; * TAG_NOIC don't always ignore case * TAG_KEEP_LANG keep language */ -int find_tags(pat, num_matches, matchesp, flags, mincount, buf_ffname) -char_u *pat; /* pattern to search for */ -int *num_matches; /* return: number of matches found */ -char_u ***matchesp; /* return: array of matches found */ -int flags; -int mincount; /* MAXCOL: find all matches +int +find_tags ( + char_u *pat, /* pattern to search for */ + int *num_matches, /* return: number of matches found */ + char_u ***matchesp, /* return: array of matches found */ + int flags, + int mincount, /* MAXCOL: find all matches other: minimal number of matches */ -char_u *buf_ffname; /* name of buffer for priority */ + char_u *buf_ffname /* name of buffer for priority */ +) { FILE *fp; char_u *lbuf; /* line buffer */ @@ -2020,9 +2017,7 @@ static void found_tagfile_cb __ARGS((char_u *fname, void *cookie)); * Callback function for finding all "tags" and "tags-??" files in * 'runtimepath' doc directories. */ -static void found_tagfile_cb(fname, cookie) -char_u *fname; -void *cookie UNUSED; +static void found_tagfile_cb(char_u *fname, void *cookie) { if (ga_grow(&tag_fnames, 1) == OK) ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = @@ -2030,7 +2025,7 @@ void *cookie UNUSED; } #if defined(EXITFREE) || defined(PROTO) -void free_tag_stuff() { +void free_tag_stuff(void) { ga_clear_strings(&tag_fnames); do_tag(NULL, DT_FREE, 0, 0, 0); tag_freematch(); @@ -2049,10 +2044,12 @@ void free_tag_stuff() { * * Return FAIL if no more tag file names, OK otherwise. */ -int get_tagfname(tnp, first, buf) -tagname_T *tnp; /* holds status info */ -int first; /* TRUE when first file name is wanted */ -char_u *buf; /* pointer to buffer of MAXPATHL chars */ +int +get_tagfname ( + tagname_T *tnp, /* holds status info */ + int first, /* TRUE when first file name is wanted */ + char_u *buf /* pointer to buffer of MAXPATHL chars */ +) { char_u *fname = NULL; char_u *r_ptr; @@ -2152,8 +2149,7 @@ char_u *buf; /* pointer to buffer of MAXPATHL chars */ /* * Free the contents of a tagname_T that was filled by get_tagfname(). */ -void tagname_free(tnp) -tagname_T *tnp; +void tagname_free(tagname_T *tnp) { vim_free(tnp->tn_tags); vim_findfile_cleanup(tnp->tn_search_ctx); @@ -2169,10 +2165,11 @@ tagname_T *tnp; * * Return FAIL if there is a format error in this line, OK otherwise. */ -static int parse_tag_line(lbuf, - tagp) -char_u *lbuf; /* line to be parsed */ -tagptrs_T *tagp; +static int +parse_tag_line ( + char_u *lbuf, /* line to be parsed */ + tagptrs_T *tagp +) { char_u *p; @@ -2232,8 +2229,7 @@ tagptrs_T *tagp; * Return TRUE if it is a static tag and adjust *tagname to the real tag. * Return FALSE if it is not a static tag. */ -static int test_for_static(tagp) -tagptrs_T *tagp; +static int test_for_static(tagptrs_T *tagp) { char_u *p; @@ -2274,9 +2270,11 @@ tagptrs_T *tagp; * * Return OK or FAIL. */ -static int parse_match(lbuf, tagp) -char_u *lbuf; /* input: matching line */ -tagptrs_T *tagp; /* output: pointers into the line */ +static int +parse_match ( + char_u *lbuf, /* input: matching line */ + tagptrs_T *tagp /* output: pointers into the line */ +) { int retval; char_u *p; @@ -2330,8 +2328,7 @@ tagptrs_T *tagp; /* output: pointers into the line */ * with the matching tag file name. * Returns an allocated string or NULL (out of memory). */ -static char_u * tag_full_fname(tagp) -tagptrs_T *tagp; +static char_u *tag_full_fname(tagptrs_T *tagp) { char_u *fullname; int c; @@ -2352,10 +2349,12 @@ tagptrs_T *tagp; * * returns OK for success, NOTAGFILE when file not found, FAIL otherwise. */ -static int jumpto_tag(lbuf, forceit, keep_help) -char_u *lbuf; /* line from the tags file for this tag */ -int forceit; /* :ta with ! */ -int keep_help; /* keep help flag (FALSE for cscope) */ +static int +jumpto_tag ( + char_u *lbuf, /* line from the tags file for this tag */ + int forceit, /* :ta with ! */ + int keep_help /* keep help flag (FALSE for cscope) */ +) { int save_secure; int save_magic; @@ -2647,10 +2646,7 @@ erret: * according to tag_fname (name of tag file containing fname). * Returns a pointer to allocated memory (or NULL when out of memory). */ -static char_u * expand_tag_fname(fname, tag_fname, expand) -char_u *fname; -char_u *tag_fname; -int expand; +static char_u *expand_tag_fname(char_u *fname, char_u *tag_fname, int expand) { char_u *p; char_u *retval; @@ -2696,8 +2692,7 @@ int expand; * resulting file name is simplified in place and will either be the same * length as that supplied, or shorter. */ -void simplify_filename(filename) -char_u *filename; +void simplify_filename(char_u *filename) { int components = 0; char_u *p, *tail, *start; @@ -2866,11 +2861,7 @@ char_u *filename; * Return TRUE if tag for file "fname" if tag file "tag_fname" is for current * file. */ -static int test_for_current(fname, fname_end, tag_fname, buf_ffname) -char_u *fname; -char_u *fname_end; -char_u *tag_fname; -char_u *buf_ffname; +static int test_for_current(char_u *fname, char_u *fname_end, char_u *tag_fname, char_u *buf_ffname) { int c; int retval = FALSE; @@ -2896,8 +2887,7 @@ char_u *buf_ffname; * Find the end of the tagaddress. * Return OK if ";\"" is following, FAIL otherwise. */ -static int find_extra(pp) -char_u **pp; +static int find_extra(char_u **pp) { char_u *str = *pp; @@ -2926,11 +2916,13 @@ char_u **pp; return FAIL; } -int expand_tags(tagnames, pat, num_file, file) -int tagnames; /* expand tag names */ -char_u *pat; -int *num_file; -char_u ***file; +int +expand_tags ( + int tagnames, /* expand tag names */ + char_u *pat, + int *num_file, + char_u ***file +) { int i; int c; @@ -2978,11 +2970,13 @@ static int add_tag_field __ARGS((dict_T *dict, char *field_name, char_u *start, * Add a tag field to the dictionary "dict". * Return OK or FAIL. */ -static int add_tag_field(dict, field_name, start, end) -dict_T *dict; -char *field_name; -char_u *start; /* start of the value */ -char_u *end; /* after the value; can be NULL */ +static int +add_tag_field ( + dict_T *dict, + char *field_name, + char_u *start, /* start of the value */ + char_u *end /* after the value; can be NULL */ +) { char_u *buf; int len = 0; @@ -3021,9 +3015,7 @@ char_u *end; /* after the value; can be NULL */ * Add the tags matching the specified pattern to the list "list" * as a dictionary */ -int get_tags(list, pat) -list_T *list; -char_u *pat; +int get_tags(list_T *list, char_u *pat) { int num_matches, i, ret; char_u **matches, *p; diff --git a/src/term.c b/src/term.c index 7525244ca1..a15e281de5 100644 --- a/src/term.c +++ b/src/term.c @@ -1143,8 +1143,7 @@ static int need_gather = FALSE; /* need to fill termleader[] */ static char_u termleader[256 + 1]; /* for check_termcode() */ static int check_for_codes = FALSE; /* check for key code response */ -static struct builtin_term * find_builtin_term(term) -char_u *term; +static struct builtin_term *find_builtin_term(char_u *term) { struct builtin_term *p; @@ -1171,8 +1170,7 @@ char_u *term; * Caller should check if 'name' is a valid builtin term. * The terminal's name is not set, as this is already done in termcapinit(). */ -static void parse_builtin_tcap(term) -char_u *term; +static void parse_builtin_tcap(char_u *term) { struct builtin_term *p; char_u name[2]; @@ -1222,8 +1220,7 @@ static void set_color_count __ARGS((int nr)); * Store it as a number in t_colors. * Store it as a string in T_CCO (using nr_colors[]). */ -static void set_color_count(nr) -int nr; +static void set_color_count(int nr) { char_u nr_colors[20]; /* string for number of colors */ @@ -1259,8 +1256,7 @@ static char *(key_names[]) = * * While doing this, until ttest(), some options may be NULL, be careful. */ -int set_termname(term) -char_u *term; +int set_termname(char_u *term) { struct builtin_term *termp; #ifdef HAVE_TGETENT @@ -1655,9 +1651,11 @@ char_u *term; # define HMT_SGR 64 static int has_mouse_termcode = 0; -void set_mouse_termcode(n, s) -int n; /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ -char_u *s; +void +set_mouse_termcode ( + int n, /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ + char_u *s +) { char_u name[2]; @@ -1683,8 +1681,10 @@ char_u *s; # if ((defined(UNIX) || defined(VMS) || defined(OS2)) \ && defined(FEAT_MOUSE_TTY)) || defined(PROTO) -void del_mouse_termcode(n) -int n; /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ +void +del_mouse_termcode ( + int n /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ +) { char_u name[2]; @@ -1714,9 +1714,7 @@ int n; /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ * Call tgetent() * Return error message if it fails, NULL if it's OK. */ -static char_u * tgetent_error(tbuf, term) -char_u *tbuf; -char_u *term; +static char_u *tgetent_error(char_u *tbuf, char_u *term) { int i; @@ -1749,9 +1747,7 @@ char_u *term; * Some versions of tgetstr() have been reported to return -1 instead of NULL. * Fix that here. */ -static char_u * vim_tgetstr(s, pp) -char *s; -char_u **pp; +static char_u *vim_tgetstr(char *s, char_u **pp) { char *p; @@ -1770,9 +1766,11 @@ char_u **pp; * and "li" entries never change. But on some systems this works. * Errors while getting the entries are ignored. */ -void getlinecol(cp, rp) -long *cp; /* pointer to columns */ -long *rp; /* pointer to rows */ +void +getlinecol ( + long *cp, /* pointer to columns */ + long *rp /* pointer to rows */ +) { char_u tbuf[TBUFSZ]; @@ -1793,9 +1791,7 @@ long *rp; /* pointer to rows */ * If force given, replace an existing entry. * Return FAIL if the entry was not found, OK if the entry was added. */ -int add_termcap_entry(name, force) -char_u *name; -int force; +int add_termcap_entry(char_u *name, int force) { char_u *term; int key; @@ -1888,8 +1884,7 @@ int force; return FAIL; } -static int term_is_builtin(name) -char_u *name; +static int term_is_builtin(char_u *name) { return STRNCMP(name, "builtin_", (size_t)8) == 0; } @@ -1899,8 +1894,7 @@ char_u *name; * Assume that the terminal is using 8-bit controls when the name contains * "8bit", like in "xterm-8bit". */ -int term_is_8bit(name) -char_u *name; +int term_is_8bit(char_u *name) { return detected_8bit || strstr((char *)name, "8bit") != NULL; } @@ -1911,8 +1905,7 @@ char_u *name; * ] -> * O -> */ -static int term_7to8bit(p) -char_u *p; +static int term_7to8bit(char_u *p) { if (*p == ESC) { if (p[1] == '[') @@ -1928,8 +1921,7 @@ char_u *p; #if !defined(HAVE_TGETENT) || defined(AMIGA) || defined(PROTO) -char_u * tltoa(i) -unsigned long i; +char_u *tltoa(unsigned long i) { static char_u buf[16]; char_u *p; @@ -1953,9 +1945,7 @@ unsigned long i; */ static char *tgoto __ARGS((char *, int, int)); -static char * tgoto(cm, x, y) -char *cm; -int x, y; +static char *tgoto(char *cm, int x, int y) { static char buf[30]; char *p, *s, *e; @@ -2001,8 +1991,7 @@ int x, y; * If "name" is NULL or empty, get the terminal name from the environment. * If that fails, use the default terminal name. */ -void termcapinit(name) -char_u *name; +void termcapinit(char_u *name) { char_u *term; @@ -2037,7 +2026,7 @@ static int out_pos = 0; /* number of chars in out_buf */ /* * out_flush(): flush the output buffer */ -void out_flush() { +void out_flush(void) { int len; if (out_pos != 0) { @@ -2052,7 +2041,7 @@ void out_flush() { * Sometimes a byte out of a multi-byte character is written with out_char(). * To avoid flushing half of the character, call this function first. */ -void out_flush_check() { +void out_flush_check(void) { if (enc_dbcs != 0 && out_pos >= OUT_SIZE - MB_MAXBYTES) out_flush(); } @@ -2063,8 +2052,7 @@ void out_flush_check() { * This should not be used for outputting text on the screen (use functions * like msg_puts() and screen_putchar() for that). */ -void out_char(c) -unsigned c; +void out_char(unsigned c) { #if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(MACOS_X_UNIX) if (c == '\n') /* turn LF into CR-LF (CRMOD doesn't seem to do this) */ @@ -2083,8 +2071,7 @@ static void out_char_nf __ARGS((unsigned)); /* * out_char_nf(c): like out_char(), but don't flush when p_wd is set */ -static void out_char_nf(c) -unsigned c; +static void out_char_nf(unsigned c) { #if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(MACOS_X_UNIX) if (c == '\n') /* turn LF into CR-LF (CRMOD doesn't seem to do this) */ @@ -2108,8 +2095,7 @@ unsigned c; * This should only be used for writing terminal codes, not for outputting * normal text (use functions like msg_puts() and screen_putchar() for that). */ -void out_str_nf(s) -char_u *s; +void out_str_nf(char_u *s) { if (out_pos > OUT_SIZE - 20) /* avoid terminal strings being split up */ out_flush(); @@ -2128,8 +2114,7 @@ char_u *s; * This should only be used for writing terminal codes, not for outputting * normal text (use functions like msg_puts() and screen_putchar() for that). */ -void out_str(s) -char_u *s; +void out_str(char_u *s) { if (s != NULL && *s) { /* avoid terminal strings being split up */ @@ -2151,35 +2136,28 @@ char_u *s; /* * cursor positioning using termcap parser. (jw) */ -void term_windgoto(row, col) -int row; -int col; +void term_windgoto(int row, int col) { OUT_STR(tgoto((char *)T_CM, col, row)); } -void term_cursor_right(i) -int i; +void term_cursor_right(int i) { OUT_STR(tgoto((char *)T_CRI, 0, i)); } -void term_append_lines(line_count) -int line_count; +void term_append_lines(int line_count) { OUT_STR(tgoto((char *)T_CAL, 0, line_count)); } -void term_delete_lines(line_count) -int line_count; +void term_delete_lines(int line_count) { OUT_STR(tgoto((char *)T_CDL, 0, line_count)); } #if defined(HAVE_TGETENT) || defined(PROTO) -void term_set_winpos(x, y) -int x; -int y; +void term_set_winpos(int x, int y) { /* Can't handle a negative value here */ if (x < 0) @@ -2189,16 +2167,13 @@ int y; OUT_STR(tgoto((char *)T_CWP, y, x)); } -void term_set_winsize(width, height) -int width; -int height; +void term_set_winsize(int width, int height) { OUT_STR(tgoto((char *)T_CWS, height, width)); } #endif -void term_fg_color(n) -int n; +void term_fg_color(int n) { /* Use "AF" termcap entry if present, "Sf" entry otherwise */ if (*T_CAF) @@ -2207,8 +2182,7 @@ int n; term_color(T_CSF, n); } -void term_bg_color(n) -int n; +void term_bg_color(int n) { /* Use "AB" termcap entry if present, "Sb" entry otherwise */ if (*T_CAB) @@ -2217,9 +2191,7 @@ int n; term_color(T_CSB, n); } -static void term_color(s, n) -char_u *s; -int n; +static void term_color(char_u *s, int n) { char buf[20]; int i = 2; /* index in s[] just after [ or CSI */ @@ -2252,8 +2224,7 @@ int n; /* * Generic function to set window title, using t_ts and t_fs. */ -void term_settitle(title) -char_u *title; +void term_settitle(char_u *title) { /* t_ts takes one argument: column in status line */ OUT_STR(tgoto((char *)T_TS, 0, 0)); /* set title start */ @@ -2267,8 +2238,7 @@ char_u *title; * Make sure we have a valid set or terminal options. * Replace all entries that are NULL by empty_option */ -void ttest(pairs) -int pairs; +void ttest(int pairs) { check_options(); /* make sure no options are NULL */ @@ -2360,9 +2330,7 @@ int pairs; * Represent the given long_u as individual bytes, with the most significant * byte first, and store them in dst. */ -void add_long_to_buf(val, dst) -long_u val; -char_u *dst; +void add_long_to_buf(long_u val, char_u *dst) { int i; int shift; @@ -2383,9 +2351,7 @@ static int get_long_from_buf __ARGS((char_u *buf, long_u *val)); * (between sizeof(long_u) and 2 * sizeof(long_u)), or -1 if not enough bytes * were present. */ -static int get_long_from_buf(buf, val) -char_u *buf; -long_u *val; +static int get_long_from_buf(char_u *buf, long_u *val) { int len; char_u bytes[sizeof(long_u)]; @@ -2413,10 +2379,7 @@ long_u *val; * from buf (between num_bytes and num_bytes*2), or -1 if not enough bytes were * available. */ -static int get_bytes_from_buf(buf, bytes, num_bytes) -char_u *buf; -char_u *bytes; -int num_bytes; +static int get_bytes_from_buf(char_u *buf, char_u *bytes, int num_bytes) { int len = 0; int i; @@ -2449,7 +2412,7 @@ int num_bytes; * Check if the new shell size is valid, correct it if it's too small or way * too big. */ -void check_shellsize() { +void check_shellsize(void) { if (Rows < min_rows()) /* need room for one window and command line */ Rows = min_rows(); limit_screen_size(); @@ -2458,7 +2421,7 @@ void check_shellsize() { /* * Limit Rows and Columns to avoid an overflow in Rows * Columns. */ -void limit_screen_size() { +void limit_screen_size(void) { if (Columns < MIN_COLUMNS) Columns = MIN_COLUMNS; else if (Columns > 10000) @@ -2470,7 +2433,7 @@ void limit_screen_size() { /* * Invoked just before the screen structures are going to be (re)allocated. */ -void win_new_shellsize() { +void win_new_shellsize(void) { static int old_Rows = 0; static int old_Columns = 0; @@ -2493,7 +2456,7 @@ void win_new_shellsize() { * Call this function when the Vim shell has been resized in any way. * Will obtain the current size and redraw (also when size didn't change). */ -void shell_resized() { +void shell_resized(void) { set_shellsize(0, 0, FALSE); } @@ -2501,7 +2464,7 @@ void shell_resized() { * Check if the shell size changed. Handle a resize. * When the size didn't change, nothing happens. */ -void shell_resized_check() { +void shell_resized_check(void) { int old_Rows = Rows; int old_Columns = Columns; @@ -2521,9 +2484,7 @@ void shell_resized_check() { * If 'mustset' is FALSE, we may try to get the real window size and if * it fails use 'width' and 'height'. */ -void set_shellsize(width, height, mustset) -int width, height; -int mustset; +void set_shellsize(int width, int height, int mustset) { static int busy = FALSE; @@ -2616,8 +2577,7 @@ int mustset; * Set the terminal to TMODE_RAW (for Normal mode) or TMODE_COOK (for external * commands and Ex mode). */ -void settmode(tmode) -int tmode; +void settmode(int tmode) { if (full_screen) { @@ -2652,7 +2612,7 @@ int tmode; } } -void starttermcap() { +void starttermcap(void) { if (full_screen && !termcap_active) { out_str(T_TI); /* start termcap mode */ out_str(T_KS); /* start "keypad transmit" mode */ @@ -2669,7 +2629,7 @@ void starttermcap() { } } -void stoptermcap() { +void stoptermcap(void) { screen_stop_highlight(); reset_cterm_colors(); if (termcap_active) { @@ -2714,7 +2674,7 @@ void stoptermcap() { * request to terminal while reading from a file). * The result is caught in check_termcode(). */ -void may_req_termresponse() { +void may_req_termresponse(void) { if (crv_status == CRV_GET && cur_tmode == TMODE_RAW && starting == 0 @@ -2744,7 +2704,7 @@ void may_req_termresponse() { * This function has the side effect that changes cursor position, so * it must be called immediately after entering termcap mode. */ -void may_req_ambiguous_char_width() { +void may_req_ambiguous_char_width(void) { if (u7_status == U7_GET && cur_tmode == TMODE_RAW && termcap_active @@ -2799,14 +2759,14 @@ static void log_tr(char *msg) { /* * Return TRUE when saving and restoring the screen. */ -int swapping_screen() { +int swapping_screen(void) { return full_screen && *T_TI != NUL; } /* * setmouse() - switch mouse on/off depending on current mode and 'mouse' */ -void setmouse() { +void setmouse(void) { int checkfor; @@ -2846,8 +2806,7 @@ void setmouse() { * - the current buffer is a help file and 'h' is in 'mouse' and we are in a * normal editing mode (not at hit-return message). */ -int mouse_has(c) -int c; +int mouse_has(int c) { char_u *p; @@ -2867,7 +2826,7 @@ int c; /* * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos". */ -int mouse_model_popup() { +int mouse_model_popup(void) { return p_mousem[0] == 'p'; } @@ -2876,7 +2835,7 @@ int mouse_model_popup() { * terminals this makes the screen scrolled to the correct position. * Used when starting Vim or returning from a shell. */ -void scroll_start() { +void scroll_start(void) { if (*T_VS != NUL) { out_str(T_VS); out_str(T_VE); @@ -2889,7 +2848,7 @@ static int cursor_is_off = FALSE; /* * Enable the cursor. */ -void cursor_on() { +void cursor_on(void) { if (cursor_is_off) { out_str(T_VE); cursor_is_off = FALSE; @@ -2899,7 +2858,7 @@ void cursor_on() { /* * Disable the cursor. */ -void cursor_off() { +void cursor_off(void) { if (full_screen) { if (!cursor_is_off) out_str(T_VI); /* disable cursor */ @@ -2911,7 +2870,7 @@ void cursor_off() { /* * Set cursor shape to match Insert mode. */ -void term_cursor_shape() { +void term_cursor_shape(void) { static int showing_insert_mode = MAYBE; if (!full_screen || *T_CSI == NUL || *T_CEI == NUL) @@ -2936,9 +2895,7 @@ void term_cursor_shape() { * Also set the vertical scroll region for a vertically split window. Always * the full width of the window, excluding the vertical separator. */ -void scroll_region_set(wp, off) -win_T *wp; -int off; +void scroll_region_set(win_T *wp, int off) { OUT_STR(tgoto((char *)T_CS, W_WINROW(wp) + wp->w_height - 1, W_WINROW(wp) + off)); @@ -2951,7 +2908,7 @@ int off; /* * Reset scrolling region to the whole screen. */ -void scroll_region_reset() { +void scroll_region_reset(void) { OUT_STR(tgoto((char *)T_CS, (int)Rows - 1, 0)); if (*T_CSV != NUL) OUT_STR(tgoto((char *)T_CSV, (int)Columns - 1, 0)); @@ -2974,7 +2931,7 @@ static int tc_len = 0; /* current number of entries in termcodes[] */ static int termcode_star __ARGS((char_u *code, int len)); -void clear_termcodes() { +void clear_termcodes(void) { while (tc_len > 0) vim_free(termcodes[--tc_len].code); vim_free(termcodes); @@ -2999,10 +2956,7 @@ void clear_termcodes() { * "flags" is TRUE when replacing 7-bit by 8-bit controls is desired. * "flags" can also be ATC_FROM_TERM for got_code_from_term(). */ -void add_termcode(name, string, flags) -char_u *name; -char_u *string; -int flags; +void add_termcode(char_u *name, char_u *string, int flags) { struct termcode *new_tc; int i, j; @@ -3107,9 +3061,7 @@ int flags; * The "X" can be any character. * Return 0 if not found, 2 for ;*X and 1 for O*X and *X. */ -static int termcode_star(code, len) -char_u *code; -int len; +static int termcode_star(char_u *code, int len) { /* Shortest is *X. With ; shortest is 1;*X */ if (len >= 3 && code[len - 2] == '*') { @@ -3121,8 +3073,7 @@ int len; return 0; } -char_u * find_termcode(name) -char_u *name; +char_u *find_termcode(char_u *name) { int i; @@ -3132,16 +3083,14 @@ char_u *name; return NULL; } -char_u * get_termcode(i) -int i; +char_u *get_termcode(int i) { if (i >= tc_len) return NULL; return &termcodes[i].name[0]; } -void del_termcode(name) -char_u *name; +void del_termcode(char_u *name) { int i; @@ -3158,8 +3107,7 @@ char_u *name; /* not found. Give error message? */ } -static void del_termcode_idx(idx) -int idx; +static void del_termcode_idx(int idx) { int i; @@ -3173,7 +3121,7 @@ int idx; * Called when detected that the terminal sends 8-bit codes. * Convert all 7-bit codes to their 8-bit equivalent. */ -static void switch_to_8bit() { +static void switch_to_8bit(void) { int i; int c; @@ -3206,8 +3154,7 @@ static int orig_topfill = 0; * Set orig_topline. Used when jumping to another window, so that a double * click still works. */ -void set_mouse_topline(wp) -win_T *wp; +void set_mouse_topline(win_T *wp) { orig_topline = wp->w_topline; orig_topfill = wp->w_topfill; @@ -3227,11 +3174,7 @@ win_T *wp; * "buflen" is then the length of the string in buf[] and is updated for * inserts and deletes. */ -int check_termcode(max_offset, buf, bufsize, buflen) -int max_offset; -char_u *buf; -int bufsize; -int *buflen; +int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen) { char_u *tp; char_u *p; @@ -4196,12 +4139,14 @@ int *buflen; * nothing). When 'cpoptions' does not contain 'B', a backslash can be used * instead of a CTRL-V. */ -char_u * replace_termcodes(from, bufp, from_part, do_lt, special) -char_u *from; -char_u **bufp; -int from_part; -int do_lt; /* also translate */ -int special; /* always accept notation */ +char_u * +replace_termcodes ( + char_u *from, + char_u **bufp, + int from_part, + int do_lt, /* also translate */ + int special /* always accept notation */ +) { int i; int slen; @@ -4374,8 +4319,7 @@ int special; /* always accept notation */ * Find a termcode with keys 'src' (must be NUL terminated). * Return the index in termcodes[], or -1 if not found. */ -int find_term_bykeys(src) -char_u *src; +int find_term_bykeys(char_u *src) { int i; int slen = (int)STRLEN(src); @@ -4392,7 +4336,7 @@ char_u *src; * Gather the first characters in the terminal key codes into a string. * Used to speed up check_termcode(). */ -static void gather_termleader() { +static void gather_termleader(void) { int i; int len = 0; @@ -4414,7 +4358,7 @@ static void gather_termleader() { * Show all termcodes (for ":set termcap") * This code looks a lot like showoptions(), but is different. */ -void show_termcodes() { +void show_termcodes(void) { int col; int *items; int item_count; @@ -4492,10 +4436,7 @@ void show_termcodes() { * Show one termcode entry. * Output goes into IObuff[] */ -int show_one_termcode(name, code, printit) -char_u *name; -char_u *code; -int printit; +int show_one_termcode(char_u *name, char_u *code, int printit) { char_u *p; int len; @@ -4546,13 +4487,13 @@ int printit; static int xt_index_in = 0; static int xt_index_out = 0; -static void req_codes_from_term() { +static void req_codes_from_term(void) { xt_index_out = 0; xt_index_in = 0; req_more_codes_from_term(); } -static void req_more_codes_from_term() { +static void req_more_codes_from_term(void) { char buf[11]; int old_idx = xt_index_out; @@ -4587,9 +4528,7 @@ static void req_more_codes_from_term() { * Both and are encoded in hex. * "code" points to the "0" or "1". */ -static void got_code_from_term(code, len) -char_u *code; -int len; +static void got_code_from_term(char_u *code, int len) { #define XT_LEN 100 char_u name[3]; @@ -4668,7 +4607,7 @@ int len; * keyboard input. We don't want responses to be send to that program or * handled as typed text. */ -static void check_for_codes_from_term() { +static void check_for_codes_from_term(void) { int c; /* If no codes requested or all are answered, no need to wait. */ @@ -4714,9 +4653,11 @@ static void check_for_codes_from_term() { * * Returns NULL when there is a problem. */ -char_u * translate_mapping(str, expmap) -char_u *str; -int expmap; /* TRUE when expanding mappings on command-line */ +char_u * +translate_mapping ( + char_u *str, + int expmap /* TRUE when expanding mappings on command-line */ +) { garray_T ga; int c; diff --git a/src/ui.c b/src/ui.c index 7eebee6572..76eca6fff9 100644 --- a/src/ui.c +++ b/src/ui.c @@ -19,9 +19,7 @@ #include "vim.h" -void ui_write(s, len) -char_u *s; -int len; +void ui_write(char_u *s, int len) { #ifndef NO_CONSOLE /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */ @@ -53,9 +51,7 @@ static char_u *ta_str = NULL; static int ta_off; /* offset for next char to use when ta_str != NULL */ static int ta_len; /* length of ta_str when it's not NULL*/ -void ui_inchar_undo(s, len) -char_u *s; -int len; +void ui_inchar_undo(char_u *s, int len) { char_u *new; int newlen; @@ -91,11 +87,13 @@ int len; * from a remote client) "buf" can no longer be used. "tb_change_cnt" is NULL * otherwise. */ -int ui_inchar(buf, maxlen, wtime, tb_change_cnt) -char_u *buf; -int maxlen; -long wtime; /* don't use "time", MIPS cannot handle it */ -int tb_change_cnt; +int +ui_inchar ( + char_u *buf, + int maxlen, + long wtime, /* don't use "time", MIPS cannot handle it */ + int tb_change_cnt +) { int retval = 0; @@ -159,7 +157,7 @@ theend: /* * return non-zero if a character is available */ -int ui_char_avail() { +int ui_char_avail(void) { #ifndef NO_CONSOLE # ifdef NO_CONSOLE_INPUT if (no_console_input()) @@ -175,9 +173,7 @@ int ui_char_avail() { * Delay for the given number of milliseconds. If ignoreinput is FALSE then we * cancel the delay if a key is hit. */ -void ui_delay(msec, ignoreinput) -long msec; -int ignoreinput; +void ui_delay(long msec, int ignoreinput) { mch_delay(msec, ignoreinput); } @@ -187,7 +183,7 @@ int ignoreinput; * otherwise fake it by starting a new shell. * When running the GUI iconify the window. */ -void ui_suspend() { +void ui_suspend(void) { mch_suspend(); } @@ -196,7 +192,7 @@ void ui_suspend() { * When the OS can't really suspend, call this function to start a shell. * This is never called in the GUI. */ -void suspend_shell() { +void suspend_shell(void) { if (*p_sh == NUL) EMSG(_(e_shellempty)); else { @@ -212,7 +208,7 @@ void suspend_shell() { * Use the new sizes as defaults for 'columns' and 'lines'. * Return OK when size could be determined, FAIL otherwise. */ -int ui_get_shellsize() { +int ui_get_shellsize(void) { int retval; retval = mch_get_shellsize(); @@ -232,8 +228,10 @@ int ui_get_shellsize() { * The gui_set_shellsize() or mch_set_shellsize() function will try to set the * new size. If this is not possible, it will adjust Rows and Columns. */ -void ui_set_shellsize(mustset) -int mustset UNUSED; /* set by the user */ +void +ui_set_shellsize ( + int mustset /* set by the user */ +) { mch_set_shellsize(); } @@ -242,13 +240,13 @@ int mustset UNUSED; /* set by the user */ * Called when Rows and/or Columns changed. Adjust scroll region and mouse * region. */ -void ui_new_shellsize() { +void ui_new_shellsize(void) { if (full_screen && !exiting) { mch_new_shellsize(); } } -void ui_breakcheck() { +void ui_breakcheck(void) { mch_breakcheck(); } @@ -305,16 +303,16 @@ static int inbufcount = 0; /* number of chars in inbuf[] */ * are used by the gui_* calls when a GUI is used to handle keyboard input. */ -int vim_is_input_buf_full() { +int vim_is_input_buf_full(void) { return inbufcount >= INBUFLEN; } -int vim_is_input_buf_empty() { +int vim_is_input_buf_empty(void) { return inbufcount == 0; } #if defined(FEAT_OLE) || defined(PROTO) -int vim_free_in_input_buf() { +int vim_free_in_input_buf(void) { return INBUFLEN - inbufcount; } @@ -325,7 +323,7 @@ int vim_free_in_input_buf() { * Return the current contents of the input buffer and make it empty. * The returned pointer must be passed to set_input_buf() later. */ -char_u * get_input_buf() { +char_u *get_input_buf(void) { garray_T *gap; /* We use a growarray to store the data pointer and the length. */ @@ -345,8 +343,7 @@ char_u * get_input_buf() { * Restore the input buffer with a pointer returned from get_input_buf(). * The allocated memory is freed, this only works once! */ -void set_input_buf(p) -char_u *p; +void set_input_buf(char_u *p) { garray_T *gap = (garray_T *)p; @@ -370,9 +367,7 @@ char_u *p; * Special keys start with CSI. A real CSI must have been translated to * CSI KS_EXTRA KE_CSI. K_SPECIAL doesn't require translation. */ -void add_to_input_buf(s, len) -char_u *s; -int len; +void add_to_input_buf(char_u *s, int len) { if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN) return; /* Shouldn't ever happen! */ @@ -413,9 +408,7 @@ void add_to_input_buf_csi(char_u *str, int len) { #endif -void push_raw_key(s, len) -char_u *s; -int len; +void push_raw_key(char_u *s, int len) { while (len--) inbuf[inbufcount++] = *s++; @@ -424,7 +417,7 @@ int len; #if defined(FEAT_GUI) || defined(FEAT_EVAL) || defined(FEAT_EX_EXTRA) \ || defined(PROTO) /* Remove everything from the input buffer. Called when ^C is found */ -void trash_input_buf() { +void trash_input_buf(void) { inbufcount = 0; } @@ -435,9 +428,7 @@ void trash_input_buf() { * it in buf. * Note: this function used to be Read() in unix.c */ -int read_from_input_buf(buf, maxlen) -char_u *buf; -long maxlen; +int read_from_input_buf(char_u *buf, long maxlen) { if (inbufcount == 0) /* if the buffer is empty, fill it */ fill_input_buf(TRUE); @@ -450,8 +441,7 @@ long maxlen; return (int)maxlen; } -void fill_input_buf(exit_on_error) -int exit_on_error UNUSED; +void fill_input_buf(int exit_on_error) { #if defined(UNIX) || defined(OS2) || defined(VMS) || defined(MACOS_X_UNIX) int len; @@ -567,7 +557,7 @@ int exit_on_error UNUSED; /* * Exit because of an input read error. */ -void read_error_exit() { +void read_error_exit(void) { if (silent_mode) /* Normal way to exit for "ex -s" */ getout(0); STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); @@ -578,7 +568,7 @@ void read_error_exit() { /* * May update the shape of the cursor. */ -void ui_cursor_shape() { +void ui_cursor_shape(void) { term_cursor_shape(); @@ -592,8 +582,7 @@ void ui_cursor_shape() { /* * Check bounds for column number */ -int check_col(col) -int col; +int check_col(int col) { if (col < 0) return 0; @@ -605,8 +594,7 @@ int col; /* * Check bounds for row number */ -int check_row(row) -int row; +int check_row(int row) { if (row < 0) return 0; @@ -626,9 +614,7 @@ int row; /* * Get the contents of the X CUT_BUFFER0 and put it in "cbd". */ -void yank_cut_buffer0(dpy, cbd) -Display *dpy; -VimClipboard *cbd; +void yank_cut_buffer0(Display *dpy, VimClipboard *cbd) { int nbytes = 0; char_u *buffer = (char_u *)XFetchBuffer(dpy, &nbytes, 0); @@ -694,10 +680,12 @@ VimClipboard *cbd; * If flags has MOUSE_SETPOS, nothing is done, only the current position is * remembered. */ -int jump_to_mouse(flags, inclusive, which_button) -int flags; -int *inclusive; /* used for inclusive operator, can be NULL */ -int which_button; /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */ +int +jump_to_mouse ( + int flags, + int *inclusive, /* used for inclusive operator, can be NULL */ + int which_button /* MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE */ +) { static int on_status_line = 0; /* #lines below bottom of window */ static int on_sep_line = 0; /* on separator right of window */ @@ -986,11 +974,7 @@ retnomove: * window "win". * Returns TRUE if the position is below the last line. */ -int mouse_comp_pos(win, rowp, colp, lnump) -win_T *win; -int *rowp; -int *colp; -linenr_T *lnump; +int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) { int col = *colp; int row = *rowp; @@ -1056,9 +1040,7 @@ linenr_T *lnump; * Find the window at screen position "*rowp" and "*colp". The positions are * updated to become relative to the top-left of the window. */ -win_T * mouse_find_win(rowp, colp) -int *rowp; -int *colp UNUSED; +win_T *mouse_find_win(int *rowp, int *colp) { frame_T *fp; @@ -1090,8 +1072,7 @@ int *colp UNUSED; /* * Translate window coordinates to buffer position without any side effects */ -int get_fpos_of_mouse(mpos) -pos_T *mpos; +int get_fpos_of_mouse(pos_T *mpos) { win_T *wp; int row = mouse_row; @@ -1129,10 +1110,7 @@ pos_T *mpos; * Convert a virtual (screen) column to a character column. * The first column is one. */ -int vcol2col(wp, lnum, vcol) -win_T *wp; -linenr_T lnum; -int vcol; +int vcol2col(win_T *wp, linenr_T lnum, int vcol) { /* try to advance to the specified column */ int count = 0; @@ -1154,8 +1132,7 @@ int vcol; /* * Save current Input Method status to specified place. */ -void im_save_status(psave) -long *psave; +void im_save_status(long *psave) { /* Don't save when 'imdisable' is set or "xic" is NULL, IM is always * disabled then (but might start later). diff --git a/src/undo.c b/src/undo.c index 9dfdcbe74c..d5bdfb53b1 100644 --- a/src/undo.c +++ b/src/undo.c @@ -98,9 +98,9 @@ static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, static void u_freeentry __ARGS((u_entry_T *, long)); static void corruption_error __ARGS((char *mesg, char_u *file_name)); static void u_free_uhp __ARGS((u_header_T *uhp)); -static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, +static size_t fwrite_crypt __ARGS((buf_T *buf, char_u *ptr, size_t len, FILE *fp)); -static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len)); +static char_u *read_string_decrypt __ARGS((buf_T *buf, FILE *fd, int len)); static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash)); static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp)); static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name)); @@ -210,7 +210,7 @@ static void u_check(int newhead_may_be_NULL) { * Careful: may trigger autocommands that reload the buffer. * Returns OK or FAIL. */ -int u_save_cursor() { +int u_save_cursor(void) { return u_save((linenr_T)(curwin->w_cursor.lnum - 1), (linenr_T)(curwin->w_cursor.lnum + 1)); } @@ -221,8 +221,7 @@ int u_save_cursor() { * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_save(top, bot) -linenr_T top, bot; +int u_save(linenr_T top, linenr_T bot) { if (undo_off) return OK; @@ -244,8 +243,7 @@ linenr_T top, bot; * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_savesub(lnum) -linenr_T lnum; +int u_savesub(linenr_T lnum) { if (undo_off) return OK; @@ -259,8 +257,7 @@ linenr_T lnum; * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_inssub(lnum) -linenr_T lnum; +int u_inssub(linenr_T lnum) { if (undo_off) return OK; @@ -275,9 +272,7 @@ linenr_T lnum; * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_savedel(lnum, nlines) -linenr_T lnum; -long nlines; +int u_savedel(linenr_T lnum, long nlines) { if (undo_off) return OK; @@ -290,7 +285,7 @@ long nlines; * Return TRUE when undo is allowed. Otherwise give an error message and * return FALSE. */ -int undo_allowed() { +int undo_allowed(void) { /* Don't allow changes when 'modifiable' is off. */ if (!curbuf->b_p_ma) { EMSG(_(e_modifiable)); @@ -318,7 +313,7 @@ int undo_allowed() { /* * Get the undolevle value for the current buffer. */ -static long get_undolevel() { +static long get_undolevel(void) { if (curbuf->b_p_ul == NO_LOCAL_UNDOLEVEL) return p_ul; return curbuf->b_p_ul; @@ -333,10 +328,7 @@ static long get_undolevel() { * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_savecommon(top, bot, newbot, reload) -linenr_T top, bot; -linenr_T newbot; -int reload; +int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) { linenr_T lnum; long i; @@ -647,8 +639,7 @@ static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); /* * Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE]. */ -void u_compute_hash(hash) -char_u *hash; +void u_compute_hash(char_u *hash) { context_sha256_T ctx; linenr_T lnum; @@ -669,9 +660,7 @@ char_u *hash; * When "reading" is FALSE use the first name where the directory exists. * Returns NULL when there is no place to write or no file to read. */ -char_u * u_get_undo_file_name(buf_ffname, reading) -char_u *buf_ffname; -int reading; +char_u *u_get_undo_file_name(char_u *buf_ffname, int reading) { char_u *dirp; char_u dir_name[IOSIZE + 1]; @@ -738,15 +727,12 @@ int reading; return undo_file_name; } -static void corruption_error(mesg, file_name) -char *mesg; -char_u *file_name; +static void corruption_error(char *mesg, char_u *file_name) { EMSG3(_("E825: Corrupted undo file (%s): %s"), mesg, file_name); } -static void u_free_uhp(uhp) -u_header_T *uhp; +static void u_free_uhp(u_header_T *uhp) { u_entry_T *nuep; u_entry_T *uep; @@ -764,11 +750,7 @@ u_header_T *uhp; * Like fwrite() but crypt the bytes when 'key' is set. * Returns 1 if successful. */ -static size_t fwrite_crypt(buf, ptr, len, fp) -buf_T *buf UNUSED; -char_u *ptr; -size_t len; -FILE *fp; +static size_t fwrite_crypt(buf_T *buf, char_u *ptr, size_t len, FILE *fp) { char_u *copy; char_u small_buf[100]; @@ -794,10 +776,7 @@ FILE *fp; * Read a string of length "len" from "fd". * When 'key' is set decrypt the bytes. */ -static char_u * read_string_decrypt(buf, fd, len) -buf_T *buf UNUSED; -FILE *fd; -int len; +static char_u *read_string_decrypt(buf_T *buf, FILE *fd, int len) { char_u *ptr; @@ -807,10 +786,7 @@ int len; return ptr; } -static int serialize_header(fp, buf, hash) -FILE *fp; -buf_T *buf; -char_u *hash; +static int serialize_header(FILE *fp, buf_T *buf, char_u *hash) { int len; @@ -872,10 +848,7 @@ char_u *hash; return OK; } -static int serialize_uhp(fp, buf, uhp) -FILE *fp; -buf_T *buf; -u_header_T *uhp; +static int serialize_uhp(FILE *fp, buf_T *buf, u_header_T *uhp) { int i; u_entry_T *uep; @@ -914,9 +887,7 @@ u_header_T *uhp; return OK; } -static u_header_T * unserialize_uhp(fp, file_name) -FILE *fp; -char_u *file_name; +static u_header_T *unserialize_uhp(FILE *fp, char_u *file_name) { u_header_T *uhp; int i; @@ -995,10 +966,7 @@ char_u *file_name; /* * Serialize "uep" to "fp". */ -static int serialize_uep(fp, buf, uep) -FILE *fp; -buf_T *buf; -u_entry_T *uep; +static int serialize_uep(FILE *fp, buf_T *buf, u_entry_T *uep) { int i; size_t len; @@ -1017,10 +985,7 @@ u_entry_T *uep; return OK; } -static u_entry_T * unserialize_uep(fp, error, file_name) -FILE *fp; -int *error; -char_u *file_name; +static u_entry_T *unserialize_uep(FILE *fp, int *error, char_u *file_name) { int i; u_entry_T *uep; @@ -1070,9 +1035,7 @@ char_u *file_name; /* * Serialize "pos" to "fp". */ -static void serialize_pos(pos, fp) -pos_T pos; -FILE *fp; +static void serialize_pos(pos_T pos, FILE *fp) { put_bytes(fp, (long_u)pos.lnum, 4); put_bytes(fp, (long_u)pos.col, 4); @@ -1082,9 +1045,7 @@ FILE *fp; /* * Unserialize the pos_T at the current position in fp. */ -static void unserialize_pos(pos, fp) -pos_T *pos; -FILE *fp; +static void unserialize_pos(pos_T *pos, FILE *fp) { pos->lnum = get4c(fp); if (pos->lnum < 0) @@ -1100,9 +1061,7 @@ FILE *fp; /* * Serialize "info" to "fp". */ -static void serialize_visualinfo(info, fp) -visualinfo_T *info; -FILE *fp; +static void serialize_visualinfo(visualinfo_T *info, FILE *fp) { serialize_pos(info->vi_start, fp); serialize_pos(info->vi_end, fp); @@ -1113,9 +1072,7 @@ FILE *fp; /* * Unserialize the visualinfo_T at the current position in fp. */ -static void unserialize_visualinfo(info, fp) -visualinfo_T *info; -FILE *fp; +static void unserialize_visualinfo(visualinfo_T *info, FILE *fp) { unserialize_pos(&info->vi_start, fp); unserialize_pos(&info->vi_end, fp); @@ -1127,9 +1084,7 @@ FILE *fp; * Write the pointer to an undo header. Instead of writing the pointer itself * we use the sequence number of the header. This is converted back to * pointers when reading. */ -static void put_header_ptr(fp, uhp) -FILE *fp; -u_header_T *uhp; +static void put_header_ptr(FILE *fp, u_header_T *uhp) { put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4); } @@ -1143,11 +1098,7 @@ u_header_T *uhp; * "forceit" is TRUE for ":wundo!", FALSE otherwise. * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. */ -void u_write_undo(name, forceit, buf, hash) -char_u *name; -int forceit; -buf_T *buf; -char_u *hash; +void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash) { u_header_T *uhp; char_u *file_name; @@ -1378,10 +1329,7 @@ theend: * Otherwise use curbuf->b_ffname to generate the undo file name. * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. */ -void u_read_undo(name, hash, orig_name) -char_u *name; -char_u *hash; -char_u *orig_name; +void u_read_undo(char_u *name, char_u *hash, char_u *orig_name) { char_u *file_name; FILE *fp; @@ -1684,8 +1632,7 @@ theend: * If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible). * If 'cpoptions' does not contain 'u': Always undo. */ -void u_undo(count) -int count; +void u_undo(int count) { /* * If we get an undo command while executing a macro, we behave like the @@ -1708,8 +1655,7 @@ int count; * If 'cpoptions' contains 'u': Repeat the previous undo or redo. * If 'cpoptions' does not contain 'u': Always redo. */ -void u_redo(count) -int count; +void u_redo(int count) { if (vim_strchr(p_cpo, CPO_UNDO) == NULL) undo_undoes = FALSE; @@ -1719,8 +1665,7 @@ int count; /* * Undo or redo, depending on 'undo_undoes', 'count' times. */ -static void u_doit(startcount) -int startcount; +static void u_doit(int startcount) { int count = startcount; @@ -1788,11 +1733,7 @@ int startcount; * When "absolute" is TRUE use "step" as the sequence number to jump to. * "sec" must be FALSE then. */ -void undo_time(step, sec, file, absolute) -long step; -int sec; -int file; -int absolute; +void undo_time(long step, int sec, int file, int absolute) { long target; long closest; @@ -2099,8 +2040,7 @@ int absolute; * * When "undo" is TRUE we go up in the tree, when FALSE we go down. */ -static void u_undoredo(undo) -int undo; +static void u_undoredo(int undo) { char_u **newarray = NULL; linenr_T oldsize; @@ -2344,9 +2284,11 @@ int undo; * Otherwise, report the number of changes (this may be incorrect * in some cases, but it's better than nothing). */ -static void u_undo_end(did_undo, absolute) -int did_undo; /* just did an undo */ -int absolute; /* used ":undo N" */ +static void +u_undo_end ( + int did_undo, /* just did an undo */ + int absolute /* used ":undo N" */ +) { char *msgstr; u_header_T *uhp; @@ -2417,8 +2359,10 @@ int absolute; /* used ":undo N" */ /* * u_sync: stop adding to the current entry list */ -void u_sync(force) -int force; /* Also sync when no_u_sync is set. */ +void +u_sync ( + int force /* Also sync when no_u_sync is set. */ +) { /* Skip it when already synced or syncing is disabled. */ if (curbuf->b_u_synced || (!force && no_u_sync > 0)) @@ -2434,8 +2378,7 @@ int force; /* Also sync when no_u_sync is set. */ /* * ":undolist": List the leafs of the undo tree */ -void ex_undolist(eap) -exarg_T *eap UNUSED; +void ex_undolist(exarg_T *eap) { garray_T ga; u_header_T *uhp; @@ -2528,10 +2471,7 @@ exarg_T *eap UNUSED; /* * Put the timestamp of an undo header in "buf[buflen]" in a nice format. */ -static void u_add_time(buf, buflen, tt) -char_u *buf; -size_t buflen; -time_t tt; +static void u_add_time(char_u *buf, size_t buflen, time_t tt) { #ifdef HAVE_STRFTIME struct tm *curtime; @@ -2553,8 +2493,7 @@ time_t tt; /* * ":undojoin": continue adding to the last entry list */ -void ex_undojoin(eap) -exarg_T *eap UNUSED; +void ex_undojoin(exarg_T *eap) { if (curbuf->b_u_newhead == NULL) return; /* nothing changed before */ @@ -2577,8 +2516,7 @@ exarg_T *eap UNUSED; * Called after writing or reloading the file and setting b_changed to FALSE. * Now an undo means that the buffer is modified. */ -void u_unchanged(buf) -buf_T *buf; +void u_unchanged(buf_T *buf) { u_unch_branch(buf->b_u_oldhead); buf->b_did_warn = FALSE; @@ -2588,7 +2526,7 @@ buf_T *buf; * After reloading a buffer which was saved for 'undoreload': Find the first * line that was changed and set the cursor there. */ -void u_find_first_changed() { +void u_find_first_changed(void) { u_header_T *uhp = curbuf->b_u_newhead; u_entry_T *uep; linenr_T lnum; @@ -2620,8 +2558,7 @@ void u_find_first_changed() { * Increase the write count, store it in the last undo header, what would be * used for "u". */ -void u_update_save_nr(buf) -buf_T *buf; +void u_update_save_nr(buf_T *buf) { u_header_T *uhp; @@ -2636,8 +2573,7 @@ buf_T *buf; uhp->uh_save_nr = buf->b_u_save_nr_last; } -static void u_unch_branch(uhp) -u_header_T *uhp; +static void u_unch_branch(u_header_T *uhp) { u_header_T *uh; @@ -2652,7 +2588,7 @@ u_header_T *uhp; * Get pointer to last added entry. * If it's not valid, give an error message and return NULL. */ -static u_entry_T * u_get_headentry() { +static u_entry_T *u_get_headentry(void) { if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) { EMSG(_("E439: undo list corrupt")); return NULL; @@ -2664,7 +2600,7 @@ static u_entry_T * u_get_headentry() { * u_getbot(): compute the line number of the previous u_save * It is called only when b_u_synced is FALSE. */ -static void u_getbot() { +static void u_getbot(void) { u_entry_T *uep; linenr_T extra; @@ -2698,10 +2634,12 @@ static void u_getbot() { /* * Free one header "uhp" and its entry list and adjust the pointers. */ -static void u_freeheader(buf, uhp, uhpp) -buf_T *buf; -u_header_T *uhp; -u_header_T **uhpp; /* if not NULL reset when freeing this header */ +static void +u_freeheader ( + buf_T *buf, + u_header_T *uhp, + u_header_T **uhpp /* if not NULL reset when freeing this header */ +) { u_header_T *uhap; @@ -2732,10 +2670,12 @@ u_header_T **uhpp; /* if not NULL reset when freeing this header */ /* * Free an alternate branch and any following alternate branches. */ -static void u_freebranch(buf, uhp, uhpp) -buf_T *buf; -u_header_T *uhp; -u_header_T **uhpp; /* if not NULL reset when freeing this header */ +static void +u_freebranch ( + buf_T *buf, + u_header_T *uhp, + u_header_T **uhpp /* if not NULL reset when freeing this header */ +) { u_header_T *tofree, *next; @@ -2764,10 +2704,12 @@ u_header_T **uhpp; /* if not NULL reset when freeing this header */ * Free all the undo entries for one header and the header itself. * This means that "uhp" is invalid when returning. */ -static void u_freeentries(buf, uhp, uhpp) -buf_T *buf; -u_header_T *uhp; -u_header_T **uhpp; /* if not NULL reset when freeing this header */ +static void +u_freeentries ( + buf_T *buf, + u_header_T *uhp, + u_header_T **uhpp /* if not NULL reset when freeing this header */ +) { u_entry_T *uep, *nuep; @@ -2794,9 +2736,7 @@ u_header_T **uhpp; /* if not NULL reset when freeing this header */ /* * free entry 'uep' and 'n' lines in uep->ue_array[] */ -static void u_freeentry(uep, n) -u_entry_T *uep; -long n; +static void u_freeentry(u_entry_T *uep, long n) { while (n > 0) vim_free(uep->ue_array[--n]); @@ -2810,8 +2750,7 @@ long n; /* * invalidate the undo buffer; called when storage has already been released */ -void u_clearall(buf) -buf_T *buf; +void u_clearall(buf_T *buf) { buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL; buf->b_u_synced = TRUE; @@ -2823,8 +2762,7 @@ buf_T *buf; /* * save the line "lnum" for the "U" command */ -void u_saveline(lnum) -linenr_T lnum; +void u_saveline(linenr_T lnum) { if (lnum == curbuf->b_u_line_lnum) /* line is already saved */ return; @@ -2844,7 +2782,7 @@ linenr_T lnum; * clear the line saved for the "U" command * (this is used externally for crossing a line while in insert mode) */ -void u_clearline() { +void u_clearline(void) { if (curbuf->b_u_line_ptr != NULL) { vim_free(curbuf->b_u_line_ptr); curbuf->b_u_line_ptr = NULL; @@ -2858,7 +2796,7 @@ void u_clearline() { * We also allow the cursor to be in another line. * Careful: may trigger autocommands that reload the buffer. */ -void u_undoline() { +void u_undoline(void) { colnr_T t; char_u *oldp; @@ -2896,8 +2834,7 @@ void u_undoline() { /* * Free all allocated memory blocks for the buffer 'buf'. */ -void u_blockfree(buf) -buf_T *buf; +void u_blockfree(buf_T *buf) { while (buf->b_u_oldhead != NULL) u_freeheader(buf, buf->b_u_oldhead, NULL); @@ -2908,8 +2845,7 @@ buf_T *buf; * u_save_line(): allocate memory and copy line 'lnum' into it. * Returns NULL when out of memory. */ -static char_u * u_save_line(lnum) -linenr_T lnum; +static char_u *u_save_line(linenr_T lnum) { return vim_strsave(ml_get(lnum)); } @@ -2919,15 +2855,14 @@ linenr_T lnum; * check the first character, because it can only be "dos", "unix" or "mac"). * "nofile" and "scratch" type buffers are considered to always be unchanged. */ -int bufIsChanged(buf) -buf_T *buf; +int bufIsChanged(buf_T *buf) { return !bt_dontwrite(buf) && (buf->b_changed || file_ff_differs(buf, TRUE)); } -int curbufIsChanged() { +int curbufIsChanged(void) { return !bt_dontwrite(curbuf) && (curbuf->b_changed || file_ff_differs(curbuf, TRUE)); @@ -2937,9 +2872,7 @@ int curbufIsChanged() { * For undotree(): Append the list of undo blocks at "first_uhp" to "list". * Recursive. */ -void u_eval_tree(first_uhp, list) -u_header_T *first_uhp; -list_T *list; +void u_eval_tree(u_header_T *first_uhp, list_T *list) { u_header_T *uhp = first_uhp; dict_T *dict; diff --git a/src/version.c b/src/version.c index 62a7aa8bc8..a928e840bd 100644 --- a/src/version.c +++ b/src/version.c @@ -568,7 +568,7 @@ static char *(extra_patches[]) = NULL }; -int highest_patch() { +int highest_patch(void) { int i; int h = 0; @@ -581,8 +581,7 @@ int highest_patch() { /* * Return TRUE if patch "n" has been included. */ -int has_patch(n) -int n; +int has_patch(int n) { int i; @@ -592,8 +591,7 @@ int n; return FALSE; } -void ex_version(eap) -exarg_T *eap; +void ex_version(exarg_T *eap) { /* * Ignore a ":version 9.99" command. @@ -607,7 +605,7 @@ exarg_T *eap; /* * List all features aligned in columns, dictionary style. */ -static void list_features() { +static void list_features(void) { int i; int ncol; int nrow; @@ -662,7 +660,7 @@ static void list_features() { } } -void list_version() { +void list_version(void) { int i; int first; char *s = ""; @@ -792,8 +790,7 @@ void list_version() { * Output a string for the version message. If it's going to wrap, output a * newline, unless the message is too long to fit on the screen anyway. */ -static void version_msg(s) -char *s; +static void version_msg(char *s) { int len = (int)STRLEN(s); @@ -810,7 +807,7 @@ static void do_intro_line __ARGS((int row, char_u *mesg, int add_version, /* * Show the intro message when not editing a file. */ -void maybe_intro_message() { +void maybe_intro_message(void) { if (bufempty() && curbuf->b_fname == NULL && firstwin->w_next == NULL @@ -823,8 +820,10 @@ void maybe_intro_message() { * Only used when starting Vim on an empty file, without a file name. * Or with the ":intro" command (for Sven :-). */ -void intro_message(colon) -int colon; /* TRUE for ":intro" */ +void +intro_message ( + int colon /* TRUE for ":intro" */ +) { int i; int row; @@ -904,11 +903,7 @@ int colon; /* TRUE for ":intro" */ msg_row = row; } -static void do_intro_line(row, mesg, add_version, attr) -int row; -char_u *mesg; -int add_version; -int attr; +static void do_intro_line(int row, char_u *mesg, int add_version, int attr) { char_u vers[20]; int col; @@ -969,8 +964,7 @@ int attr; /* * ":intro": clear screen, display intro screen and wait for return. */ -void ex_intro(eap) -exarg_T *eap UNUSED; +void ex_intro(exarg_T *eap) { screenclear(); intro_message(TRUE); diff --git a/src/vim.h b/src/vim.h index 53706da049..fab3d70568 100644 --- a/src/vim.h +++ b/src/vim.h @@ -72,14 +72,6 @@ Error: configure did not run properly.Check auto/config.log. # endif #endif -/* Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter - * can be used to check for mistakes. */ -#ifdef HAVE_ATTRIBUTE_UNUSED -# define UNUSED __attribute__((unused)) -#else -# define UNUSED -#endif - # ifdef HAVE_LOCALE_H # include # endif diff --git a/src/window.c b/src/window.c index 336f9dbcca..29c82e4086 100644 --- a/src/window.c +++ b/src/window.c @@ -86,10 +86,12 @@ static char *m_onlyone = N_("Already only one window"); /* * all CTRL-W window commands are handled here, called from normal_cmd(). */ -void do_window(nchar, Prenum, xchar) -int nchar; -long Prenum; -int xchar; /* extra char from ":wincmd gx" or NUL */ +void +do_window ( + int nchar, + long Prenum, + int xchar /* extra char from ":wincmd gx" or NUL */ +) { long Prenum1; win_T *wp; @@ -510,9 +512,7 @@ wingotofile: * * return FAIL for failure, OK otherwise */ -int win_split(size, flags) -int size; -int flags; +int win_split(int size, int flags) { /* When the ":tab" modifier was used open a new tab page instead. */ if (may_open_tabpage() == OK) @@ -541,11 +541,7 @@ int flags; * top/left/right/bottom. * return FAIL for failure, OK otherwise */ -int win_split_ins(size, flags, new_wp, dir) -int size; -int flags; -win_T *new_wp; -int dir; +int win_split_ins(int size, int flags, win_T *new_wp, int dir) { win_T *wp = new_wp; win_T *oldwin; @@ -936,10 +932,7 @@ int dir; * WSP_NEWLOC may be specified in flags to prevent the location list from * being copied. */ -static void win_init(newp, oldp, flags) -win_T *newp; -win_T *oldp; -int flags UNUSED; +static void win_init(win_T *newp, win_T *oldp, int flags) { int i; @@ -989,9 +982,7 @@ int flags UNUSED; * Initialize window "newp" from window"old". * Only the essential things are copied. */ -static void win_init_some(newp, oldp) -win_T *newp; -win_T *oldp; +static void win_init_some(win_T *newp, win_T *oldp) { /* Use the same argument list. */ newp->w_alist = oldp->w_alist; @@ -1006,8 +997,7 @@ win_T *oldp; /* * Check if "win" is a pointer to an existing window. */ -int win_valid(win) -win_T *win; +int win_valid(win_T *win) { win_T *wp; @@ -1022,7 +1012,7 @@ win_T *win; /* * Return the number of windows. */ -int win_count() { +int win_count(void) { win_T *wp; int count = 0; @@ -1037,9 +1027,11 @@ int win_count() { * Must be called when there is just one window, filling the whole screen * (excluding the command line). */ -int make_windows(count, vertical) -int count; -int vertical UNUSED; /* split windows vertically if TRUE */ +int +make_windows ( + int count, + int vertical /* split windows vertically if TRUE */ +) { int maxcount; int todo; @@ -1094,8 +1086,7 @@ int vertical UNUSED; /* split windows vertically if TRUE */ /* * Exchange current and next window */ -static void win_exchange(Prenum) -long Prenum; +static void win_exchange(long Prenum) { frame_T *frp; frame_T *frp2; @@ -1185,9 +1176,7 @@ long Prenum; * rotate windows: if upwards TRUE the second window becomes the first one * if upwards FALSE the first window becomes the second one */ -static void win_rotate(upwards, count) -int upwards; -int count; +static void win_rotate(int upwards, int count) { win_T *wp1; win_T *wp2; @@ -1260,9 +1249,7 @@ int count; /* * Move the current window to the very top/bottom/left/right of the screen. */ -static void win_totop(size, flags) -int size; -int flags; +static void win_totop(int size, int flags) { int dir; int height = curwin->w_height; @@ -1292,8 +1279,7 @@ int flags; * Move window "win1" to below/right of "win2" and make "win1" the current * window. Only works within the same frame! */ -void win_move_after(win1, win2) -win_T *win1, *win2; +void win_move_after(win_T *win1, win_T *win2) { int height; @@ -1346,11 +1332,13 @@ win_T *win1, *win2; * 'next_curwin' will soon be the current window, make sure it has enough * rows. */ -void win_equal(next_curwin, current, dir) -win_T *next_curwin; /* pointer to current window to be or NULL */ -int current; /* do only frame with current window */ -int dir; /* 'v' for vertically, 'h' for horizontally, +void +win_equal ( + win_T *next_curwin, /* pointer to current window to be or NULL */ + int current, /* do only frame with current window */ + int dir /* 'v' for vertically, 'h' for horizontally, 'b' for both, 0 for using p_ead */ +) { if (dir == 0) dir = *p_ead; @@ -1365,16 +1353,17 @@ int dir; /* 'v' for vertically, 'h' for horizontally, * The window "next_curwin" (if not NULL) should at least get the size from * 'winheight' and 'winwidth' if possible. */ -static void win_equal_rec(next_curwin, current, topfr, dir, col, row, width, - height) -win_T *next_curwin; /* pointer to current window to be or NULL */ -int current; /* do only frame with current window */ -frame_T *topfr; /* frame to set size off */ -int dir; /* 'v', 'h' or 'b', see win_equal() */ -int col; /* horizontal position for frame */ -int row; /* vertical position for frame */ -int width; /* new width of frame */ -int height; /* new height of frame */ +static void +win_equal_rec ( + win_T *next_curwin, /* pointer to current window to be or NULL */ + int current, /* do only frame with current window */ + frame_T *topfr, /* frame to set size off */ + int dir, /* 'v', 'h' or 'b', see win_equal() */ + int col, /* horizontal position for frame */ + int row, /* vertical position for frame */ + int width, /* new width of frame */ + int height /* new height of frame */ +) { int n, m; int extra_sep = 0; @@ -1646,9 +1635,11 @@ int height; /* new height of frame */ /* * close all windows for buffer 'buf' */ -void close_windows(buf, keep_curwin) -buf_T *buf; -int keep_curwin; /* don't close "curwin" */ +void +close_windows ( + buf_T *buf, + int keep_curwin /* don't close "curwin" */ +) { win_T *wp; tabpage_T *tp, *nexttp; @@ -1697,7 +1688,7 @@ int keep_curwin; /* don't close "curwin" */ * "aucmd_win"). * Returns FALSE if there is a window, possibly in another tab page. */ -static int last_window() { +static int last_window(void) { return one_window() && first_tabpage->tp_next == NULL; } @@ -1705,7 +1696,7 @@ static int last_window() { * Return TRUE if there is only one window other than "aucmd_win" in the * current tab page. */ -int one_window() { +int one_window(void) { win_T *wp; int seen_one = FALSE; @@ -1724,10 +1715,7 @@ int one_window() { * Close the possibly last window in a tab page. * Returns TRUE when the window was closed already. */ -static int close_last_window_tabpage(win, free_buf, prev_curtab) -win_T *win; -int free_buf; -tabpage_T *prev_curtab; +static int close_last_window_tabpage(win_T *win, int free_buf, tabpage_T *prev_curtab) { if (firstwin == lastwin) { buf_T *old_curbuf = curbuf; @@ -1770,9 +1758,7 @@ tabpage_T *prev_curtab; * Called by :quit, :close, :xit, :wq and findtag(). * Returns FAIL when the window was not closed. */ -int win_close(win, free_buf) -win_T *win; -int free_buf; +int win_close(win_T *win, int free_buf) { win_T *wp; int other_buffer = FALSE; @@ -1941,10 +1927,7 @@ int free_buf; * Caller must check if buffer is hidden and whether the tabline needs to be * updated. */ -void win_close_othertab(win, free_buf, tp) -win_T *win; -int free_buf; -tabpage_T *tp; +void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) { win_T *wp; int dir; @@ -1998,10 +1981,12 @@ tabpage_T *tp; * Free the memory used for a window. * Returns a pointer to the window that got the freed up space. */ -static win_T * win_free_mem(win, dirp, tp) -win_T *win; -int *dirp; /* set to 'v' or 'h' for direction if 'ea' */ -tabpage_T *tp; /* tab page "win" is in, NULL for current */ +static win_T * +win_free_mem ( + win_T *win, + int *dirp, /* set to 'v' or 'h' for direction if 'ea' */ + tabpage_T *tp /* tab page "win" is in, NULL for current */ +) { frame_T *frp; win_T *wp; @@ -2021,7 +2006,7 @@ tabpage_T *tp; /* tab page "win" is in, NULL for current */ } #if defined(EXITFREE) || defined(PROTO) -void win_free_all() { +void win_free_all(void) { int dummy; while (first_tabpage->tp_next != NULL) @@ -2042,10 +2027,12 @@ void win_free_all() { * Remove a window and its frame from the tree of frames. * Returns a pointer to the window that got the freed up space. */ -win_T * winframe_remove(win, dirp, tp) -win_T *win; -int *dirp UNUSED; /* set to 'v' or 'h' for direction if 'ea' */ -tabpage_T *tp; /* tab page "win" is in, NULL for current */ +win_T * +winframe_remove ( + win_T *win, + int *dirp, /* set to 'v' or 'h' for direction if 'ea' */ + tabpage_T *tp /* tab page "win" is in, NULL for current */ +) { frame_T *frp, *frp2, *frp3; frame_T *frp_close = win->w_frame; @@ -2181,9 +2168,11 @@ tabpage_T *tp; /* tab page "win" is in, NULL for current */ * This makes opening a window and closing it immediately keep the same window * layout. */ -static frame_T * win_altframe(win, tp) -win_T *win; -tabpage_T *tp; /* tab page "win" is in, NULL for current */ +static frame_T * +win_altframe ( + win_T *win, + tabpage_T *tp /* tab page "win" is in, NULL for current */ +) { frame_T *frp; int b; @@ -2205,7 +2194,7 @@ tabpage_T *tp; /* tab page "win" is in, NULL for current */ /* * Return the tabpage that will be used if the current one is closed. */ -static tabpage_T * alt_tabpage() { +static tabpage_T *alt_tabpage(void) { tabpage_T *tp; /* Use the next tab page if possible. */ @@ -2221,8 +2210,7 @@ static tabpage_T * alt_tabpage() { /* * Find the left-upper window in frame "frp". */ -static win_T * frame2win(frp) -frame_T *frp; +static win_T *frame2win(frame_T *frp) { while (frp->fr_win == NULL) frp = frp->fr_child; @@ -2232,9 +2220,7 @@ frame_T *frp; /* * Return TRUE if frame "frp" contains window "wp". */ -static int frame_has_win(frp, wp) -frame_T *frp; -win_T *wp; +static int frame_has_win(frame_T *frp, win_T *wp) { frame_T *p; @@ -2251,12 +2237,14 @@ win_T *wp; * Set a new height for a frame. Recursively sets the height for contained * frames and windows. Caller must take care of positions. */ -static void frame_new_height(topfrp, height, topfirst, wfh) -frame_T *topfrp; -int height; -int topfirst; /* resize topmost contained frame first */ -int wfh; /* obey 'winfixheight' when there is a choice; +static void +frame_new_height ( + frame_T *topfrp, + int height, + int topfirst, /* resize topmost contained frame first */ + int wfh /* obey 'winfixheight' when there is a choice; may cause the height not to be set */ +) { frame_T *frp; int extra_lines; @@ -2338,8 +2326,7 @@ int wfh; /* obey 'winfixheight' when there is a choice; * Return TRUE if height of frame "frp" should not be changed because of * the 'winfixheight' option. */ -static int frame_fixed_height(frp) -frame_T *frp; +static int frame_fixed_height(frame_T *frp) { /* frame with one window: fixed height if 'winfixheight' set. */ if (frp->fr_win != NULL) @@ -2366,8 +2353,7 @@ frame_T *frp; * Return TRUE if width of frame "frp" should not be changed because of * the 'winfixwidth' option. */ -static int frame_fixed_width(frp) -frame_T *frp; +static int frame_fixed_width(frame_T *frp) { /* frame with one window: fixed width if 'winfixwidth' set. */ if (frp->fr_win != NULL) @@ -2394,8 +2380,7 @@ frame_T *frp; * Add a status line to windows at the bottom of "frp". * Note: Does not check if there is room! */ -static void frame_add_statusline(frp) -frame_T *frp; +static void frame_add_statusline(frame_T *frp) { win_T *wp; @@ -2422,12 +2407,14 @@ frame_T *frp; * Set width of a frame. Handles recursively going through contained frames. * May remove separator line for windows at the right side (for win_close()). */ -static void frame_new_width(topfrp, width, leftfirst, wfw) -frame_T *topfrp; -int width; -int leftfirst; /* resize leftmost contained frame first */ -int wfw; /* obey 'winfixwidth' when there is a choice; +static void +frame_new_width ( + frame_T *topfrp, + int width, + int leftfirst, /* resize leftmost contained frame first */ + int wfw /* obey 'winfixwidth' when there is a choice; may cause the width not to be set */ +) { frame_T *frp; int extra_cols; @@ -2516,8 +2503,7 @@ int wfw; /* obey 'winfixwidth' when there is a choice; * Add the vertical separator to windows at the right side of "frp". * Note: Does not check if there is room! */ -static void frame_add_vsep(frp) -frame_T *frp; +static void frame_add_vsep(frame_T *frp) { win_T *wp; @@ -2544,8 +2530,7 @@ frame_T *frp; /* * Set frame width from the window it contains. */ -static void frame_fix_width(wp) -win_T *wp; +static void frame_fix_width(win_T *wp) { wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width; } @@ -2553,8 +2538,7 @@ win_T *wp; /* * Set frame height from the window it contains. */ -static void frame_fix_height(wp) -win_T *wp; +static void frame_fix_height(win_T *wp) { wp->w_frame->fr_height = wp->w_height + wp->w_status_height; } @@ -2566,9 +2550,7 @@ win_T *wp; * When "next_curwin" is NOWIN, don't use at least one line for the current * window. */ -static int frame_minheight(topfrp, next_curwin) -frame_T *topfrp; -win_T *next_curwin; +static int frame_minheight(frame_T *topfrp, win_T *next_curwin) { frame_T *frp; int m; @@ -2608,9 +2590,11 @@ win_T *next_curwin; * When "next_curwin" is NOWIN, don't use at least one column for the current * window. */ -static int frame_minwidth(topfrp, next_curwin) -frame_T *topfrp; -win_T *next_curwin; /* use p_wh and p_wiw for next_curwin */ +static int +frame_minwidth ( + frame_T *topfrp, + win_T *next_curwin /* use p_wh and p_wiw for next_curwin */ +) { frame_T *frp; int m, n; @@ -2651,9 +2635,11 @@ win_T *next_curwin; /* use p_wh and p_wiw for next_curwin */ * * Used by ":bdel" and ":only". */ -void close_others(message, forceit) -int message; -int forceit; /* always hide all other windows */ +void +close_others ( + int message, + int forceit /* always hide all other windows */ +) { win_T *wp; win_T *nextwp; @@ -2702,12 +2688,11 @@ int forceit; /* always hide all other windows */ * Init the current window "curwin". * Called when a new file is being edited. */ -void curwin_init() { +void curwin_init(void) { win_init_empty(curwin); } -void win_init_empty(wp) -win_T *wp; +void win_init_empty(win_T *wp) { redraw_win_later(wp, NOT_VALID); wp->w_lines_valid = 0; @@ -2733,7 +2718,7 @@ win_T *wp; * Called from main(). * Return FAIL when something goes wrong (out of memory). */ -int win_alloc_first() { +int win_alloc_first(void) { if (win_alloc_firstwin(NULL) == FAIL) return FAIL; @@ -2750,7 +2735,7 @@ int win_alloc_first() { * Init "aucmd_win". This can only be done after the first * window is fully initialized, thus it can't be in win_alloc_first(). */ -void win_alloc_aucmd_win() { +void win_alloc_aucmd_win(void) { aucmd_win = win_alloc(NULL, TRUE); if (aucmd_win != NULL) { win_init_some(aucmd_win, curwin); @@ -2766,8 +2751,7 @@ void win_alloc_aucmd_win() { * FEAT_WINDOWS). * Return FAIL when something goes wrong (out of memory). */ -static int win_alloc_firstwin(oldwin) -win_T *oldwin; +static int win_alloc_firstwin(win_T *oldwin) { curwin = win_alloc(NULL, FALSE); if (oldwin == NULL) { @@ -2816,7 +2800,7 @@ static void new_frame(win_T *wp) { /* * Initialize the window and frame size to the maximum. */ -void win_init_size() { +void win_init_size(void) { firstwin->w_height = ROWS_AVAIL; topframe->fr_height = ROWS_AVAIL; firstwin->w_width = Columns; @@ -2827,7 +2811,7 @@ void win_init_size() { * Allocate a new tabpage_T and init the values. * Returns NULL when out of memory. */ -static tabpage_T * alloc_tabpage() { +static tabpage_T *alloc_tabpage(void) { tabpage_T *tp; @@ -2849,8 +2833,7 @@ static tabpage_T * alloc_tabpage() { return tp; } -void free_tabpage(tp) -tabpage_T *tp; +void free_tabpage(tabpage_T *tp) { int idx; @@ -2873,8 +2856,7 @@ tabpage_T *tp; * Otherwise put it just before tab page "after". * Return FAIL or OK. */ -int win_new_tabpage(after) -int after; +int win_new_tabpage(int after) { tabpage_T *tp = curtab; tabpage_T *newtp; @@ -2933,7 +2915,7 @@ int after; * like with ":split". * Returns OK if a new tab page was created, FAIL otherwise. */ -int may_open_tabpage() { +int may_open_tabpage(void) { int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab; if (n != 0) { @@ -2948,8 +2930,7 @@ int may_open_tabpage() { * Create up to "maxcount" tabpages with empty windows. * Returns the number of resulting tab pages. */ -int make_tabpages(maxcount) -int maxcount; +int make_tabpages(int maxcount) { int count = maxcount; int todo; @@ -2977,8 +2958,7 @@ int maxcount; /* * Return TRUE when "tpc" points to a valid tab page. */ -int valid_tabpage(tpc) -tabpage_T *tpc; +int valid_tabpage(tabpage_T *tpc) { tabpage_T *tp; @@ -2991,8 +2971,7 @@ tabpage_T *tpc; /* * Find tab page "n" (first one is 1). Returns NULL when not found. */ -tabpage_T * find_tabpage(n) -int n; +tabpage_T *find_tabpage(int n) { tabpage_T *tp; int i = 1; @@ -3006,8 +2985,7 @@ int n; * Get index of tab page "tp". First one has index 1. * When not found returns number of tab pages plus one. */ -int tabpage_index(ftp) -tabpage_T *ftp; +int tabpage_index(tabpage_T *ftp) { int i = 1; tabpage_T *tp; @@ -3023,10 +3001,12 @@ tabpage_T *ftp; * FAIL. * Careful: When OK is returned need to get a new tab page very very soon! */ -static int leave_tabpage(new_curbuf, trigger_leave_autocmds) -buf_T *new_curbuf UNUSED; /* what is going to be the new curbuf, +static int +leave_tabpage ( + buf_T *new_curbuf, /* what is going to be the new curbuf, NULL if unknown */ -int trigger_leave_autocmds UNUSED; + int trigger_leave_autocmds +) { tabpage_T *tp = curtab; @@ -3061,12 +3041,7 @@ int trigger_leave_autocmds UNUSED; * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE. * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE. */ -static void enter_tabpage(tp, old_curbuf, trigger_enter_autocmds, - trigger_leave_autocmds) -tabpage_T *tp; -buf_T *old_curbuf UNUSED; -int trigger_enter_autocmds UNUSED; -int trigger_leave_autocmds UNUSED; +static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds) { int old_off = tp->tp_firstwin->w_winrow; win_T *next_prevwin = tp->tp_prevwin; @@ -3115,8 +3090,7 @@ int trigger_leave_autocmds UNUSED; * Go to tab page "n". For ":tab N" and "Ngt". * When "n" is 9999 go to the last tab page. */ -void goto_tabpage(n) -int n; +void goto_tabpage(int n) { tabpage_T *tp; tabpage_T *ttp; @@ -3177,10 +3151,7 @@ int n; * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE. * Note: doesn't update the GUI tab. */ -void goto_tabpage_tp(tp, trigger_enter_autocmds, trigger_leave_autocmds) -tabpage_T *tp; -int trigger_enter_autocmds; -int trigger_leave_autocmds; +void goto_tabpage_tp(tabpage_T *tp, int trigger_enter_autocmds, int trigger_leave_autocmds) { /* Don't repeat a message in another tab page. */ set_keep_msg(NULL, 0); @@ -3200,9 +3171,7 @@ int trigger_leave_autocmds; * Enter window "wp" in tab page "tp". * Also updates the GUI tab. */ -void goto_tabpage_win(tp, wp) -tabpage_T *tp; -win_T *wp; +void goto_tabpage_win(tabpage_T *tp, win_T *wp) { goto_tabpage_tp(tp, TRUE, TRUE); if (curtab == tp && win_valid(wp)) { @@ -3213,8 +3182,7 @@ win_T *wp; /* * Move the current tab page to before tab page "nr". */ -void tabpage_move(nr) -int nr; +void tabpage_move(int nr) { int n = nr; tabpage_T *tp; @@ -3257,8 +3225,7 @@ int nr; * When jumping to another window on the same buffer, adjust its cursor * position to keep the same Visual area. */ -void win_goto(wp) -win_T *wp; +void win_goto(win_T *wp) { win_T *owp = curwin; @@ -3290,8 +3257,7 @@ win_T *wp; /* * Find the tabpage for window "win". */ -tabpage_T * win_find_tabpage(win) -win_T *win; +tabpage_T *win_find_tabpage(win_T *win) { win_T *wp; tabpage_T *tp; @@ -3308,9 +3274,11 @@ win_T *win; /* * Move to window above or below "count" times. */ -static void win_goto_ver(up, count) -int up; /* TRUE to go to win above */ -long count; +static void +win_goto_ver ( + int up, /* TRUE to go to win above */ + long count +) { frame_T *fr; frame_T *nfr; @@ -3365,9 +3333,11 @@ end: /* * Move to left or right window. */ -static void win_goto_hor(left, count) -int left; /* TRUE to go to left win */ -long count; +static void +win_goto_hor ( + int left, /* TRUE to go to left win */ + long count +) { frame_T *fr; frame_T *nfr; @@ -3422,9 +3392,7 @@ end: /* * Make window "wp" the current window. */ -void win_enter(wp, undo_sync) -win_T *wp; -int undo_sync; +void win_enter(win_T *wp, int undo_sync) { win_enter_ext(wp, undo_sync, FALSE, TRUE, TRUE); } @@ -3434,13 +3402,7 @@ int undo_sync; * Can be called with "curwin_invalid" TRUE, which means that curwin has just * been closed and isn't valid. */ -static void win_enter_ext(wp, undo_sync, curwin_invalid, trigger_enter_autocmds, - trigger_leave_autocmds) -win_T *wp; -int undo_sync; -int curwin_invalid; -int trigger_enter_autocmds UNUSED; -int trigger_leave_autocmds UNUSED; +static void win_enter_ext(win_T *wp, int undo_sync, int curwin_invalid, int trigger_enter_autocmds, int trigger_leave_autocmds) { int other_buffer = FALSE; @@ -3536,8 +3498,7 @@ int trigger_leave_autocmds UNUSED; * Jump to the first open window that contains buffer "buf", if one exists. * Returns a pointer to the window found, otherwise NULL. */ -win_T * buf_jump_open_win(buf) -buf_T *buf; +win_T *buf_jump_open_win(buf_T *buf) { win_T *wp; @@ -3554,8 +3515,7 @@ buf_T *buf; * if one exists. * Returns a pointer to the window found, otherwise NULL. */ -win_T * buf_jump_open_tab(buf) -buf_T *buf; +win_T *buf_jump_open_tab(buf_T *buf) { win_T *wp; tabpage_T *tp; @@ -3585,9 +3545,7 @@ buf_T *buf; * Allocate a window structure and link it in the window list when "hidden" is * FALSE. */ -static win_T * win_alloc(after, hidden) -win_T *after UNUSED; -int hidden UNUSED; +static win_T *win_alloc(win_T *after, int hidden) { win_T *new_wp; @@ -3646,9 +3604,11 @@ int hidden UNUSED; /* * Remove window 'wp' from the window list and free the structure. */ -static void win_free(wp, tp) -win_T *wp; -tabpage_T *tp; /* tab page "win" is in, NULL for current */ +static void +win_free ( + win_T *wp, + tabpage_T *tp /* tab page "win" is in, NULL for current */ +) { int i; buf_T *buf; @@ -3712,8 +3672,7 @@ tabpage_T *tp; /* tab page "win" is in, NULL for current */ /* * Append window "wp" in the window list after window "after". */ -void win_append(after, wp) -win_T *after, *wp; +void win_append(win_T *after, win_T *wp) { win_T *before; @@ -3737,9 +3696,11 @@ win_T *after, *wp; /* * Remove a window from the window list. */ -void win_remove(wp, tp) -win_T *wp; -tabpage_T *tp; /* tab page "win" is in, NULL for current */ +void +win_remove ( + win_T *wp, + tabpage_T *tp /* tab page "win" is in, NULL for current */ +) { if (wp->w_prev != NULL) wp->w_prev->w_next = wp->w_next; @@ -3758,8 +3719,7 @@ tabpage_T *tp; /* tab page "win" is in, NULL for current */ /* * Append frame "frp" in a frame list after frame "after". */ -static void frame_append(after, frp) -frame_T *after, *frp; +static void frame_append(frame_T *after, frame_T *frp) { frp->fr_next = after->fr_next; after->fr_next = frp; @@ -3771,8 +3731,7 @@ frame_T *after, *frp; /* * Insert frame "frp" in a frame list before frame "before". */ -static void frame_insert(before, frp) -frame_T *before, *frp; +static void frame_insert(frame_T *before, frame_T *frp) { frp->fr_next = before; frp->fr_prev = before->fr_prev; @@ -3786,8 +3745,7 @@ frame_T *before, *frp; /* * Remove a frame from a frame list. */ -static void frame_remove(frp) -frame_T *frp; +static void frame_remove(frame_T *frp) { if (frp->fr_prev != NULL) frp->fr_prev->fr_next = frp->fr_next; @@ -3802,8 +3760,7 @@ frame_T *frp; * Allocate w_lines[] for window "wp". * Return FAIL for failure, OK for success. */ -int win_alloc_lines(wp) -win_T *wp; +int win_alloc_lines(win_T *wp) { wp->w_lines_valid = 0; wp->w_lines = (wline_T *)alloc_clear((unsigned)(Rows * sizeof(wline_T))); @@ -3815,8 +3772,7 @@ win_T *wp; /* * free lsize arrays for a window */ -void win_free_lsize(wp) -win_T *wp; +void win_free_lsize(win_T *wp) { vim_free(wp->w_lines); wp->w_lines = NULL; @@ -3826,7 +3782,7 @@ win_T *wp; * Called from win_new_shellsize() after Rows changed. * This only does the current tab page, others must be done when made active. */ -void shell_new_rows() { +void shell_new_rows(void) { int h = (int)ROWS_AVAIL; if (firstwin == NULL) /* not initialized yet */ @@ -3849,7 +3805,7 @@ void shell_new_rows() { /* * Called from win_new_shellsize() after Columns changed. */ -void shell_new_columns() { +void shell_new_columns(void) { if (firstwin == NULL) /* not initialized yet */ return; @@ -3865,8 +3821,7 @@ void shell_new_columns() { /* * Save the size of all windows in "gap". */ -void win_size_save(gap) -garray_T *gap; +void win_size_save(garray_T *gap) { win_T *wp; @@ -3884,8 +3839,7 @@ garray_T *gap; * Restore window sizes, but only if the number of windows is still the same. * Does not free the growarray. */ -void win_size_restore(gap) -garray_T *gap; +void win_size_restore(garray_T *gap) { win_T *wp; int i; @@ -3906,7 +3860,7 @@ garray_T *gap; * frames. * Returns the row just after the last window. */ -int win_comp_pos() { +int win_comp_pos(void) { int row = tabline_height(); int col = 0; @@ -3920,10 +3874,7 @@ int win_comp_pos() { * "*row" and "*col" are the top-left position of the frame. They are updated * to the bottom-right position plus one. */ -static void frame_comp_pos(topfrp, row, col) -frame_T *topfrp; -int *row; -int *col; +static void frame_comp_pos(frame_T *topfrp, int *row, int *col) { win_T *wp; frame_T *frp; @@ -3961,8 +3912,7 @@ int *col; * Set current window height and take care of repositioning other windows to * fit around it. */ -void win_setheight(height) -int height; +void win_setheight(int height) { win_setheight_win(height, curwin); } @@ -3971,9 +3921,7 @@ int height; * Set the window height of window "win" and take care of repositioning other * windows to fit around it. */ -void win_setheight_win(height, win) -int height; -win_T *win; +void win_setheight_win(int height, win_T *win) { int row; @@ -4018,9 +3966,7 @@ win_T *win; * Check for the minimal height of the FR_ROW frame. * At the top level we can also use change the command line height. */ -static void frame_setheight(curfrp, height) -frame_T *curfrp; -int height; +static void frame_setheight(frame_T *curfrp, int height) { int room; /* total number of lines available */ int take; /* number of lines taken from other windows */ @@ -4168,15 +4114,12 @@ int height; * Set current window width and take care of repositioning other windows to * fit around it. */ -void win_setwidth(width) -int width; +void win_setwidth(int width) { win_setwidth_win(width, curwin); } -void win_setwidth_win(width, wp) -int width; -win_T *wp; +void win_setwidth_win(int width, win_T *wp) { /* Always keep current window at least one column wide, even when * 'winminwidth' is zero. */ @@ -4202,9 +4145,7 @@ win_T *wp; * * Strategy is similar to frame_setheight(). */ -static void frame_setwidth(curfrp, width) -frame_T *curfrp; -int width; +static void frame_setwidth(frame_T *curfrp, int width) { int room; /* total number of lines available */ int take; /* number of lines taken from other windows */ @@ -4328,7 +4269,7 @@ int width; /* * Check 'winminheight' for a valid value. */ -void win_setminheight() { +void win_setminheight(void) { int room; int first = TRUE; win_T *wp; @@ -4352,9 +4293,7 @@ void win_setminheight() { /* * Status line of dragwin is dragged "offset" lines down (negative is up). */ -void win_drag_status_line(dragwin, offset) -win_T *dragwin; -int offset; +void win_drag_status_line(win_T *dragwin, int offset) { frame_T *curfr; frame_T *fr; @@ -4468,9 +4407,7 @@ int offset; /* * Separator line of dragwin is dragged "offset" lines right (negative is left). */ -void win_drag_vsep_line(dragwin, offset) -win_T *dragwin; -int offset; +void win_drag_vsep_line(win_T *dragwin, int offset) { frame_T *curfr; frame_T *fr; @@ -4562,8 +4499,7 @@ int offset; /* * Set wp->w_fraction for the current w_wrow and w_height. */ -static void set_fraction(wp) -win_T *wp; +static void set_fraction(win_T *wp) { wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + FRACTION_MULT / 2) / (long)wp->w_height; @@ -4574,9 +4510,7 @@ win_T *wp; * This takes care of the things inside the window, not what happens to the * window position, the frame or to other windows. */ -void win_new_height(wp, height) -win_T *wp; -int height; +void win_new_height(win_T *wp, int height) { linenr_T lnum; int sline, line_size; @@ -4688,9 +4622,7 @@ int height; /* * Set the width of a window. */ -void win_new_width(wp, width) -win_T *wp; -int width; +void win_new_width(win_T *wp, int width) { wp->w_width = width; wp->w_lines_valid = 0; @@ -4704,8 +4636,7 @@ int width; wp->w_redr_status = TRUE; } -void win_comp_scroll(wp) -win_T *wp; +void win_comp_scroll(win_T *wp) { wp->w_p_scr = ((unsigned)wp->w_height >> 1); if (wp->w_p_scr == 0) @@ -4715,7 +4646,7 @@ win_T *wp; /* * command_height: called whenever p_ch has been changed */ -void command_height() { +void command_height(void) { int h; frame_T *frp; int old_p_ch = curtab->tp_ch_used; @@ -4782,9 +4713,7 @@ void command_height() { * Resize frame "frp" to be "n" lines higher (negative for less high). * Also resize the frames it is contained in. */ -static void frame_add_height(frp, n) -frame_T *frp; -int n; +static void frame_add_height(frame_T *frp, int n) { frame_new_height(frp, frp->fr_height + n, FALSE, FALSE); for (;; ) { @@ -4799,17 +4728,17 @@ int n; * Add or remove a status line for the bottom window(s), according to the * value of 'laststatus'. */ -void last_status(morewin) -int morewin; /* pretend there are two or more windows */ +void +last_status ( + int morewin /* pretend there are two or more windows */ +) { /* Don't make a difference between horizontal or vertical split. */ last_status_rec(topframe, (p_ls == 2 || (p_ls == 1 && (morewin || lastwin != firstwin)))); } -static void last_status_rec(fr, statusline) -frame_T *fr; -int statusline; +static void last_status_rec(frame_T *fr, int statusline) { frame_T *fp; win_T *wp; @@ -4861,7 +4790,7 @@ int statusline; /* * Return the number of lines used by the tab page line. */ -int tabline_height() { +int tabline_height(void) { switch (p_stal) { case 0: return 0; case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1; @@ -4874,9 +4803,7 @@ int tabline_height() { * If Visual mode is active, use the selected text if it's in one line. * Returns the name in allocated memory, NULL for failure. */ -char_u * grab_file_name(count, file_lnum) -long count; -linenr_T *file_lnum; +char_u *grab_file_name(long count, linenr_T *file_lnum) { if (VIsual_active) { int len; @@ -4905,10 +4832,7 @@ linenr_T *file_lnum; * FNAME_HYP check for hypertext link * FNAME_INCL apply "includeexpr" */ -char_u * file_name_at_cursor(options, count, file_lnum) -int options; -long count; -linenr_T *file_lnum; +char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum) { return file_name_in_line(ml_get_curline(), curwin->w_cursor.col, options, count, curbuf->b_ffname, @@ -4919,13 +4843,15 @@ linenr_T *file_lnum; * Return the name of the file under or after ptr[col]. * Otherwise like file_name_at_cursor(). */ -char_u * file_name_in_line(line, col, options, count, rel_fname, file_lnum) -char_u *line; -int col; -int options; -long count; -char_u *rel_fname; /* file we are searching relative to */ -linenr_T *file_lnum; /* line number after the file name */ +char_u * +file_name_in_line ( + char_u *line, + int col, + int options, + long count, + char_u *rel_fname, /* file we are searching relative to */ + linenr_T *file_lnum /* line number after the file name */ +) { char_u *ptr; int len; @@ -4996,9 +4922,7 @@ linenr_T *file_lnum; /* line number after the file name */ static char_u *eval_includeexpr __ARGS((char_u *ptr, int len)); -static char_u * eval_includeexpr(ptr, len) -char_u *ptr; -int len; +static char_u *eval_includeexpr(char_u *ptr, int len) { char_u *res; @@ -5013,12 +4937,14 @@ int len; * Return the name of the file ptr[len] in 'path'. * Otherwise like file_name_at_cursor(). */ -char_u * find_file_name_in_path(ptr, len, options, count, rel_fname) -char_u *ptr; -int len; -int options; -long count; -char_u *rel_fname; /* file we are searching relative to */ +char_u * +find_file_name_in_path ( + char_u *ptr, + int len, + int options, + long count, + char_u *rel_fname /* file we are searching relative to */ +) { char_u *file_name; int c; @@ -5076,8 +5002,7 @@ char_u *rel_fname; /* file we are searching relative to */ * Also check for ":\\", which MS Internet Explorer accepts, return * URL_BACKSLASH. */ -static int path_is_url(p) -char_u *p; +static int path_is_url(char_u *p) { if (STRNCMP(p, "://", (size_t)3) == 0) return URL_SLASH; @@ -5091,8 +5016,7 @@ char_u *p; * Return URL_BACKSLASH for "name:\\". * Return zero otherwise. */ -int path_with_url(fname) -char_u *fname; +int path_with_url(char_u *fname) { char_u *p; @@ -5104,8 +5028,7 @@ char_u *fname; /* * Return TRUE if "name" is a full (absolute) path name or URL. */ -int vim_isAbsName(name) -char_u *name; +int vim_isAbsName(char_u *name) { return path_with_url(name) != 0 || mch_isFullName(name); } @@ -5115,10 +5038,13 @@ char_u *name; * * return FAIL for failure, OK otherwise */ -int vim_FullName(fname, buf, len, force) -char_u *fname, *buf; -int len; -int force; /* force expansion even when already absolute */ +int +vim_FullName ( + char_u *fname, + char_u *buf, + int len, + int force /* force expansion even when already absolute */ +) { int retval = OK; int url; @@ -5141,7 +5067,7 @@ int force; /* force expansion even when already absolute */ * Return the minimal number of rows that is needed on the screen to display * the current number of windows. */ -int min_rows() { +int min_rows(void) { int total; tabpage_T *tp; int n; @@ -5165,7 +5091,7 @@ int min_rows() { * counting a help or preview window, unless it is the current window. * Does not count "aucmd_win". */ -int only_one_window() { +int only_one_window(void) { int count = 0; win_T *wp; @@ -5189,8 +5115,7 @@ int only_one_window() { * current buffer, and before applying autocommands. * When "do_curwin" is TRUE, also check current window. */ -void check_lnums(do_curwin) -int do_curwin; +void check_lnums(int do_curwin) { win_T *wp; @@ -5221,16 +5146,13 @@ int do_curwin; /* * Create a snapshot of the current frame sizes. */ -void make_snapshot(idx) -int idx; +void make_snapshot(int idx) { clear_snapshot(curtab, idx); make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]); } -static void make_snapshot_rec(fr, frp) -frame_T *fr; -frame_T **frp; +static void make_snapshot_rec(frame_T *fr, frame_T **frp) { *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T)); if (*frp == NULL) @@ -5249,16 +5171,13 @@ frame_T **frp; /* * Remove any existing snapshot. */ -static void clear_snapshot(tp, idx) -tabpage_T *tp; -int idx; +static void clear_snapshot(tabpage_T *tp, int idx) { clear_snapshot_rec(tp->tp_snapshot[idx]); tp->tp_snapshot[idx] = NULL; } -static void clear_snapshot_rec(fr) -frame_T *fr; +static void clear_snapshot_rec(frame_T *fr) { if (fr != NULL) { clear_snapshot_rec(fr->fr_next); @@ -5272,9 +5191,11 @@ frame_T *fr; * This is only done if the screen size didn't change and the window layout is * still the same. */ -void restore_snapshot(idx, close_curwin) -int idx; -int close_curwin; /* closing current window */ +void +restore_snapshot ( + int idx, + int close_curwin /* closing current window */ +) { win_T *wp; @@ -5295,9 +5216,7 @@ int close_curwin; /* closing current window */ * Check if frames "sn" and "fr" have the same layout, same following frames * and same children. */ -static int check_snapshot_rec(sn, fr) -frame_T *sn; -frame_T *fr; +static int check_snapshot_rec(frame_T *sn, frame_T *fr) { if (sn->fr_layout != fr->fr_layout || (sn->fr_next == NULL) != (fr->fr_next == NULL) @@ -5315,9 +5234,7 @@ frame_T *fr; * following frames and children. * Returns a pointer to the old current window, or NULL. */ -static win_T * restore_snapshot_rec(sn, fr) -frame_T *sn; -frame_T *fr; +static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr) { win_T *wp = NULL; win_T *wp2; @@ -5353,12 +5270,7 @@ frame_T *fr; * triggered, another tabpage access is limited. * Returns FAIL if switching to "win" failed. */ -int switch_win(save_curwin, save_curtab, win, tp, no_display) -win_T **save_curwin UNUSED; -tabpage_T **save_curtab UNUSED; -win_T *win UNUSED; -tabpage_T *tp UNUSED; -int no_display UNUSED; +int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display) { block_autocmds(); *save_curwin = curwin; @@ -5387,10 +5299,7 @@ int no_display UNUSED; * When "no_display" is TRUE the display won't be affected, no redraw is * triggered. */ -void restore_win(save_curwin, save_curtab, no_display) -win_T *save_curwin UNUSED; -tabpage_T *save_curtab UNUSED; -int no_display UNUSED; +void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display) { if (save_curtab != NULL && valid_tabpage(save_curtab)) { if (no_display) { @@ -5413,9 +5322,7 @@ int no_display UNUSED; * Make "buf" the current buffer. restore_buffer() MUST be called to undo. * No autocommands will be executed. Use aucmd_prepbuf() if there are any. */ -void switch_buffer(save_curbuf, buf) -buf_T *buf; -buf_T **save_curbuf; +void switch_buffer(buf_T **save_curbuf, buf_T *buf) { block_autocmds(); *save_curbuf = curbuf; @@ -5428,8 +5335,7 @@ buf_T **save_curbuf; /* * Restore the current buffer after using switch_buffer(). */ -void restore_buffer(save_curbuf) -buf_T *save_curbuf; +void restore_buffer(buf_T *save_curbuf) { unblock_autocmds(); /* Check for valid buffer, just in case. */ @@ -5450,12 +5356,7 @@ buf_T *save_curbuf; * If no particular ID is desired, -1 must be specified for 'id'. * Return ID of added match, -1 on failure. */ -int match_add(wp, grp, pat, prio, id) -win_T *wp; -char_u *grp; -char_u *pat; -int prio; -int id; +int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id) { matchitem_T *cur; matchitem_T *prev; @@ -5530,10 +5431,7 @@ int id; * Delete match with ID 'id' in the match list of window 'wp'. * Print error messages if 'perr' is TRUE. */ -int match_delete(wp, id, perr) -win_T *wp; -int id; -int perr; +int match_delete(win_T *wp, int id, int perr) { matchitem_T *cur = wp->w_match_head; matchitem_T *prev = cur; @@ -5567,8 +5465,7 @@ int perr; /* * Delete all matches in the match list of window 'wp'. */ -void clear_matches(wp) -win_T *wp; +void clear_matches(win_T *wp) { matchitem_T *m; @@ -5586,9 +5483,7 @@ win_T *wp; * Get match from ID 'id' in window 'wp'. * Return NULL if match not found. */ -matchitem_T * get_match(wp, id) -win_T *wp; -int id; +matchitem_T *get_match(win_T *wp, int id) { matchitem_T *cur = wp->w_match_head; @@ -5601,9 +5496,7 @@ int id; /* * Return TRUE if "topfrp" and its children are at the right height. */ -static int frame_check_height(topfrp, height) -frame_T *topfrp; -int height; +static int frame_check_height(frame_T *topfrp, int height) { frame_T *frp; @@ -5621,9 +5514,7 @@ int height; /* * Return TRUE if "topfrp" and its children are at the right width. */ -static int frame_check_width(topfrp, width) -frame_T *topfrp; -int width; +static int frame_check_width(frame_T *topfrp, int width) { frame_T *frp; -- cgit From 7afaf8ce26a8cbbcb0fa9e37cffe8c40ca908aef Mon Sep 17 00:00:00 2001 From: "waffle.io" Date: Mon, 24 Feb 2014 09:34:34 -0700 Subject: add waffle.io badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e3ca041283..0cbc9b56f1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Stories in Ready](https://badge.waffle.io/neovim/neovim.png?label=ready)](https://waffle.io/neovim/neovim) # neovim ([bountysource fundraiser](https://www.bountysource.com/fundraisers/539-neovim-first-iteration)) [![Build Status](https://travis-ci.org/neovim/neovim.png?branch=master)](https://travis-ci.org/neovim/neovim) -- cgit From 79321c62d504674d26de1d70a4832cfad7fb976e Mon Sep 17 00:00:00 2001 From: Christian Wellenbrock Date: Sat, 22 Feb 2014 15:11:17 +0100 Subject: Use neovim versions of ~/.vim and ~/.vimrc --- src/os_unix.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/os_unix.h b/src/os_unix.h index 692bb3442b..6320666097 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -200,21 +200,21 @@ #ifndef USR_VIMRC_FILE -# define USR_VIMRC_FILE "$HOME/.vimrc" +# define USR_VIMRC_FILE "$HOME/.neovimrc" #endif #if !defined(USR_EXRC_FILE2) -# define USR_VIMRC_FILE2 "~/.vim/vimrc" +# define USR_VIMRC_FILE2 "~/.neovim/vimrc" #endif #ifndef USR_GVIMRC_FILE -# define USR_GVIMRC_FILE "$HOME/.gvimrc" +# define USR_GVIMRC_FILE "$HOME/.neogvimrc" #endif #ifndef USR_GVIMRC_FILE2 -# define USR_GVIMRC_FILE2 "~/.vim/gvimrc" +# define USR_GVIMRC_FILE2 "~/.neovim/gvimrc" #endif @@ -223,7 +223,7 @@ #endif # ifndef VIMINFO_FILE -# define VIMINFO_FILE "$HOME/.viminfo" +# define VIMINFO_FILE "$HOME/.neoviminfo" # endif #ifndef EXRC_FILE @@ -231,7 +231,7 @@ #endif #ifndef VIMRC_FILE -# define VIMRC_FILE ".vimrc" +# define VIMRC_FILE ".neovimrc" #endif @@ -248,17 +248,17 @@ #endif #ifndef DFLT_VDIR -# define DFLT_VDIR "$HOME/.vim/view" /* default for 'viewdir' */ +# define DFLT_VDIR "$HOME/.neovim/view" /* default for 'viewdir' */ #endif #define DFLT_ERRORFILE "errors.err" # ifdef RUNTIME_GLOBAL -# define DFLT_RUNTIMEPATH "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," \ - RUNTIME_GLOBAL "/after,~/.vim/after" +# define DFLT_RUNTIMEPATH "~/.neovim," RUNTIME_GLOBAL ",$VIMRUNTIME," \ + RUNTIME_GLOBAL "/after,~/.neovim/after" # else # define DFLT_RUNTIMEPATH \ - "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after" + "~/.neovim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.neovim/after" # endif # define TEMPDIRNAMES "$TMPDIR", "/tmp", ".", "$HOME" -- cgit From 1df4ec20976ad0d6c52eb1207c40e06589ce54da Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 24 Feb 2014 14:16:21 -0300 Subject: Put waffle and travis badge together --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cbc9b56f1..20f8341d1b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -[![Stories in Ready](https://badge.waffle.io/neovim/neovim.png?label=ready)](https://waffle.io/neovim/neovim) # neovim ([bountysource fundraiser](https://www.bountysource.com/fundraisers/539-neovim-first-iteration)) [![Build Status](https://travis-ci.org/neovim/neovim.png?branch=master)](https://travis-ci.org/neovim/neovim) +[![Stories in Ready](https://badge.waffle.io/neovim/neovim.png?label=ready)](https://waffle.io/neovim/neovim) ### Introduction -- cgit From be3ce617c718cee0cbd418cd1b014f9e9480a0b9 Mon Sep 17 00:00:00 2001 From: jdiez17 Date: Sat, 22 Feb 2014 15:30:50 +0000 Subject: Changed binary output directory from src/ to bin/ --- CMakeLists.txt | 2 ++ Makefile | 6 +++--- src/po/Makefile | 2 +- src/testdir/Makefile | 2 +- src/testdir/test49.vim | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index adb9894a3c..340bbad979 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,5 +21,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/include") include_directories ("${PROJECT_BINARY_DIR}/config") +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + add_subdirectory(src) add_subdirectory(config) diff --git a/Makefile b/Makefile index 6e456022c2..ef609b0a49 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug -build/src/vim: deps +build/bin/vim: deps cd build && make -test: build/src/vim +test: build/bin/vim cd src/testdir && make deps: .deps/usr/lib/libuv.a @@ -23,4 +23,4 @@ clean: .PHONY: test deps cmake -.DEFAULT: build/src/vim +.DEFAULT: build/bin/vim diff --git a/src/po/Makefile b/src/po/Makefile index 8674031d84..e22c7f807e 100644 --- a/src/po/Makefile +++ b/src/po/Makefile @@ -127,7 +127,7 @@ CHECKFILES = \ PACKAGE = vim SHELL = /bin/sh -VIM = ../../build/src/vim +VIM = ../../build/bin/vim # The OLD_PO_FILE_INPUT and OLD_PO_FILE_OUTPUT are for the new GNU gettext # tools 0.10.37, which use a slightly different .po file format that is not diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 5238fda86a..8915328a8f 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -2,7 +2,7 @@ # Makefile to run all tests for Vim # -VIMPROG = ../../build/src/vim +VIMPROG = ../../build/bin/vim # Uncomment this line to use valgrind for memory leaks and extra warnings. # The output goes into a file "valgrind.testN" diff --git a/src/testdir/test49.vim b/src/testdir/test49.vim index eaf0cba00b..f5e6d56bc3 100644 --- a/src/testdir/test49.vim +++ b/src/testdir/test49.vim @@ -456,7 +456,7 @@ function! ExtraVim(...) " messing up the user's viminfo file. let redirect = a:0 ? \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : "" - exec "!echo '" . debug_quits . "q' | ../../build/src/vim -u NONE -N -Xes" . redirect . + exec "!echo '" . debug_quits . "q' | ../../build/bin/vim -u NONE -N -Xes" . redirect . \ " -c 'debuggreedy|set viminfo+=nviminfo'" . \ " -c 'let ExtraVimBegin = " . extra_begin . "'" . \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints . -- cgit From fd346a95fa619ef3dd8440bf541332ea2c97e399 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 18:52:12 +0000 Subject: use CMake's built in pthread detection CMake ships with a standard FindThreads module which can be used to a) test for a threading library and b) confirm that it is pthread. It also allows the hard-coding of the threading library name to be removed from ``src/CMakeLists.txt``. Make it an error not to have a pthread library installed and indicate to CMake that we strongly prefer pthread to any other platform threading library. --- CMakeLists.txt | 9 +++++++++ src/CMakeLists.txt | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 340bbad979..f0a04efe23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,15 @@ else() set(DEBUG 0) endif() +# Determine platform's threading library. Set CMAKE_THREAD_PREFER_PTHREAD +# explicitly to indicate a strong preference for pthread. It is an error to not +# have pthread installed even if, for example, the Win32 threading API is found. +set(CMAKE_THREAD_PREFER_PTHREAD ON) +find_package(Threads REQUIRED) +if(NOT CMAKE_USE_PTHREADS_INIT) + message(SEND_ERROR "The pthread library must be installed on your system.") +endif(NOT CMAKE_USE_PTHREADS_INIT) + # add dependencies to include/lib directories link_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/lib") include_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/include") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c7829e7d6..5ae5662a88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ file( GLOB IO_SOURCES io/*.c ) add_executable (vim ${NEOVIM_SOURCES} ${IO_SOURCES}) -target_link_libraries (vim m uv pthread) +target_link_libraries (vim m uv ${CMAKE_THREAD_LIBS_INIT}) include(CheckLibraryExists) check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP) -- cgit From 3ab95bcc861031f6c7e86d53102dcdcc98a67770 Mon Sep 17 00:00:00 2001 From: Jim Hester Date: Mon, 24 Feb 2014 13:48:18 -0500 Subject: Add table of contents to README.md I added a table of contents to the readme and replaced the html links with markdown links. Thought you might find it useful! --- README.md | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 87919c7027..d0ff8a0f39 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,27 @@ [![Build Status](https://travis-ci.org/neovim/neovim.png?branch=master)](https://travis-ci.org/neovim/neovim) [![Stories in Ready](https://badge.waffle.io/neovim/neovim.png?label=ready)](https://waffle.io/neovim/neovim) +* [Introduction](#introduction) +* [Problem](#problem) +* [Solution](#solution) + * [Migrate to a cmake-based build](#migrate-to-a-cmake-based-build) + * [Legacy support and compile-time features](#legacy-support-and-compile-time-features) + * [Platform-specific code](#platform-specific code) + * [New plugin architecture](#new-plugin-architecture) + * [New GUI architecture](#new-gui-architecture) + * [Development on github](#development-on-github) +* [Status](#status) +* [Dependencies](#dependencies) + * [For Debian/Ubuntu](#for-debianubuntu) + * [For FreeBSD 10](#for-freebsd-10) + * [For OS X](#for-os-x) +* [For Arch Linux](#for-arch-linux) +* [Building](#building) +* [Community](#community) +* [Contributing](#contributing) +* [License](#license) + + ### Introduction Vim is a powerful text editor with a big community that is constantly growing. Even though the editor is about two decades old, people still extend and want to improve it, mostly using vimscript or one of the supported scripting languages. @@ -28,23 +49,14 @@ By achieving those goals new developers will soon join the community, consequent It is important to emphasize that this is not a project to rewrite vim from scratch or transform it into an IDE (though the new features provided will enable IDE-like distributions of the editor). The changes implemented here should have little impact on vim's editing model or vimscript in general. Most vimscript plugins should continue to work normally. -The following topics contain brief explanations of the major changes (and motivations) that will be performed in the first iteration: - -* Migrate to a cmake-based build -* Legacy support and compile-time features -* Platform-specific code -* New plugin architecture -* New GUI architecture -* Development on github +The following topics contain brief explanations of the major changes (and motivations) that will be performed in the first iteration. - ##### Migrate to a cmake-based build The source tree has dozens (if not hundreds) of files dedicated to building vim with on various platforms with different configurations, and many of these files look abandoned or outdated. Most users don't care about selecting individual features and just compile using '--with-features=huge', which still generates an executable that is small enough even for lightweight systems by today's standards. All those files will be removed and vim will be built using [cmake](http://www.cmake.org), a modern build system that generates build scripts for the most relevant platforms. - ##### Legacy support and compile-time features Vim has a significant amount of code dedicated to supporting legacy systems and compilers. All that code increases the maintenance burden and will be removed. @@ -56,14 +68,12 @@ These changes wont affect most users. Those that only have a C89 compiler instal - Upgrade their software - Continue using vim - ##### Platform-specific code Most of the platform-specific code will be removed and [libuv](https://github.com/joyent/libuv) will be used to handle system differences. libuv is a modern multi-platform library with functions to perform common system tasks, and supports most unixes and windows, so the vast majority of vim's community will be covered. - ##### New plugin architecture All code supporting embedded scripting language interpreters will be replaced by a new plugin system that will support extensions written in any programming language. -- cgit From 0ad500de588a9f95bfa673a83751c5e472e7eded Mon Sep 17 00:00:00 2001 From: Jim Hester Date: Mon, 24 Feb 2014 14:40:00 -0500 Subject: Fix space in link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0ff8a0f39..dcb94e2751 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ * [Solution](#solution) * [Migrate to a cmake-based build](#migrate-to-a-cmake-based-build) * [Legacy support and compile-time features](#legacy-support-and-compile-time-features) - * [Platform-specific code](#platform-specific code) + * [Platform-specific code](#platform-specific-code) * [New plugin architecture](#new-plugin-architecture) * [New GUI architecture](#new-gui-architecture) * [Development on github](#development-on-github) -- cgit From d29ab233a6516064e83aca98339a587026684d4d Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 24 Feb 2014 18:24:30 -0300 Subject: Add link to mailing list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcb94e2751..4ef4a69f2c 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ Using Homebrew on Mac: ### Community -Join the community on IRC in #neovim on Freenode. +Join the community on IRC in #neovim on Freenode or the [mailing list](https://groups.google.com/forum/#!forum/neovim) ### Contributing -- cgit From 9db0fc35823f648ea9ce8c56e24131db8e9444b9 Mon Sep 17 00:00:00 2001 From: scott-linder Date: Mon, 24 Feb 2014 14:57:47 -0500 Subject: Changed name of binary (vim -> nvim). Also updated affected config files and test49.vim --- Makefile | 6 +++--- src/CMakeLists.txt | 8 ++++---- src/po/Makefile | 4 ++-- src/testdir/Makefile | 2 +- src/testdir/test49.vim | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index ef609b0a49..c10f93c6b5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug -build/bin/vim: deps +build/bin/nvim: deps cd build && make -test: build/bin/vim +test: build/bin/nvim cd src/testdir && make deps: .deps/usr/lib/libuv.a @@ -23,4 +23,4 @@ clean: .PHONY: test deps cmake -.DEFAULT: build/bin/vim +.DEFAULT: build/bin/nvim diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ae5662a88..e355979723 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,19 +12,19 @@ list(APPEND NEOVIM_SOURCES "${PROJECT_BINARY_DIR}/config/auto/pathdef.c") file( GLOB IO_SOURCES io/*.c ) -add_executable (vim ${NEOVIM_SOURCES} ${IO_SOURCES}) +add_executable (nvim ${NEOVIM_SOURCES} ${IO_SOURCES}) -target_link_libraries (vim m uv ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (nvim m uv ${CMAKE_THREAD_LIBS_INIT}) include(CheckLibraryExists) check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP) if (HAVE_LIBTERMCAP) - target_link_libraries(vim termcap) + target_link_libraries(nvim termcap) else() check_library_exists(curses tgetent "" HAVE_LIBCURSES) if (HAVE_LIBCURSES) - target_link_libraries(vim curses) + target_link_libraries(nvim curses) else() message(FATAL_ERROR "can't find something resembling -ltermcap") endif() diff --git a/src/po/Makefile b/src/po/Makefile index e22c7f807e..d702b9f277 100644 --- a/src/po/Makefile +++ b/src/po/Makefile @@ -125,9 +125,9 @@ CHECKFILES = \ uk.cp1251.ck \ zh_CN.cp936.ck -PACKAGE = vim +PACKAGE = nvim SHELL = /bin/sh -VIM = ../../build/bin/vim +VIM = ../../build/bin/nvim # The OLD_PO_FILE_INPUT and OLD_PO_FILE_OUTPUT are for the new GNU gettext # tools 0.10.37, which use a slightly different .po file format that is not diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 8915328a8f..16db2846c2 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -2,7 +2,7 @@ # Makefile to run all tests for Vim # -VIMPROG = ../../build/bin/vim +VIMPROG = ../../build/bin/nvim # Uncomment this line to use valgrind for memory leaks and extra warnings. # The output goes into a file "valgrind.testN" diff --git a/src/testdir/test49.vim b/src/testdir/test49.vim index f5e6d56bc3..21c2a0c582 100644 --- a/src/testdir/test49.vim +++ b/src/testdir/test49.vim @@ -456,7 +456,7 @@ function! ExtraVim(...) " messing up the user's viminfo file. let redirect = a:0 ? \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : "" - exec "!echo '" . debug_quits . "q' | ../../build/bin/vim -u NONE -N -Xes" . redirect . + exec "!echo '" . debug_quits . "q' | ../../build/bin/nvim -u NONE -N -Xes" . redirect . \ " -c 'debuggreedy|set viminfo+=nviminfo'" . \ " -c 'let ExtraVimBegin = " . extra_begin . "'" . \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints . -- cgit From f608d2361c2be9ea4f0c0b258f1b4f173d1004be Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Sun, 23 Feb 2014 09:18:25 -0300 Subject: README.md: cosmetic fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4ef4a69f2c..219ee5b60a 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,9 @@ All those files will be removed and vim will be built using [cmake](http://www.c Vim has a significant amount of code dedicated to supporting legacy systems and compilers. All that code increases the maintenance burden and will be removed. -Most optional features will no longer be optional (see above), with the exception of some broken and useless features (eg: netbeans integration, sun workshop) which will be removed permanently. Vi emulation will also be removed (setting 'nocompatible' will be a no-op). +Most optional features will no longer be optional (see above), with the exception of some broken and useless features (e.g., netbeans integration, sun workshop) which will be removed permanently. Vi emulation will also be removed (setting 'nocompatible' will be a no-op). -These changes wont affect most users. Those that only have a C89 compiler installed or use vim on legacy systems such as Amiga, BeOS or MSDOS will have two options: +These changes won't affect most users. Those that only have a C89 compiler installed or use vim on legacy systems such as Amiga, BeOS or MS-DOS will have two options: - Upgrade their software - Continue using vim -- cgit From b58f079d8a24ce13fb72d1ea043e523955a20e74 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:08:36 +0000 Subject: os_unix: add #include for libuv --- src/os_unix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/os_unix.c b/src/os_unix.c index 8dbd512726..5ced167868 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -32,6 +32,7 @@ #include "os_unixx.h" /* unix includes for os_unix.c only */ +#include "uv.h" #ifdef HAVE_SELINUX # include -- cgit From 68d8ab54a126671ccd157318c3d51885872dec1d Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:11:36 +0000 Subject: os_unix: switch to libuv chdir() function --- src/os_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os_unix.c b/src/os_unix.c index 5ced167868..d00b5a82e0 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -229,7 +229,7 @@ int mch_chdir(char *path) smsg((char_u *)"chdir(%s)", path); verbose_leave(); } - return chdir(path); + return uv_chdir(path); } /* -- cgit From 65e761065583ff445a5f78a454e931fc81bfe40f Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:14:16 +0000 Subject: os_unix: use libuv total memory function --- src/os_unix.c | 90 ++--------------------------------------------------------- src/os_unix.h | 11 -------- 2 files changed, 3 insertions(+), 98 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index d00b5a82e0..8c46dab522 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -333,100 +333,16 @@ int mch_char_avail() { return WaitForChar(0L); } -#if defined(HAVE_TOTAL_MEM) || defined(PROTO) -# ifdef HAVE_SYS_RESOURCE_H -# include -# endif -# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL) -# include -# endif -# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO) -# include -# endif - /* * Return total amount of memory available in Kbyte. * Doesn't change when memory has been allocated. */ long_u mch_total_mem(int special) { - long_u mem = 0; - long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */ - -# ifdef HAVE_SYSCTL - int mib[2], physmem; - size_t len; - - /* BSD way of getting the amount of RAM available. */ - mib[0] = CTL_HW; - mib[1] = HW_USERMEM; - len = sizeof(physmem); - if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0) - mem = (long_u)physmem; -# endif - -# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO) - if (mem == 0) { - struct sysinfo sinfo; - - /* Linux way of getting amount of RAM available */ - if (sysinfo(&sinfo) == 0) { -# ifdef HAVE_SYSINFO_MEM_UNIT - /* avoid overflow as much as possible */ - while (shiftright > 0 && (sinfo.mem_unit & 1) == 0) { - sinfo.mem_unit = sinfo.mem_unit >> 1; - --shiftright; - } - mem = sinfo.totalram * sinfo.mem_unit; -# else - mem = sinfo.totalram; -# endif - } - } -# endif - -# ifdef HAVE_SYSCONF - if (mem == 0) { - long pagesize, pagecount; - - /* Solaris way of getting amount of RAM available */ - pagesize = sysconf(_SC_PAGESIZE); - pagecount = sysconf(_SC_PHYS_PAGES); - if (pagesize > 0 && pagecount > 0) { - /* avoid overflow as much as possible */ - while (shiftright > 0 && (pagesize & 1) == 0) { - pagesize = (long_u)pagesize >> 1; - --shiftright; - } - mem = (long_u)pagesize * pagecount; - } - } -# endif - - /* Return the minimum of the physical memory and the user limit, because - * using more than the user limit may cause Vim to be terminated. */ -# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) - { - struct rlimit rlp; - - if (getrlimit(RLIMIT_DATA, &rlp) == 0 - && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1)) -# ifdef RLIM_INFINITY - && rlp.rlim_cur != RLIM_INFINITY -# endif - && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright) - ) { - mem = (long_u)rlp.rlim_cur; - shiftright = 10; - } - } -# endif - - if (mem > 0) - return mem >> shiftright; - return (long_u)0x1fffff; + /* We need to return memory in *Kbytes* but uv_get_total_memory() returns the + * number of bytes of total memory. */ + return uv_get_total_memory() >> 10; } -#endif void mch_delay(long msec, int ignoreinput) { diff --git a/src/os_unix.h b/src/os_unix.h index 6320666097..5ae7c38f88 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -149,17 +149,6 @@ # undef __ARGS #endif -#if (defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)) \ - || (defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)) \ - || defined(HAVE_SYSCTL) || defined(HAVE_SYSCONF) -# define HAVE_TOTAL_MEM -#endif - - - - - - /* * Unix system-dependent file names */ -- cgit From 0f438e42a839d67b1c66ceb2817ae90b0a368c2a Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 23:12:00 +0000 Subject: move libuv functions to os.c and io.c module Despite being an io library, the functions currently implemented with libuv include some non-I/O tasks like getting the total amount of memory. --- src/io.c | 26 ++++++++++++++++++++++++++ src/os.c | 27 +++++++++++++++++++++++++++ src/os_unix.c | 23 ----------------------- 3 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 src/io.c create mode 100644 src/os.c diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000000..f75f6a03ea --- /dev/null +++ b/src/io.c @@ -0,0 +1,26 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * io.c -- filesystem access, event loop etc. + */ + +#include "vim.h" + +#include "uv.h" + +int mch_chdir(char *path) +{ + if (p_verbose >= 5) { + verbose_enter(); + smsg((char_u *)"chdir(%s)", path); + verbose_leave(); + } + return uv_chdir(path); +} diff --git a/src/os.c b/src/os.c new file mode 100644 index 0000000000..c61259dd55 --- /dev/null +++ b/src/os.c @@ -0,0 +1,27 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * os.c -- OS-level calls to query hardware, etc. + */ + +#include "vim.h" + +#include "uv.h" + +/* + * Return total amount of memory available in Kbyte. + * Doesn't change when memory has been allocated. + */ +long_u mch_total_mem(int special) +{ + /* We need to return memory in *Kbytes* but uv_get_total_memory() returns the + * number of bytes of total memory. */ + return uv_get_total_memory() >> 10; +} diff --git a/src/os_unix.c b/src/os_unix.c index 8c46dab522..f67307346e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -32,8 +32,6 @@ #include "os_unixx.h" /* unix includes for os_unix.c only */ -#include "uv.h" - #ifdef HAVE_SELINUX # include static int selinux_enabled = -1; @@ -222,16 +220,6 @@ static struct signalinfo { {-1, "Unknown!", FALSE} }; -int mch_chdir(char *path) -{ - if (p_verbose >= 5) { - verbose_enter(); - smsg((char_u *)"chdir(%s)", path); - verbose_leave(); - } - return uv_chdir(path); -} - /* * Write s[len] to the screen. */ @@ -333,17 +321,6 @@ int mch_char_avail() { return WaitForChar(0L); } -/* - * Return total amount of memory available in Kbyte. - * Doesn't change when memory has been allocated. - */ -long_u mch_total_mem(int special) -{ - /* We need to return memory in *Kbytes* but uv_get_total_memory() returns the - * number of bytes of total memory. */ - return uv_get_total_memory() >> 10; -} - void mch_delay(long msec, int ignoreinput) { int old_tmode; -- cgit From c067e5580b26410eb3130f716f55c4e4d0831d51 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 24 Feb 2014 22:17:46 -0300 Subject: Create new OS module This module will contain all functions that perform OS calls such as IO, filesystem access, etc. --- src/CMakeLists.txt | 4 ++-- src/diff.c | 1 + src/ex_docmd.c | 1 + src/io.c | 26 -------------------------- src/misc1.c | 1 + src/misc2.c | 1 + src/os.c | 27 --------------------------- src/os/fs.c | 25 +++++++++++++++++++++++++ src/os/mem.c | 26 ++++++++++++++++++++++++++ src/os/os.h | 4 ++++ src/os_unix.c | 1 + src/proto/os_unix.pro | 2 -- src/window.c | 1 + 13 files changed, 63 insertions(+), 57 deletions(-) delete mode 100644 src/io.c delete mode 100644 src/os.c create mode 100644 src/os/fs.c create mode 100644 src/os/mem.c create mode 100644 src/os/os.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e355979723..8adfa9fff8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,9 +10,9 @@ endforeach() list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove}) list(APPEND NEOVIM_SOURCES "${PROJECT_BINARY_DIR}/config/auto/pathdef.c") -file( GLOB IO_SOURCES io/*.c ) +file( GLOB OS_SOURCES os/*.c ) -add_executable (nvim ${NEOVIM_SOURCES} ${IO_SOURCES}) +add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES}) target_link_libraries (nvim m uv ${CMAKE_THREAD_LIBS_INIT}) diff --git a/src/diff.c b/src/diff.c index 61c91f248d..166b40ee0c 100644 --- a/src/diff.c +++ b/src/diff.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" static int diff_busy = FALSE; /* ex_diffgetput() is busy */ diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 942a0f28c5..0a31ccc108 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" static int quitmore = 0; static int ex_pressedreturn = FALSE; diff --git a/src/io.c b/src/io.c deleted file mode 100644 index f75f6a03ea..0000000000 --- a/src/io.c +++ /dev/null @@ -1,26 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * io.c -- filesystem access, event loop etc. - */ - -#include "vim.h" - -#include "uv.h" - -int mch_chdir(char *path) -{ - if (p_verbose >= 5) { - verbose_enter(); - smsg((char_u *)"chdir(%s)", path); - verbose_leave(); - } - return uv_chdir(path); -} diff --git a/src/misc1.c b/src/misc1.c index 3f1e32bc69..98ed65a08b 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -13,6 +13,7 @@ #include "vim.h" #include "version.h" +#include "os/os.h" static char_u *vim_version_dir __ARGS((char_u *vimdir)); static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name)); diff --git a/src/misc2.c b/src/misc2.c index e59ccf6626..da90eedb55 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -11,6 +11,7 @@ * misc2.c: Various functions. */ #include "vim.h" +#include "os/os.h" static char_u *username = NULL; /* cached result of mch_get_user_name() */ diff --git a/src/os.c b/src/os.c deleted file mode 100644 index c61259dd55..0000000000 --- a/src/os.c +++ /dev/null @@ -1,27 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -/* - * os.c -- OS-level calls to query hardware, etc. - */ - -#include "vim.h" - -#include "uv.h" - -/* - * Return total amount of memory available in Kbyte. - * Doesn't change when memory has been allocated. - */ -long_u mch_total_mem(int special) -{ - /* We need to return memory in *Kbytes* but uv_get_total_memory() returns the - * number of bytes of total memory. */ - return uv_get_total_memory() >> 10; -} diff --git a/src/os/fs.c b/src/os/fs.c new file mode 100644 index 0000000000..358b07e57b --- /dev/null +++ b/src/os/fs.c @@ -0,0 +1,25 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * fs.c -- filesystem access + */ + +#include + +#include "os.h" + +int mch_chdir(char *path) { + if (p_verbose >= 5) { + verbose_enter(); + smsg((char_u *)"chdir(%s)", path); + verbose_leave(); + } + return uv_chdir(path); +} diff --git a/src/os/mem.c b/src/os/mem.c new file mode 100644 index 0000000000..20abd58261 --- /dev/null +++ b/src/os/mem.c @@ -0,0 +1,26 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * os.c -- OS-level calls to query hardware, etc. + */ + +#include + +#include "os.h" + +/* + * Return total amount of memory available in Kbyte. + * Doesn't change when memory has been allocated. + */ +long_u mch_total_mem(int special) { + /* We need to return memory in *Kbytes* but uv_get_total_memory() returns the + * number of bytes of total memory. */ + return uv_get_total_memory() >> 10; +} diff --git a/src/os/os.h b/src/os/os.h new file mode 100644 index 0000000000..f344f180df --- /dev/null +++ b/src/os/os.h @@ -0,0 +1,4 @@ +#include "../vim.h" + +long_u mch_total_mem(int special); +int mch_chdir(char *path); diff --git a/src/os_unix.c b/src/os_unix.c index f67307346e..f65b285ba7 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -28,6 +28,7 @@ # define select select_declared_wrong #include "vim.h" +#include "os/os.h" #include "os_unixx.h" /* unix includes for os_unix.c only */ diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 3c97345d00..7c5c62a786 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -1,9 +1,7 @@ /* os_unix.c */ -int mch_chdir __ARGS((char *path)); void mch_write __ARGS((char_u *s, int len)); int mch_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); int mch_char_avail __ARGS((void)); -long_u mch_total_mem __ARGS((int special)); void mch_delay __ARGS((long msec, int ignoreinput)); int mch_stackcheck __ARGS((char *p)); void mch_startjmp __ARGS((void)); diff --git a/src/window.c b/src/window.c index 29c82e4086..5256fbd1fa 100644 --- a/src/window.c +++ b/src/window.c @@ -8,6 +8,7 @@ */ #include "vim.h" +#include "os/os.h" static int path_is_url __ARGS((char_u *p)); static void win_init __ARGS((win_T *newp, win_T *oldp, int flags)); -- cgit From d5f74cf8bbfd9b4b3dce756756dd09de98da3458 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 24 Feb 2014 22:41:39 -0300 Subject: Add missing include guard to os module --- src/os/os.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/os/os.h b/src/os/os.h index f344f180df..58d49d36e7 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -1,4 +1,9 @@ +#ifndef NEOVIM_OS_H +#define NEOVIM_OS_H + #include "../vim.h" long_u mch_total_mem(int special); int mch_chdir(char *path); + +#endif -- cgit From e7b0aa224a2a873ad9da05776e26793eb5c882e6 Mon Sep 17 00:00:00 2001 From: Theo Belaire Date: Sat, 22 Feb 2014 14:49:53 -0800 Subject: Added curl support and one test Now it checks for the existance of curl after failing to find wget. Note that I ended up removing the quotes around $url when referencing it in the call to wget, since urls can't have spaces anyways, and the correct quoting was messy. To test, I did rm -r .deps make clean make cmake make And it worked. --- scripts/common.sh | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/scripts/common.sh b/scripts/common.sh index f42c000c6f..eb2d05c48c 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -23,21 +23,29 @@ download() { if [ ! -d "$tgt" ]; then mkdir -p "$tgt" + local download_command="" if which wget > /dev/null 2>&1; then - tmp_dir=$(mktemp -d "/tmp/download_sha1check_XXXXXXX") - fifo="$tmp_dir/fifo" - mkfifo "$fifo" - # download, untar and calculate sha1 sum in one pass - (wget "$url" -O - | tee "$fifo" | \ - (cd "$tgt"; tar --strip-components=1 -xvzf -)) & - sum=$("$sha1sumcmd" < "$fifo" | cut -d ' ' -f1) - rm -rf "$tmp_dir" - if [ "$sum" != "$sha1" ]; then - echo "SHA1 sum doesn't match, expected '$sha1' got '$sum'" - exit 1 - fi + # -O - to send output to stdout + download_command="wget $url -O -" + elif which curl >/dev/null 2>&1; then + # -L to follow the redirects that github will send us + # -sS to supress the progress bar, but show errors + # curl sends output to stdout by default + download_command="curl -L -sS $url" else - echo "Missing wget utility" + echo "Missing wget utility and curl utility" + exit 1 + fi + local tmp_dir=$(mktemp -d "/tmp/download_sha1check_XXXXXXX") + local fifo="$tmp_dir/fifo" + mkfifo "$fifo" + # download, untar and calculate sha1 sum in one pass + ($download_command | tee "$fifo" | \ + (cd "$tgt"; tar --strip-components=1 -xvzf -)) & + local sum=$("$sha1sumcmd" < "$fifo" | cut -d ' ' -f1) + rm -rf "$tmp_dir" + if [ "$sum" != "$sha1" ]; then + echo "SHA1 sum doesn't match, expected '$sha1' got '$sum'" exit 1 fi fi -- cgit From 98f4c55e456371050a373e077d894d6031395680 Mon Sep 17 00:00:00 2001 From: Theo Belaire Date: Sat, 22 Feb 2014 16:10:31 -0800 Subject: Silenced wget's progress bar This way it won't show up in travis-ci like: 0% [ ] 0 --.-K/s 100%[======================================>] 371,453 --.-K/s --- scripts/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/common.sh b/scripts/common.sh index eb2d05c48c..0317f02725 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -26,7 +26,7 @@ download() { local download_command="" if which wget > /dev/null 2>&1; then # -O - to send output to stdout - download_command="wget $url -O -" + download_command="wget --no-verbose $url -O -" elif which curl >/dev/null 2>&1; then # -L to follow the redirects that github will send us # -sS to supress the progress bar, but show errors -- cgit From fffb8991fdb3333355bf6fbc584229990d4455ab Mon Sep 17 00:00:00 2001 From: ash-lshift Date: Tue, 25 Feb 2014 09:11:16 +0000 Subject: silence tar when getting libuv --- scripts/common.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/common.sh b/scripts/common.sh index 0317f02725..9efa3d5e6c 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -39,14 +39,17 @@ download() { local tmp_dir=$(mktemp -d "/tmp/download_sha1check_XXXXXXX") local fifo="$tmp_dir/fifo" mkfifo "$fifo" + echo "Downloading $url..." # download, untar and calculate sha1 sum in one pass ($download_command | tee "$fifo" | \ - (cd "$tgt"; tar --strip-components=1 -xvzf -)) & + (cd "$tgt"; tar --strip-components=1 -xzf -)) & local sum=$("$sha1sumcmd" < "$fifo" | cut -d ' ' -f1) rm -rf "$tmp_dir" if [ "$sum" != "$sha1" ]; then echo "SHA1 sum doesn't match, expected '$sha1' got '$sum'" exit 1 + else + echo "Download complete." fi fi } -- cgit From ba6273bb51d7bb0a189b4af922dd7b65aa5bb5ec Mon Sep 17 00:00:00 2001 From: Jim Hester Date: Mon, 24 Feb 2014 17:41:30 -0500 Subject: Arch linux link in TOC had the wrong indentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 219ee5b60a..23bc7af842 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ * [For Debian/Ubuntu](#for-debianubuntu) * [For FreeBSD 10](#for-freebsd-10) * [For OS X](#for-os-x) -* [For Arch Linux](#for-arch-linux) + * [For Arch Linux](#for-arch-linux) * [Building](#building) * [Community](#community) * [Contributing](#contributing) -- cgit From de7d5cec8ed450b06efadf2151db43c378f9d5db Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 25 Feb 2014 11:55:36 -0300 Subject: Add local.mk include in makefile This can be used by devs that need their own custom targets --- .gitignore | 3 +++ Makefile | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index b013dd8c3c..a36e19fe97 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ src/testdir/test.log src/testdir/test.ok src/testdir/*.failed src/testdir/X* + +# local make targets +local.mk diff --git a/Makefile b/Makefile index c10f93c6b5..29966619e6 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +-include local.mk + CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug build/bin/nvim: deps -- cgit From 4961654a2ab5c746920d4f9c40eda662dfe19cc3 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Tue, 25 Feb 2014 00:03:13 +0000 Subject: CMakeLists: add install target for nvim --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8adfa9fff8..dfd0764a94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,3 +31,5 @@ else() endif() include_directories ("${PROJECT_SOURCE_DIR}/src/proto") + +install(TARGETS nvim RUNTIME DESTINATION bin) -- cgit From cf3322f8c2dc3c7a0a366546de0a6a25921d7165 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Tue, 25 Feb 2014 00:04:51 +0000 Subject: Makefile: add install target This simply calls the install target in the build directory. IMHO I think it's looking a bit hacky having a separate Makefile target to do this rather than using the usual CMake workflow but mine is not to reason why... [Also, I've copied ``cd build && make ...`` although I'm sure ``$MAKE -C build/ ...`` is probably the Right Thing (TM).] Note that you'll have to set CMAKE_INSTALL_PREFIX on the cmake command line to change where this installs to. --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 29966619e6..cfb1d15a13 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,9 @@ clean: rm -f src/testdir/$$file.vim; \ done -.PHONY: test deps cmake +install: build/bin/nvim + cd build && make install + +.PHONY: test deps cmake install .DEFAULT: build/bin/nvim -- cgit From 0a15feee9d0ceb051a66ec31eee60f5477359ee2 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Tue, 25 Feb 2014 00:22:48 +0000 Subject: Makefile: allow configuration of CMake flags Although CMAKE_FLAGS was already a Makefile variable, it didn't have an empty default value meaning that extending the flags to CMake in a clean way was difficult. Add a CMAKE_EXTRA_FLAGS variable which is appended to the default flags. --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cfb1d15a13..689f171cd1 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,9 @@ CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug +# Extra CMake flags which extend the default set +CMAKE_EXTRA_FLAGS := + build/bin/nvim: deps cd build && make @@ -15,7 +18,7 @@ deps: .deps/usr/lib/libuv.a cmake: clean mkdir build - cd build && cmake $(CMAKE_FLAGS) ../ + cd build && cmake $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) ../ clean: rm -rf build -- cgit From d342257ae414a98be74b2a58382678eef7249ebc Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Tue, 25 Feb 2014 00:24:06 +0000 Subject: add installation as a travis test Not only should we pass the test suite but we should also install successfully. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bb82ce1e4c..04c592fc95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,2 @@ language: c -script: make cmake && make test +script: make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$PWD/dist" && make test && make install -- cgit From 1e2da25d3da075c87fababccae0c58d6ffa7df21 Mon Sep 17 00:00:00 2001 From: Thomas Wienecke Date: Tue, 25 Feb 2014 17:03:04 +0100 Subject: os_unix: Use libuv uv_cwd instead of getcwd/getwd. --- src/eval.c | 1 + src/fileio.c | 1 + src/mark.c | 1 + src/os/fs.c | 14 ++++++++++++++ src/os/os.h | 1 + src/os_unix.c | 18 ------------------ src/proto/os_unix.pro | 1 - src/quickfix.c | 1 + 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/eval.c b/src/eval.c index 1ad5cf6eae..51519bb899 100644 --- a/src/eval.c +++ b/src/eval.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" diff --git a/src/fileio.c b/src/fileio.c index e4d261d902..8dc31c31c6 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" #if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) diff --git a/src/mark.c b/src/mark.c index 67888912d8..52f51b7679 100644 --- a/src/mark.c +++ b/src/mark.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" /* * This file contains routines to maintain and manipulate marks. diff --git a/src/os/fs.c b/src/os/fs.c index 358b07e57b..e9a76c6b79 100644 --- a/src/os/fs.c +++ b/src/os/fs.c @@ -23,3 +23,17 @@ int mch_chdir(char *path) { } return uv_chdir(path); } + +/* + * Get name of current directory into buffer 'buf' of length 'len' bytes. + * Return OK for success, FAIL for failure. + */ +int mch_dirname(char_u *buf, int len) +{ + int errno; + if ((errno = uv_cwd((char *)buf, len)) != 0) { + STRCPY(buf, uv_strerror(errno)); + return FAIL; + } + return OK; +} diff --git a/src/os/os.h b/src/os/os.h index 58d49d36e7..099f53312f 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -5,5 +5,6 @@ long_u mch_total_mem(int special); int mch_chdir(char *path); +int mch_dirname(char_u *buf, int len); #endif diff --git a/src/os_unix.c b/src/os_unix.c index f65b285ba7..2bfddafc6c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1244,24 +1244,6 @@ static char * strerror(int err) } #endif -/* - * Get name of current directory into buffer 'buf' of length 'len' bytes. - * Return OK for success, FAIL for failure. - */ -int mch_dirname(char_u *buf, int len) -{ -#if defined(USE_GETCWD) - if (getcwd((char *)buf, len) == NULL) { - STRCPY(buf, strerror(errno)); - return FAIL; - } - return OK; -#else - return getwd((char *)buf) != NULL ? OK : FAIL; -#endif -} - - /* * Get absolute file name into "buf[len]". * diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 7c5c62a786..64be80500c 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -27,7 +27,6 @@ int mch_get_user_name __ARGS((char_u *s, int len)); int mch_get_uname __ARGS((uid_t uid, char_u *s, int len)); void mch_get_host_name __ARGS((char_u *s, int len)); long mch_get_pid __ARGS((void)); -int mch_dirname __ARGS((char_u *buf, int len)); void slash_adjust __ARGS((char_u *p)); int mch_FullName __ARGS((char_u *fname, char_u *buf, int len, int force)); int mch_isFullName __ARGS((char_u *fname)); diff --git a/src/quickfix.c b/src/quickfix.c index 5fa175c0cb..a141d9834b 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" struct dir_stack_T { -- cgit From 60280ffa1095cf62e9c4892177c1ccc47db4f8f8 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 25 Feb 2014 15:24:29 -0300 Subject: Modify travis script to remove testing noise --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04c592fc95..d1a0445925 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,2 @@ language: c -script: make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$PWD/dist" && make test && make install +script: make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$PWD/dist" && make && make test > /dev/null 2>&1 && make install -- cgit From 8437a4c9724f17824c9043afc27288013d096649 Mon Sep 17 00:00:00 2001 From: Thomas Wienecke Date: Tue, 25 Feb 2014 20:50:23 +0100 Subject: os_unix: Port mch_FullName and mch_isFullName to libuv. Basically just delete conditional use of fchdir, since the other called mch_* functions are already ported to libuv. --- src/ex_getln.c | 1 + src/memline.c | 1 + src/os/fs.c | 88 ++++++++++++++++++++++++++++++++++++ src/os/os.h | 2 + src/os_unix.c | 121 -------------------------------------------------- src/proto/os_unix.pro | 2 - src/syntax.c | 1 + 7 files changed, 93 insertions(+), 123 deletions(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index 9637b64f2d..83a0fd3dcc 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" /* * Variables shared between getcmdline(), redrawcmdline() and others. diff --git a/src/memline.c b/src/memline.c index 2f8fd69669..09818a5115 100644 --- a/src/memline.c +++ b/src/memline.c @@ -43,6 +43,7 @@ */ #include "vim.h" +#include "os/os.h" #ifndef UNIX /* it's in os_unix.h for Unix */ # include diff --git a/src/os/fs.c b/src/os/fs.c index e9a76c6b79..e9fe651b6b 100644 --- a/src/os/fs.c +++ b/src/os/fs.c @@ -37,3 +37,91 @@ int mch_dirname(char_u *buf, int len) } return OK; } + +/* + * Get absolute file name into "buf[len]". + * + * return FAIL for failure, OK for success + */ +int mch_FullName( + char_u *fname, + char_u *buf, + int len, + int force /* also expand when already absolute path */ + ) +{ + int l; + char_u olddir[MAXPATHL]; + char_u *p; + int retval = OK; + + + + /* expand it if forced or not an absolute path */ + if (force || !mch_isFullName(fname)) { + /* + * If the file name has a path, change to that directory for a moment, + * and then do the getwd() (and get back to where we were). + * This will get the correct path name with "../" things. + */ + if ((p = vim_strrchr(fname, '/')) != NULL) { + + /* Only change directory when we are sure we can return to where + * we are now. After doing "su" chdir(".") might not work. */ + if ((mch_dirname(olddir, MAXPATHL) == FAIL + || mch_chdir((char *)olddir) != 0)) { + p = NULL; /* can't get current dir: don't chdir */ + retval = FAIL; + } else { + /* The directory is copied into buf[], to be able to remove + * the file name without changing it (could be a string in + * read-only memory) */ + if (p - fname >= len) + retval = FAIL; + else { + vim_strncpy(buf, fname, p - fname); + if (mch_chdir((char *)buf)) + retval = FAIL; + else + fname = p + 1; + *buf = NUL; + } + } + } + if (mch_dirname(buf, len) == FAIL) { + retval = FAIL; + *buf = NUL; + } + if (p != NULL) { + l = mch_chdir((char *)olddir); + if (l != 0) + EMSG(_(e_prev_dir)); + } + + l = STRLEN(buf); + if (l >= len - 1) + retval = FAIL; /* no space for trailing "/" */ + else if (l > 0 && buf[l - 1] != '/' && *fname != NUL + && STRCMP(fname, ".") != 0) + STRCAT(buf, "/"); + } + + /* Catch file names which are too long. */ + if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len) + return FAIL; + + /* Do not append ".", "/dir/." is equal to "/dir". */ + if (STRCMP(fname, ".") != 0) + STRCAT(buf, fname); + + return OK; +} + +/* + * Return TRUE if "fname" does not depend on the current directory. + */ +int mch_isFullName(char_u *fname) +{ + return *fname == '/' || *fname == '~'; +} + diff --git a/src/os/os.h b/src/os/os.h index 099f53312f..9cf2116091 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -6,5 +6,7 @@ long_u mch_total_mem(int special); int mch_chdir(char *path); int mch_dirname(char_u *buf, int len); +int mch_FullName (char_u *fname, char_u *buf, int len, int force); +int mch_isFullName (char_u *fname); #endif diff --git a/src/os_unix.c b/src/os_unix.c index 2bfddafc6c..4bc4024abb 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1244,127 +1244,6 @@ static char * strerror(int err) } #endif -/* - * Get absolute file name into "buf[len]". - * - * return FAIL for failure, OK for success - */ -int mch_FullName( - char_u *fname, - char_u *buf, - int len, - int force /* also expand when already absolute path */ - ) -{ - int l; -#ifdef HAVE_FCHDIR - int fd = -1; - static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */ -#endif - char_u olddir[MAXPATHL]; - char_u *p; - int retval = OK; - - - - /* expand it if forced or not an absolute path */ - if (force || !mch_isFullName(fname)) { - /* - * If the file name has a path, change to that directory for a moment, - * and then do the getwd() (and get back to where we were). - * This will get the correct path name with "../" things. - */ - if ((p = vim_strrchr(fname, '/')) != NULL) { -#ifdef HAVE_FCHDIR - /* - * Use fchdir() if possible, it's said to be faster and more - * reliable. But on SunOS 4 it might not work. Check this by - * doing a fchdir() right now. - */ - if (!dont_fchdir) { - fd = open(".", O_RDONLY | O_EXTRA, 0); - if (fd >= 0 && fchdir(fd) < 0) { - close(fd); - fd = -1; - dont_fchdir = TRUE; /* don't try again */ - } - } -#endif - - /* Only change directory when we are sure we can return to where - * we are now. After doing "su" chdir(".") might not work. */ - if ( -#ifdef HAVE_FCHDIR - fd < 0 && -#endif - (mch_dirname(olddir, MAXPATHL) == FAIL - || mch_chdir((char *)olddir) != 0)) { - p = NULL; /* can't get current dir: don't chdir */ - retval = FAIL; - } else { - /* The directory is copied into buf[], to be able to remove - * the file name without changing it (could be a string in - * read-only memory) */ - if (p - fname >= len) - retval = FAIL; - else { - vim_strncpy(buf, fname, p - fname); - if (mch_chdir((char *)buf)) - retval = FAIL; - else - fname = p + 1; - *buf = NUL; - } - } - } - if (mch_dirname(buf, len) == FAIL) { - retval = FAIL; - *buf = NUL; - } - if (p != NULL) { -#ifdef HAVE_FCHDIR - if (fd >= 0) { - if (p_verbose >= 5) { - verbose_enter(); - MSG("fchdir() to previous dir"); - verbose_leave(); - } - l = fchdir(fd); - close(fd); - } else -#endif - l = mch_chdir((char *)olddir); - if (l != 0) - EMSG(_(e_prev_dir)); - } - - l = STRLEN(buf); - if (l >= len - 1) - retval = FAIL; /* no space for trailing "/" */ - else if (l > 0 && buf[l - 1] != '/' && *fname != NUL - && STRCMP(fname, ".") != 0) - STRCAT(buf, "/"); - } - - /* Catch file names which are too long. */ - if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len) - return FAIL; - - /* Do not append ".", "/dir/." is equal to "/dir". */ - if (STRCMP(fname, ".") != 0) - STRCAT(buf, fname); - - return OK; -} - -/* - * Return TRUE if "fname" does not depend on the current directory. - */ -int mch_isFullName(char_u *fname) -{ - return *fname == '/' || *fname == '~'; -} - #if defined(USE_FNAME_CASE) || defined(PROTO) /* * Set the case of the file name, if it already exists. This will cause the diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 64be80500c..3d03df1eaf 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -28,8 +28,6 @@ int mch_get_uname __ARGS((uid_t uid, char_u *s, int len)); void mch_get_host_name __ARGS((char_u *s, int len)); long mch_get_pid __ARGS((void)); void slash_adjust __ARGS((char_u *p)); -int mch_FullName __ARGS((char_u *fname, char_u *buf, int len, int force)); -int mch_isFullName __ARGS((char_u *fname)); void fname_case __ARGS((char_u *name, int len)); long mch_getperm __ARGS((char_u *name)); int mch_setperm __ARGS((char_u *name, long perm)); diff --git a/src/syntax.c b/src/syntax.c index c600b2f2a1..e576185b7d 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -12,6 +12,7 @@ */ #include "vim.h" +#include "os/os.h" /* * Structure that stores information about a highlight group. -- cgit From 82e0636e788f131d46451805f6c46e2d4f8496a9 Mon Sep 17 00:00:00 2001 From: Thomas Wienecke Date: Wed, 26 Feb 2014 00:36:01 +0100 Subject: Delete local function strerror and USE_GETCWD define. Both are useless after porting mch_dirname to libuv. --- src/os_unix.c | 16 ---------------- src/os_unix.h | 10 ---------- 2 files changed, 26 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 4bc4024abb..c3353d3724 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1228,22 +1228,6 @@ long mch_get_pid() { return (long)getpid(); } -#if !defined(HAVE_STRERROR) && defined(USE_GETCWD) -static char *strerror __ARGS((int)); - -static char * strerror(int err) -{ - extern int sys_nerr; - extern char *sys_errlist[]; - static char er[20]; - - if (err > 0 && err < sys_nerr) - return sys_errlist[err]; - sprintf(er, "Error %d", err); - return er; -} -#endif - #if defined(USE_FNAME_CASE) || defined(PROTO) /* * Set the case of the file name, if it already exists. This will cause the diff --git a/src/os_unix.h b/src/os_unix.h index 5ae7c38f88..3eb79e9a25 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -42,16 +42,6 @@ * Sun defines FILE on SunOS 4.x.x, Solaris has a typedef for FILE */ -/* - * Using getcwd() is preferred, because it checks for a buffer overflow. - * Don't use getcwd() on systems do use system("sh -c pwd"). There is an - * autoconf check for this. - * Use getcwd() anyway if getwd() isn't present. - */ -#if defined(HAVE_GETCWD) && !(defined(BAD_GETCWD) && defined(HAVE_GETWD)) -# define USE_GETCWD -#endif - #ifndef __ARGS /* The AIX VisualAge cc compiler defines __EXTENDED__ instead of __STDC__ * because it includes pre-ansi features. */ -- cgit From 0ef90c13b72b74928bfb3c183c7a5bd7240b51ad Mon Sep 17 00:00:00 2001 From: scott-linder Date: Tue, 25 Feb 2014 15:41:16 -0500 Subject: Removes 'proto' dir See #137 for the issue. Every header in the proto directory was: * Given include guards in the form #ifndef NEOVIM_FILENAME_H #define NEOVIM_FILENAME_H ... #endif /* NEOVIM_FILENAM_H */ * Renamed from *.pro -> *.h * Moved from src/proto/ to src/ This would have caused conficts with some existing headers in src/; rather than merge these conflicts now (which is a whole other can of worms involving multiple and conditional inclusion), any header in src/ with a conflicting name was renamed from *.h -> *_defs.h (which may or may not actually describe its purpose, the change is purely a namespacing issue). Once all of these changes were made a script was developed to determine what #includes needed to be added to each source file to describe its dependencies and allow it to compile; because the script is so short and I'll just list it here: #! /bin/bash cd $(dirname $0) # Scrapes `make` output for provided error messages and outputs #includes # needed to resolve them. # $1 : part of the clang error message between filename and identifier list_missing_includes() { for file_missing_pair in $(CC=clang make 2>&1 >/dev/null | sed -n "s/\/\(.*\.[hc]\).*$1.*'\(.*\)'.*/\1:\2/p"); do fields=(${file_missing_pair//:/ }) source_file=${fields[0]} missing_func=${fields[1]} # Try to find the declaration of the missing function. echo $(basename $source_file) \ \#include \"$(grep -r "\b$missing_func __ARGS" | sed -n "s/.*\/\(.*\)\:.*/\1/p")\" # Remove duplicates done | sort | uniq } echo "Finding missing function prototypes..." list_missing_includes "implicit declaration of function" echo "Finding missing identifier declarations..." list_missing_includes "use of undeclared identifier" Each list of required headers was added by hand in the following format: #include "vim.h" #include "*_defs.h" #include "filename.h" /* All other includes in same module here, in alphabetical order. */ /* All includes from other modules (e.g. "os/*.h") here in alphabetical * order. */ --- src/arabic.c | 2 + src/ascii.h | 5 + src/blowfish.c | 4 +- src/blowfish.h | 13 + src/buffer.c | 35 +- src/buffer.h | 84 ++++ src/charset.c | 8 + src/charset.h | 67 +++ src/diff.c | 21 +- src/diff.h | 33 ++ src/digraph.c | 13 +- src/digraph.h | 12 + src/edit.c | 32 ++ src/edit.h | 49 ++ src/eval.c | 46 +- src/eval.h | 153 ++++++ src/ex_cmds.c | 39 +- src/ex_cmds.h | 1267 +++-------------------------------------------- src/ex_cmds2.c | 27 +- src/ex_cmds2.h | 96 ++++ src/ex_cmds_defs.h | 1191 ++++++++++++++++++++++++++++++++++++++++++++ src/ex_docmd.c | 44 +- src/ex_docmd.h | 72 +++ src/ex_eval.c | 8 + src/ex_eval.h | 41 ++ src/ex_getln.c | 31 ++ src/ex_getln.h | 69 +++ src/farsi.c | 4 + src/farsi.h | 5 + src/fileio.c | 31 ++ src/fileio.h | 85 ++++ src/fold.c | 16 +- src/fold.h | 53 ++ src/getchar.c | 21 + src/getchar.h | 77 +++ src/globals.h | 7 + src/hangulin.c | 6 + src/hangulin.h | 12 + src/hardcopy.c | 19 +- src/hardcopy.h | 24 + src/hashtab.c | 5 +- src/hashtab.h | 18 + src/if_cscope.c | 17 +- src/if_cscope.h | 88 +--- src/if_cscope_defs.h | 72 +++ src/keymap.h | 2 +- src/main.c | 32 ++ src/main.h | 30 ++ src/mark.c | 18 + src/mark.h | 37 ++ src/mbyte.c | 11 + src/mbyte.h | 103 ++++ src/memfile.c | 8 + src/memfile.h | 21 + src/memline.c | 23 +- src/memline.h | 44 ++ src/menu.c | 9 + src/menu.h | 26 + src/message.c | 14 + src/message.h | 83 ++++ src/misc1.c | 31 +- src/misc1.h | 120 +++++ src/misc2.c | 22 + src/misc2.h | 136 +++++ src/move.c | 11 + src/move.h | 44 ++ src/normal.c | 33 ++ src/normal.h | 32 ++ src/ops.c | 25 + src/ops.h | 69 +++ src/option.c | 37 +- src/option.h | 845 +++---------------------------- src/option_defs.h | 768 ++++++++++++++++++++++++++++ src/os/fs.c | 1 + src/os_unix.c | 18 +- src/os_unix.h | 429 +++------------- src/os_unix_defs.h | 351 +++++++++++++ src/popupmnu.c | 11 +- src/popupmnu.h | 11 + src/proto.h | 75 --- src/proto/blowfish.pro | 10 - src/proto/buffer.pro | 81 --- src/proto/charset.pro | 64 --- src/proto/diff.pro | 30 -- src/proto/digraph.pro | 9 - src/proto/edit.pro | 46 -- src/proto/eval.pro | 150 ------ src/proto/ex_cmds.pro | 72 --- src/proto/ex_cmds2.pro | 93 ---- src/proto/ex_docmd.pro | 69 --- src/proto/ex_eval.pro | 38 -- src/proto/ex_getln.pro | 66 --- src/proto/fileio.pro | 82 --- src/proto/fold.pro | 50 -- src/proto/getchar.pro | 74 --- src/proto/hangulin.pro | 9 - src/proto/hardcopy.pro | 21 - src/proto/hashtab.pro | 15 - src/proto/if_cscope.pro | 13 - src/proto/main.pro | 27 - src/proto/mark.pro | 34 -- src/proto/mbyte.pro | 100 ---- src/proto/memfile.pro | 18 - src/proto/memline.pro | 41 -- src/proto/menu.pro | 23 - src/proto/message.pro | 80 --- src/proto/misc1.pro | 117 ----- src/proto/misc2.pro | 133 ----- src/proto/move.pro | 41 -- src/proto/normal.pro | 29 -- src/proto/ops.pro | 66 --- src/proto/option.pro | 74 --- src/proto/os_unix.pro | 75 --- src/proto/popupmnu.pro | 8 - src/proto/quickfix.pro | 33 -- src/proto/regexp.pro | 24 - src/proto/screen.pro | 66 --- src/proto/search.pro | 49 -- src/proto/sha256.pro | 12 - src/proto/spell.pro | 30 -- src/proto/syntax.pro | 58 --- src/proto/tag.pro | 15 - src/proto/term.pro | 65 --- src/proto/ui.pro | 67 --- src/proto/undo.pro | 31 -- src/proto/version.pro | 10 - src/proto/window.pro | 93 ---- src/quickfix.c | 28 ++ src/quickfix.h | 36 ++ src/regexp.c | 11 +- src/regexp.h | 179 +------ src/regexp_defs.h | 152 ++++++ src/regexp_nfa.c | 2 + src/screen.c | 31 ++ src/screen.h | 69 +++ src/search.c | 25 + src/search.h | 52 ++ src/sha256.c | 2 +- src/sha256.h | 15 + src/spell.c | 31 +- src/spell.h | 33 ++ src/structs.h | 4 +- src/syntax.c | 19 + src/syntax.h | 61 +++ src/tag.c | 27 + src/tag.h | 18 + src/term.c | 19 + src/term.h | 224 +++------ src/term_defs.h | 156 ++++++ src/ui.c | 16 +- src/ui.h | 70 +++ src/undo.c | 15 + src/undo.h | 34 ++ src/version.c | 9 +- src/version.h | 53 +- src/version_defs.h | 40 ++ src/vim.h | 16 +- src/window.c | 32 ++ src/window.h | 96 ++++ 159 files changed, 6277 insertions(+), 5261 deletions(-) create mode 100644 src/blowfish.h create mode 100644 src/buffer.h create mode 100644 src/charset.h create mode 100644 src/diff.h create mode 100644 src/digraph.h create mode 100644 src/edit.h create mode 100644 src/eval.h create mode 100644 src/ex_cmds2.h create mode 100644 src/ex_cmds_defs.h create mode 100644 src/ex_docmd.h create mode 100644 src/ex_eval.h create mode 100644 src/ex_getln.h create mode 100644 src/fileio.h create mode 100644 src/fold.h create mode 100644 src/getchar.h create mode 100644 src/hangulin.h create mode 100644 src/hardcopy.h create mode 100644 src/hashtab.h create mode 100644 src/if_cscope_defs.h create mode 100644 src/main.h create mode 100644 src/mark.h create mode 100644 src/mbyte.h create mode 100644 src/memfile.h create mode 100644 src/memline.h create mode 100644 src/menu.h create mode 100644 src/message.h create mode 100644 src/misc1.h create mode 100644 src/misc2.h create mode 100644 src/move.h create mode 100644 src/normal.h create mode 100644 src/ops.h create mode 100644 src/option_defs.h create mode 100644 src/os_unix_defs.h create mode 100644 src/popupmnu.h delete mode 100644 src/proto/blowfish.pro delete mode 100644 src/proto/buffer.pro delete mode 100644 src/proto/charset.pro delete mode 100644 src/proto/diff.pro delete mode 100644 src/proto/digraph.pro delete mode 100644 src/proto/edit.pro delete mode 100644 src/proto/eval.pro delete mode 100644 src/proto/ex_cmds.pro delete mode 100644 src/proto/ex_cmds2.pro delete mode 100644 src/proto/ex_docmd.pro delete mode 100644 src/proto/ex_eval.pro delete mode 100644 src/proto/ex_getln.pro delete mode 100644 src/proto/fileio.pro delete mode 100644 src/proto/fold.pro delete mode 100644 src/proto/getchar.pro delete mode 100644 src/proto/hangulin.pro delete mode 100644 src/proto/hardcopy.pro delete mode 100644 src/proto/hashtab.pro delete mode 100644 src/proto/if_cscope.pro delete mode 100644 src/proto/main.pro delete mode 100644 src/proto/mark.pro delete mode 100644 src/proto/mbyte.pro delete mode 100644 src/proto/memfile.pro delete mode 100644 src/proto/memline.pro delete mode 100644 src/proto/menu.pro delete mode 100644 src/proto/message.pro delete mode 100644 src/proto/misc1.pro delete mode 100644 src/proto/misc2.pro delete mode 100644 src/proto/move.pro delete mode 100644 src/proto/normal.pro delete mode 100644 src/proto/ops.pro delete mode 100644 src/proto/option.pro delete mode 100644 src/proto/os_unix.pro delete mode 100644 src/proto/popupmnu.pro delete mode 100644 src/proto/quickfix.pro delete mode 100644 src/proto/regexp.pro delete mode 100644 src/proto/screen.pro delete mode 100644 src/proto/search.pro delete mode 100644 src/proto/sha256.pro delete mode 100644 src/proto/spell.pro delete mode 100644 src/proto/syntax.pro delete mode 100644 src/proto/tag.pro delete mode 100644 src/proto/term.pro delete mode 100644 src/proto/ui.pro delete mode 100644 src/proto/undo.pro delete mode 100644 src/proto/version.pro delete mode 100644 src/proto/window.pro create mode 100644 src/quickfix.h create mode 100644 src/regexp_defs.h create mode 100644 src/screen.h create mode 100644 src/search.h create mode 100644 src/sha256.h create mode 100644 src/spell.h create mode 100644 src/syntax.h create mode 100644 src/tag.h create mode 100644 src/term_defs.h create mode 100644 src/ui.h create mode 100644 src/undo.h create mode 100644 src/version_defs.h create mode 100644 src/window.h diff --git a/src/arabic.c b/src/arabic.c index 3aec35aba3..5359b83a43 100644 --- a/src/arabic.c +++ b/src/arabic.c @@ -7,6 +7,8 @@ * See README.txt for an overview of the Vim source code. */ +#include "arabic.h" + /* * arabic.c: functions for Arabic language * diff --git a/src/ascii.h b/src/ascii.h index 0904521ccf..50ca04f443 100644 --- a/src/ascii.h +++ b/src/ascii.h @@ -6,6 +6,9 @@ * Do ":help credits" in Vim to see a list of people who contributed. */ +#ifndef NEOVIM_ASCII_H +#define NEOVIM_ASCII_H + /* * Definitions of various common control characters. * For EBCDIC we have to use different values. @@ -94,3 +97,5 @@ # define PATHSEP '/' # define PATHSEPSTR "/" #endif + +#endif /* NEOVIM_ASCII_H */ diff --git a/src/blowfish.c b/src/blowfish.c index df820d1152..d7074bd42c 100644 --- a/src/blowfish.c +++ b/src/blowfish.c @@ -12,7 +12,9 @@ */ #include "vim.h" - +#include "blowfish.h" +#include "message.h" +#include "sha256.h" #define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0])) diff --git a/src/blowfish.h b/src/blowfish.h new file mode 100644 index 0000000000..d4d8f36429 --- /dev/null +++ b/src/blowfish.h @@ -0,0 +1,13 @@ +#ifndef NEOVIM_BLOWFISH_H +#define NEOVIM_BLOWFISH_H +/* blowfish.c */ +void bf_key_init __ARGS((char_u *password, char_u *salt, int salt_len)); +void bf_ofb_init __ARGS((char_u *iv, int iv_len)); +void bf_crypt_encode __ARGS((char_u *from, size_t len, char_u *to)); +void bf_crypt_decode __ARGS((char_u *ptr, long len)); +void bf_crypt_init_keys __ARGS((char_u *passwd)); +void bf_crypt_save __ARGS((void)); +void bf_crypt_restore __ARGS((void)); +int blowfish_self_test __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_BLOWFISH_H */ diff --git a/src/buffer.c b/src/buffer.c index de1af62307..401dc40333 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -26,6 +26,39 @@ */ #include "vim.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "digraph.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_cmds.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "spell.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" static char_u *buflist_match __ARGS((regprog_T *prog, buf_T *buf)); # define HAVE_BUFLIST_MATCH @@ -4111,7 +4144,7 @@ void do_modelines(int flags) --entered; } -#include "version.h" /* for version number */ +#include "version_defs.h" /* for version number */ /* * chk_modeline() - check a single line for a mode string diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000000..3ca525612d --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,84 @@ +#ifndef NEOVIM_BUFFER_H +#define NEOVIM_BUFFER_H +/* buffer.c */ +int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags)); +int buf_valid __ARGS((buf_T *buf)); +void close_buffer __ARGS((win_T *win, buf_T *buf, int action, int abort_if_last)); +void buf_clear_file __ARGS((buf_T *buf)); +void buf_freeall __ARGS((buf_T *buf, int flags)); +void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count)); +void handle_swap_exists __ARGS((buf_T *old_curbuf)); +char_u *do_bufdel __ARGS((int command, char_u *arg, int addr_count, + int start_bnr, int end_bnr, + int forceit)); +int do_buffer __ARGS((int action, int start, int dir, int count, int forceit)); +void set_curbuf __ARGS((buf_T *buf, int action)); +void enter_buffer __ARGS((buf_T *buf)); +void do_autochdir __ARGS((void)); +buf_T *buflist_new __ARGS((char_u *ffname, char_u *sfname, linenr_T lnum, + int flags)); +void free_buf_options __ARGS((buf_T *buf, int free_p_ff)); +int buflist_getfile __ARGS((int n, linenr_T lnum, int options, int forceit)); +void buflist_getfpos __ARGS((void)); +buf_T *buflist_findname_exp __ARGS((char_u *fname)); +buf_T *buflist_findname __ARGS((char_u *ffname)); +int buflist_findpat __ARGS((char_u *pattern, char_u *pattern_end, int unlisted, + int diffmode, + int curtab_only)); +int ExpandBufnames __ARGS((char_u *pat, int *num_file, char_u ***file, + int options)); +buf_T *buflist_findnr __ARGS((int nr)); +char_u *buflist_nr2name __ARGS((int n, int fullname, int helptail)); +void get_winopts __ARGS((buf_T *buf)); +pos_T *buflist_findfpos __ARGS((buf_T *buf)); +linenr_T buflist_findlnum __ARGS((buf_T *buf)); +void buflist_list __ARGS((exarg_T *eap)); +int buflist_name_nr __ARGS((int fnum, char_u **fname, linenr_T *lnum)); +int setfname __ARGS((buf_T *buf, char_u *ffname, char_u *sfname, int message)); +void buf_set_name __ARGS((int fnum, char_u *name)); +void buf_name_changed __ARGS((buf_T *buf)); +buf_T *setaltfname __ARGS((char_u *ffname, char_u *sfname, linenr_T lnum)); +char_u *getaltfname __ARGS((int errmsg)); +int buflist_add __ARGS((char_u *fname, int flags)); +void buflist_slash_adjust __ARGS((void)); +void buflist_altfpos __ARGS((win_T *win)); +int otherfile __ARGS((char_u *ffname)); +void buf_setino __ARGS((buf_T *buf)); +void fileinfo __ARGS((int fullname, int shorthelp, int dont_truncate)); +void col_print __ARGS((char_u *buf, size_t buflen, int col, int vcol)); +void maketitle __ARGS((void)); +void resettitle __ARGS((void)); +void free_titles __ARGS((void)); +int build_stl_str_hl __ARGS((win_T *wp, char_u *out, size_t outlen, char_u *fmt, + int use_sandbox, int fillchar, int maxwidth, + struct stl_hlrec *hltab, + struct stl_hlrec *tabtab)); +void get_rel_pos __ARGS((win_T *wp, char_u *buf, int buflen)); +char_u *fix_fname __ARGS((char_u *fname)); +void fname_expand __ARGS((buf_T *buf, char_u **ffname, char_u **sfname)); +char_u *alist_name __ARGS((aentry_T *aep)); +void do_arg_all __ARGS((int count, int forceit, int keep_tabs)); +void ex_buffer_all __ARGS((exarg_T *eap)); +void do_modelines __ARGS((int flags)); +int read_viminfo_bufferlist __ARGS((vir_T *virp, int writing)); +void write_viminfo_bufferlist __ARGS((FILE *fp)); +char_u *buf_spname __ARGS((buf_T *buf)); +int find_win_for_buf __ARGS((buf_T *buf, win_T **wp, tabpage_T **tp)); +void buf_addsign __ARGS((buf_T *buf, int id, linenr_T lnum, int typenr)); +linenr_T buf_change_sign_type __ARGS((buf_T *buf, int markId, int typenr)); +int buf_getsigntype __ARGS((buf_T *buf, linenr_T lnum, int type)); +linenr_T buf_delsign __ARGS((buf_T *buf, int id)); +int buf_findsign __ARGS((buf_T *buf, int id)); +int buf_findsign_id __ARGS((buf_T *buf, linenr_T lnum)); +int buf_findsigntype_id __ARGS((buf_T *buf, linenr_T lnum, int typenr)); +int buf_signcount __ARGS((buf_T *buf, linenr_T lnum)); +void buf_delete_signs __ARGS((buf_T *buf)); +void buf_delete_all_signs __ARGS((void)); +void sign_list_placed __ARGS((buf_T *rbuf)); +void sign_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, + long amount_after)); +void set_buflisted __ARGS((int on)); +int buf_contents_changed __ARGS((buf_T *buf)); +void wipe_buffer __ARGS((buf_T *buf, int aucmd)); +/* vim: set ft=c : */ +#endif /* NEOVIM_BUFFER_H */ diff --git a/src/charset.c b/src/charset.c index 1cc1a79a6f..271df2c7f4 100644 --- a/src/charset.c +++ b/src/charset.c @@ -8,6 +8,14 @@ */ #include "vim.h" +#include "charset.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "os_unix.h" static int win_chartabsize __ARGS((win_T *wp, char_u *p, colnr_T col)); diff --git a/src/charset.h b/src/charset.h new file mode 100644 index 0000000000..d680522880 --- /dev/null +++ b/src/charset.h @@ -0,0 +1,67 @@ +#ifndef NEOVIM_CHARSET_H +#define NEOVIM_CHARSET_H +/* charset.c */ +int init_chartab __ARGS((void)); +int buf_init_chartab __ARGS((buf_T *buf, int global)); +void trans_characters __ARGS((char_u *buf, int bufsize)); +char_u *transstr __ARGS((char_u *s)); +char_u *str_foldcase __ARGS((char_u *str, int orglen, char_u *buf, int buflen)); +char_u *transchar __ARGS((int c)); +char_u *transchar_byte __ARGS((int c)); +void transchar_nonprint __ARGS((char_u *buf, int c)); +void transchar_hex __ARGS((char_u *buf, int c)); +int byte2cells __ARGS((int b)); +int char2cells __ARGS((int c)); +int ptr2cells __ARGS((char_u *p)); +int vim_strsize __ARGS((char_u *s)); +int vim_strnsize __ARGS((char_u *s, int len)); +int chartabsize __ARGS((char_u *p, colnr_T col)); +int linetabsize __ARGS((char_u *s)); +int linetabsize_col __ARGS((int startcol, char_u *s)); +int win_linetabsize __ARGS((win_T *wp, char_u *p, colnr_T len)); +int vim_isIDc __ARGS((int c)); +int vim_iswordc __ARGS((int c)); +int vim_iswordc_buf __ARGS((int c, buf_T *buf)); +int vim_iswordp __ARGS((char_u *p)); +int vim_iswordp_buf __ARGS((char_u *p, buf_T *buf)); +int vim_isfilec __ARGS((int c)); +int vim_isfilec_or_wc __ARGS((int c)); +int vim_isprintc __ARGS((int c)); +int vim_isprintc_strict __ARGS((int c)); +int lbr_chartabsize __ARGS((unsigned char *s, colnr_T col)); +int lbr_chartabsize_adv __ARGS((char_u **s, colnr_T col)); +int win_lbr_chartabsize __ARGS((win_T *wp, char_u *s, colnr_T col, int *headp)); +int in_win_border __ARGS((win_T *wp, colnr_T vcol)); +void getvcol __ARGS((win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, + colnr_T *end)); +colnr_T getvcol_nolist __ARGS((pos_T *posp)); +void getvvcol __ARGS((win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, + colnr_T *end)); +void getvcols __ARGS((win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, + colnr_T *right)); +char_u *skipwhite __ARGS((char_u *q)); +char_u *skipdigits __ARGS((char_u *q)); +char_u *skiphex __ARGS((char_u *q)); +char_u *skiptodigit __ARGS((char_u *q)); +char_u *skiptohex __ARGS((char_u *q)); +int vim_isdigit __ARGS((int c)); +int vim_isxdigit __ARGS((int c)); +int vim_islower __ARGS((int c)); +int vim_isupper __ARGS((int c)); +int vim_toupper __ARGS((int c)); +int vim_tolower __ARGS((int c)); +char_u *skiptowhite __ARGS((char_u *p)); +char_u *skiptowhite_esc __ARGS((char_u *p)); +long getdigits __ARGS((char_u **pp)); +int vim_isblankline __ARGS((char_u *lbuf)); +void vim_str2nr __ARGS((char_u *start, int *hexp, int *len, int dooct, + int dohex, long *nptr, + unsigned long *unptr)); +int hex2nr __ARGS((int c)); +int hexhex2nr __ARGS((char_u *p)); +int rem_backslash __ARGS((char_u *str)); +void backslash_halve __ARGS((char_u *p)); +char_u *backslash_halve_save __ARGS((char_u *p)); +void ebcdic2ascii __ARGS((char_u *buffer, int len)); +/* vim: set ft=c : */ +#endif /* NEOVIM_CHARSET_H */ diff --git a/src/diff.c b/src/diff.c index 166b40ee0c..626271a7b5 100644 --- a/src/diff.c +++ b/src/diff.c @@ -12,9 +12,28 @@ */ #include "vim.h" +#include "diff.h" +#include "buffer.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_docmd.h" +#include "fileio.h" +#include "fold.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "screen.h" +#include "undo.h" +#include "window.h" #include "os/os.h" - static int diff_busy = FALSE; /* ex_diffgetput() is busy */ /* flags obtained from the 'diffopt' option */ diff --git a/src/diff.h b/src/diff.h new file mode 100644 index 0000000000..5a2d32204e --- /dev/null +++ b/src/diff.h @@ -0,0 +1,33 @@ +#ifndef NEOVIM_DIFF_H +#define NEOVIM_DIFF_H +/* diff.c */ +void diff_buf_delete __ARGS((buf_T *buf)); +void diff_buf_adjust __ARGS((win_T *win)); +void diff_buf_add __ARGS((buf_T *buf)); +void diff_invalidate __ARGS((buf_T *buf)); +void diff_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, + long amount_after)); +void ex_diffupdate __ARGS((exarg_T *eap)); +void ex_diffpatch __ARGS((exarg_T *eap)); +void ex_diffsplit __ARGS((exarg_T *eap)); +void ex_diffthis __ARGS((exarg_T *eap)); +void diff_win_options __ARGS((win_T *wp, int addbuf)); +void ex_diffoff __ARGS((exarg_T *eap)); +void diff_clear __ARGS((tabpage_T *tp)); +int diff_check __ARGS((win_T *wp, linenr_T lnum)); +int diff_check_fill __ARGS((win_T *wp, linenr_T lnum)); +void diff_set_topline __ARGS((win_T *fromwin, win_T *towin)); +int diffopt_changed __ARGS((void)); +int diffopt_horizontal __ARGS((void)); +int diff_find_change __ARGS((win_T *wp, linenr_T lnum, int *startp, int *endp)); +int diff_infold __ARGS((win_T *wp, linenr_T lnum)); +void nv_diffgetput __ARGS((int put)); +void ex_diffgetput __ARGS((exarg_T *eap)); +int diff_mode_buf __ARGS((buf_T *buf)); +int diff_move_to __ARGS((int dir, long count)); +linenr_T diff_get_corresponding_line __ARGS((buf_T *buf1, linenr_T lnum1, + buf_T *buf2, + linenr_T lnum3)); +linenr_T diff_lnum_win __ARGS((linenr_T lnum, win_T *wp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_DIFF_H */ diff --git a/src/digraph.c b/src/digraph.c index 4a1e1e4d04..9a58058fde 100644 --- a/src/digraph.c +++ b/src/digraph.c @@ -12,7 +12,18 @@ */ #include "vim.h" - +#include "digraph.h" +#include "charset.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "getchar.h" +#include "mbyte.h" +#include "message.h" +#include "misc2.h" +#include "normal.h" +#include "screen.h" +#include "ui.h" typedef int result_T; diff --git a/src/digraph.h b/src/digraph.h new file mode 100644 index 0000000000..c74e428979 --- /dev/null +++ b/src/digraph.h @@ -0,0 +1,12 @@ +#ifndef NEOVIM_DIGRAPH_H +#define NEOVIM_DIGRAPH_H +/* digraph.c */ +int do_digraph __ARGS((int c)); +int get_digraph __ARGS((int cmdline)); +int getdigraph __ARGS((int char1, int char2, int meta_char)); +void putdigraph __ARGS((char_u *str)); +void listdigraphs __ARGS((void)); +char_u *keymap_init __ARGS((void)); +void ex_loadkeymap __ARGS((exarg_T *eap)); +/* vim: set ft=c : */ +#endif /* NEOVIM_DIGRAPH_H */ diff --git a/src/edit.c b/src/edit.c index eec47b3637..6ac6565d40 100644 --- a/src/edit.c +++ b/src/edit.c @@ -12,6 +12,38 @@ */ #include "vim.h" +#include "edit.h" +#include "buffer.h" +#include "charset.h" +#include "digraph.h" +#include "eval.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "popupmnu.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" /* * definitions used for CTRL-X submode diff --git a/src/edit.h b/src/edit.h new file mode 100644 index 0000000000..aa2b72d93b --- /dev/null +++ b/src/edit.h @@ -0,0 +1,49 @@ +#ifndef NEOVIM_EDIT_H +#define NEOVIM_EDIT_H +/* edit.c */ +int edit __ARGS((int cmdchar, int startln, long count)); +void edit_putchar __ARGS((int c, int highlight)); +void edit_unputchar __ARGS((void)); +void display_dollar __ARGS((colnr_T col)); +void change_indent __ARGS((int type, int amount, int round, int replaced, + int call_changed_bytes)); +void truncate_spaces __ARGS((char_u *line)); +void backspace_until_column __ARGS((int col)); +int vim_is_ctrl_x_key __ARGS((int c)); +int ins_compl_add_infercase __ARGS((char_u *str, int len, int icase, char_u * + fname, int dir, + int flags)); +void set_completion __ARGS((colnr_T startcol, list_T *list)); +void ins_compl_show_pum __ARGS((void)); +char_u *find_word_start __ARGS((char_u *ptr)); +char_u *find_word_end __ARGS((char_u *ptr)); +int ins_compl_active __ARGS((void)); +int ins_compl_add_tv __ARGS((typval_T *tv, int dir)); +void ins_compl_check_keys __ARGS((int frequency)); +int get_literal __ARGS((void)); +void insertchar __ARGS((int c, int flags, int second_indent)); +void auto_format __ARGS((int trailblank, int prev_line)); +int comp_textwidth __ARGS((int ff)); +int stop_arrow __ARGS((void)); +void set_last_insert __ARGS((int c)); +void free_last_insert __ARGS((void)); +char_u *add_char2buf __ARGS((int c, char_u *s)); +void beginline __ARGS((int flags)); +int oneright __ARGS((void)); +int oneleft __ARGS((void)); +int cursor_up __ARGS((long n, int upd_topline)); +int cursor_down __ARGS((long n, int upd_topline)); +int stuff_inserted __ARGS((int c, long count, int no_esc)); +char_u *get_last_insert __ARGS((void)); +char_u *get_last_insert_save __ARGS((void)); +void replace_push __ARGS((int c)); +int replace_push_mb __ARGS((char_u *p)); +void fixthisline __ARGS((int (*get_the_indent)(void))); +void fix_indent __ARGS((void)); +int in_cinkeys __ARGS((int keytyped, int when, int line_is_empty)); +int hkmap __ARGS((int c)); +void ins_scroll __ARGS((void)); +void ins_horscroll __ARGS((void)); +int ins_copychar __ARGS((linenr_T lnum)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EDIT_H */ diff --git a/src/eval.c b/src/eval.c index 51519bb899..4d120c82ce 100644 --- a/src/eval.c +++ b/src/eval.c @@ -12,12 +12,48 @@ */ #include "vim.h" +#include "eval.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "if_cscope.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "popupmnu.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "sha256.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "version.h" +#include "window.h" #include "os/os.h" - - - - #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) # include #endif @@ -264,7 +300,7 @@ typedef struct { * The reason to use this table anyway is for very quick access to the * variables with the VV_ defines. */ -#include "version.h" +#include "version_defs.h" /* values for vv_flags: */ #define VV_COMPAT 1 /* compatible, also used without "v:" */ diff --git a/src/eval.h b/src/eval.h new file mode 100644 index 0000000000..d63ea3dd8b --- /dev/null +++ b/src/eval.h @@ -0,0 +1,153 @@ +#ifndef NEOVIM_EVAL_H +#define NEOVIM_EVAL_H +/* eval.c */ +void eval_init __ARGS((void)); +void eval_clear __ARGS((void)); +char_u *func_name __ARGS((void *cookie)); +linenr_T *func_breakpoint __ARGS((void *cookie)); +int *func_dbg_tick __ARGS((void *cookie)); +int func_level __ARGS((void *cookie)); +int current_func_returned __ARGS((void)); +void set_internal_string_var __ARGS((char_u *name, char_u *value)); +int var_redir_start __ARGS((char_u *name, int append)); +void var_redir_str __ARGS((char_u *value, int value_len)); +void var_redir_stop __ARGS((void)); +int eval_charconvert __ARGS((char_u *enc_from, char_u *enc_to, char_u * + fname_from, + char_u *fname_to)); +int eval_printexpr __ARGS((char_u *fname, char_u *args)); +void eval_diff __ARGS((char_u *origfile, char_u *newfile, char_u *outfile)); +void eval_patch __ARGS((char_u *origfile, char_u *difffile, char_u *outfile)); +int eval_to_bool __ARGS((char_u *arg, int *error, char_u **nextcmd, int skip)); +char_u *eval_to_string_skip __ARGS((char_u *arg, char_u **nextcmd, int skip)); +int skip_expr __ARGS((char_u **pp)); +char_u *eval_to_string __ARGS((char_u *arg, char_u **nextcmd, int convert)); +char_u *eval_to_string_safe __ARGS((char_u *arg, char_u **nextcmd, + int use_sandbox)); +int eval_to_number __ARGS((char_u *expr)); +list_T *eval_spell_expr __ARGS((char_u *badword, char_u *expr)); +int get_spellword __ARGS((list_T *list, char_u **pp)); +typval_T *eval_expr __ARGS((char_u *arg, char_u **nextcmd)); +int call_vim_function __ARGS((char_u *func, int argc, char_u **argv, int safe, + int str_arg_only, + typval_T *rettv)); +long call_func_retnr __ARGS((char_u *func, int argc, char_u **argv, int safe)); +void *call_func_retstr __ARGS((char_u *func, int argc, char_u **argv, int safe)); +void *call_func_retlist __ARGS((char_u *func, int argc, char_u **argv, int safe)); +void *save_funccal __ARGS((void)); +void restore_funccal __ARGS((void *vfc)); +void prof_child_enter __ARGS((proftime_T *tm)); +void prof_child_exit __ARGS((proftime_T *tm)); +int eval_foldexpr __ARGS((char_u *arg, int *cp)); +void ex_let __ARGS((exarg_T *eap)); +void list_add_watch __ARGS((list_T *l, listwatch_T *lw)); +void list_rem_watch __ARGS((list_T *l, listwatch_T *lwrem)); +void *eval_for_line __ARGS((char_u *arg, int *errp, char_u **nextcmdp, int skip)); +int next_for_item __ARGS((void *fi_void, char_u *arg)); +void free_for_info __ARGS((void *fi_void)); +void set_context_for_expression __ARGS((expand_T *xp, char_u *arg, + cmdidx_T cmdidx)); +void ex_call __ARGS((exarg_T *eap)); +void ex_unlet __ARGS((exarg_T *eap)); +void ex_lockvar __ARGS((exarg_T *eap)); +int do_unlet __ARGS((char_u *name, int forceit)); +void del_menutrans_vars __ARGS((void)); +char_u *get_user_var_name __ARGS((expand_T *xp, int idx)); +list_T *list_alloc __ARGS((void)); +void list_unref __ARGS((list_T *l)); +void list_free __ARGS((list_T *l, int recurse)); +listitem_T *listitem_alloc __ARGS((void)); +void listitem_free __ARGS((listitem_T *item)); +void listitem_remove __ARGS((list_T *l, listitem_T *item)); +dictitem_T *dict_lookup __ARGS((hashitem_T *hi)); +listitem_T *list_find __ARGS((list_T *l, long n)); +char_u *list_find_str __ARGS((list_T *l, long idx)); +void list_append __ARGS((list_T *l, listitem_T *item)); +int list_append_tv __ARGS((list_T *l, typval_T *tv)); +int list_append_dict __ARGS((list_T *list, dict_T *dict)); +int list_append_string __ARGS((list_T *l, char_u *str, int len)); +int list_insert_tv __ARGS((list_T *l, typval_T *tv, listitem_T *item)); +void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); +void list_insert __ARGS((list_T *l, listitem_T *ni, listitem_T *item)); +int garbage_collect __ARGS((void)); +void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); +void set_ref_in_list __ARGS((list_T *l, int copyID)); +void set_ref_in_item __ARGS((typval_T *tv, int copyID)); +dict_T *dict_alloc __ARGS((void)); +void dict_unref __ARGS((dict_T *d)); +void dict_free __ARGS((dict_T *d, int recurse)); +dictitem_T *dictitem_alloc __ARGS((char_u *key)); +void dictitem_free __ARGS((dictitem_T *item)); +int dict_add __ARGS((dict_T *d, dictitem_T *item)); +int dict_add_nr_str __ARGS((dict_T *d, char *key, long nr, char_u *str)); +int dict_add_list __ARGS((dict_T *d, char *key, list_T *list)); +dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len)); +char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save)); +long get_dict_number __ARGS((dict_T *d, char_u *key)); +char_u *get_function_name __ARGS((expand_T *xp, int idx)); +char_u *get_expr_name __ARGS((expand_T *xp, int idx)); +int func_call __ARGS((char_u *name, typval_T *args, dict_T *selfdict, + typval_T *rettv)); +void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action)); +void mzscheme_call_vim __ARGS((char_u *name, typval_T *args, typval_T *rettv)); +float_T vim_round __ARGS((float_T f)); +long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir, + char_u *skip, int flags, pos_T *match_pos, + linenr_T lnum_stop, + long time_limit)); +void set_vim_var_nr __ARGS((int idx, long val)); +long get_vim_var_nr __ARGS((int idx)); +char_u *get_vim_var_str __ARGS((int idx)); +list_T *get_vim_var_list __ARGS((int idx)); +void set_vim_var_char __ARGS((int c)); +void set_vcount __ARGS((long count, long count1, int set_prevcount)); +void set_vim_var_string __ARGS((int idx, char_u *val, int len)); +void set_vim_var_list __ARGS((int idx, list_T *val)); +void set_reg_var __ARGS((int c)); +char_u *v_exception __ARGS((char_u *oldval)); +char_u *v_throwpoint __ARGS((char_u *oldval)); +char_u *set_cmdarg __ARGS((exarg_T *eap, char_u *oldarg)); +void free_tv __ARGS((typval_T *varp)); +void clear_tv __ARGS((typval_T *varp)); +long get_tv_number_chk __ARGS((typval_T *varp, int *denote)); +char_u *get_tv_string_chk __ARGS((typval_T *varp)); +char_u *get_var_value __ARGS((char_u *name)); +void new_script_vars __ARGS((scid_T id)); +void init_var_dict __ARGS((dict_T *dict, dictitem_T *dict_var, int scope)); +void unref_var_dict __ARGS((dict_T *dict)); +void vars_clear __ARGS((hashtab_T *ht)); +void copy_tv __ARGS((typval_T *from, typval_T *to)); +void ex_echo __ARGS((exarg_T *eap)); +void ex_echohl __ARGS((exarg_T *eap)); +void ex_execute __ARGS((exarg_T *eap)); +void ex_function __ARGS((exarg_T *eap)); +void free_all_functions __ARGS((void)); +int translated_function_exists __ARGS((char_u *name)); +char_u *get_expanded_name __ARGS((char_u *name, int check)); +void func_dump_profile __ARGS((FILE *fd)); +char_u *get_user_func_name __ARGS((expand_T *xp, int idx)); +void ex_delfunction __ARGS((exarg_T *eap)); +void func_unref __ARGS((char_u *name)); +void func_ref __ARGS((char_u *name)); +void ex_return __ARGS((exarg_T *eap)); +int do_return __ARGS((exarg_T *eap, int reanimate, int is_cmd, void *rettv)); +void discard_pending_return __ARGS((void *rettv)); +char_u *get_return_cmd __ARGS((void *rettv)); +char_u *get_func_line __ARGS((int c, void *cookie, int indent)); +void func_line_start __ARGS((void *cookie)); +void func_line_exec __ARGS((void *cookie)); +void func_line_end __ARGS((void *cookie)); +int func_has_ended __ARGS((void *cookie)); +int func_has_abort __ARGS((void *cookie)); +int read_viminfo_varlist __ARGS((vir_T *virp, int writing)); +void write_viminfo_varlist __ARGS((FILE *fp)); +int store_session_globals __ARGS((FILE *fd)); +void last_set_msg __ARGS((scid_T scriptID)); +void ex_oldfiles __ARGS((exarg_T *eap)); +int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u * + *bufp, + int *fnamelen)); +char_u *do_string_sub __ARGS((char_u *str, char_u *pat, char_u *sub, + char_u *flags)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EVAL_H */ diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 2570335f66..5a28167ddb 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -12,7 +12,44 @@ */ #include "vim.h" -#include "version.h" +#include "version_defs.h" +#include "ex_cmds.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "digraph.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" static int linelen __ARGS((int *has_tab)); static void do_filter __ARGS((linenr_T line1, linenr_T line2, exarg_T *eap, diff --git a/src/ex_cmds.h b/src/ex_cmds.h index a560789fef..4bb11ea20c 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1,1191 +1,76 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * This file defines the Ex commands. - * When DO_DECLARE_EXCMD is defined, the table with ex command names and - * options results. - * When DO_DECLARE_EXCMD is NOT defined, the enum with all the Ex commands - * results. - * This clever trick was invented by Ron Aaron. - */ - -/* - * When adding an Ex command: - * 1. Add an entry in the table below. Keep it sorted on the shortest - * version of the command name that works. If it doesn't start with a - * lower case letter, add it at the end. - * 2. Add a "case: CMD_xxx" in the big switch in ex_docmd.c. - * 3. Add an entry in the index for Ex commands at ":help ex-cmd-index". - * 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and - * long name of the command. - */ - -#ifdef RANGE -# undef RANGE /* SASC on Amiga defines it */ -#endif - -#define RANGE 0x001 /* allow a linespecs */ -#define BANG 0x002 /* allow a ! after the command name */ -#define EXTRA 0x004 /* allow extra args after command name */ -#define XFILE 0x008 /* expand wildcards in extra part */ -#define NOSPC 0x010 /* no spaces allowed in the extra part */ -#define DFLALL 0x020 /* default file range is 1,$ */ -#define WHOLEFOLD 0x040 /* extend range to include whole fold also - when less than two numbers given */ -#define NEEDARG 0x080 /* argument required */ -#define TRLBAR 0x100 /* check for trailing vertical bar */ -#define REGSTR 0x200 /* allow "x for register designation */ -#define COUNT 0x400 /* allow count in argument, after command */ -#define NOTRLCOM 0x800 /* no trailing comment allowed */ -#define ZEROR 0x1000 /* zero line number allowed */ -#define USECTRLV 0x2000 /* do not remove CTRL-V from argument */ -#define NOTADR 0x4000 /* number before command is not an address */ -#define EDITCMD 0x8000 /* allow "+command" argument */ -#define BUFNAME 0x10000L /* accepts buffer name */ -#define BUFUNL 0x20000L /* accepts unlisted buffer too */ -#define ARGOPT 0x40000L /* allow "++opt=val" argument */ -#define SBOXOK 0x80000L /* allowed in the sandbox */ -#define CMDWIN 0x100000L /* allowed in cmdline window */ -#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */ -#define EXFLAGS 0x400000L /* allow flags after count in argument */ -#define FILES (XFILE | EXTRA) /* multiple extra files allowed */ -#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */ -#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */ - -#ifndef DO_DECLARE_EXCMD -typedef struct exarg exarg_T; -#endif - -/* - * This array maps ex command names to command codes. - * The order in which command names are listed below is significant -- - * ambiguous abbreviations are always resolved to be the first possible match - * (e.g. "r" is taken to mean "read", not "rewind", because "read" comes - * before "rewind"). - * Not supported commands are included to avoid ambiguities. - */ -#ifdef EX -# undef EX /* just in case */ -#endif -#ifdef DO_DECLARE_EXCMD -# define EX(a, b, c, d) {(char_u *)b, c, (long_u)(d)} - -typedef void (*ex_func_T) __ARGS ((exarg_T *eap)); - -static struct cmdname { - char_u *cmd_name; /* name of the command */ - ex_func_T cmd_func; /* function for this command */ - long_u cmd_argt; /* flags declared above */ -} -cmdnames[] = -#else -# define EX(a, b, c, d) a -enum CMD_index -#endif -{ - EX(CMD_append, "append", ex_append, - BANG|RANGE|ZEROR|TRLBAR|CMDWIN|MODIFY), - EX(CMD_abbreviate, "abbreviate", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_abclear, "abclear", ex_abclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_aboveleft, "aboveleft", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_all, "all", ex_all, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_amenu, "amenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_anoremenu, "anoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_args, "args", ex_args, - BANG|FILES|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_argadd, "argadd", ex_argadd, - BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|TRLBAR), - EX(CMD_argdelete, "argdelete", ex_argdelete, - BANG|RANGE|NOTADR|FILES|TRLBAR), - EX(CMD_argdo, "argdo", ex_listdo, - BANG|NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_argedit, "argedit", ex_argedit, - BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_argglobal, "argglobal", ex_args, - BANG|FILES|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_arglocal, "arglocal", ex_args, - BANG|FILES|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_argument, "argument", ex_argument, - BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_ascii, "ascii", do_ascii, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_autocmd, "autocmd", ex_autocmd, - BANG|EXTRA|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_augroup, "augroup", ex_autocmd, - BANG|WORD1|TRLBAR|CMDWIN), - EX(CMD_aunmenu, "aunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_buffer, "buffer", ex_buffer, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), - EX(CMD_bNext, "bNext", ex_bprevious, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_ball, "ball", ex_buffer_all, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_badd, "badd", ex_edit, - NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN), - EX(CMD_bdelete, "bdelete", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), - EX(CMD_behave, "behave", ex_behave, - NEEDARG|WORD1|TRLBAR|CMDWIN), - EX(CMD_belowright, "belowright", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_bfirst, "bfirst", ex_brewind, - BANG|RANGE|NOTADR|TRLBAR), - EX(CMD_blast, "blast", ex_blast, - BANG|RANGE|NOTADR|TRLBAR), - EX(CMD_bmodified, "bmodified", ex_bmodified, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_bnext, "bnext", ex_bnext, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_botright, "botright", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_bprevious, "bprevious", ex_bprevious, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_brewind, "brewind", ex_brewind, - BANG|RANGE|NOTADR|TRLBAR), - EX(CMD_break, "break", ex_break, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_breakadd, "breakadd", ex_breakadd, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_breakdel, "breakdel", ex_breakdel, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_breaklist, "breaklist", ex_breaklist, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_browse, "browse", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM|CMDWIN), - EX(CMD_buffers, "buffers", buflist_list, - BANG|TRLBAR|CMDWIN), - EX(CMD_bufdo, "bufdo", ex_listdo, - BANG|NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_bunload, "bunload", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), - EX(CMD_bwipeout, "bwipeout", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), - EX(CMD_change, "change", ex_change, - BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY), - EX(CMD_cNext, "cNext", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cNfile, "cNfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cabbrev, "cabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cabclear, "cabclear", ex_abclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_caddbuffer, "caddbuffer", ex_cbuffer, - RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_caddexpr, "caddexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR), - EX(CMD_caddfile, "caddfile", ex_cfile, - TRLBAR|FILE1), - EX(CMD_call, "call", ex_call, - RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_catch, "catch", ex_catch, - EXTRA|SBOXOK|CMDWIN), - EX(CMD_cbuffer, "cbuffer", ex_cbuffer, - BANG|RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_cc, "cc", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cclose, "cclose", ex_cclose, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_cd, "cd", ex_cd, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_center, "center", ex_align, - TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), - EX(CMD_cexpr, "cexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG), - EX(CMD_cfile, "cfile", ex_cfile, - TRLBAR|FILE1|BANG), - EX(CMD_cfirst, "cfirst", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cgetfile, "cgetfile", ex_cfile, - TRLBAR|FILE1), - EX(CMD_cgetbuffer, "cgetbuffer", ex_cbuffer, - RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_cgetexpr, "cgetexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR), - EX(CMD_chdir, "chdir", ex_cd, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_changes, "changes", ex_changes, - TRLBAR|CMDWIN), - EX(CMD_checkpath, "checkpath", ex_checkpath, - TRLBAR|BANG|CMDWIN), - EX(CMD_checktime, "checktime", ex_checktime, - RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), - EX(CMD_clist, "clist", qf_list, - BANG|EXTRA|TRLBAR|CMDWIN), - EX(CMD_clast, "clast", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_close, "close", ex_close, - BANG|TRLBAR|CMDWIN), - EX(CMD_cmap, "cmap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cmapclear, "cmapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_cmenu, "cmenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cnext, "cnext", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cnewer, "cnewer", qf_age, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_cnfile, "cnfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cnoremap, "cnoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cnoreabbrev, "cnoreabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cnoremenu, "cnoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_copy, "copy", ex_copymove, - RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), - EX(CMD_colder, "colder", qf_age, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_colorscheme, "colorscheme", ex_colorscheme, - WORD1|TRLBAR|CMDWIN), - EX(CMD_command, "command", ex_command, - EXTRA|BANG|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_comclear, "comclear", ex_comclear, - TRLBAR|CMDWIN), - EX(CMD_compiler, "compiler", ex_compiler, - BANG|TRLBAR|WORD1|CMDWIN), - EX(CMD_continue, "continue", ex_continue, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_confirm, "confirm", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM|CMDWIN), - EX(CMD_copen, "copen", ex_copen, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_cprevious, "cprevious", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cpfile, "cpfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cquit, "cquit", ex_cquit, - TRLBAR|BANG), - EX(CMD_crewind, "crewind", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_cscope, "cscope", do_cscope, - EXTRA|NOTRLCOM|XFILE), - EX(CMD_cstag, "cstag", do_cstag, - BANG|TRLBAR|WORD1), - EX(CMD_cunmap, "cunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cunabbrev, "cunabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cunmenu, "cunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_cwindow, "cwindow", ex_cwindow, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_delete, "delete", ex_operators, - RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN|MODIFY), - EX(CMD_delmarks, "delmarks", ex_delmarks, - BANG|EXTRA|TRLBAR|CMDWIN), - EX(CMD_debug, "debug", ex_debug, - NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_debuggreedy, "debuggreedy", ex_debuggreedy, - RANGE|NOTADR|ZEROR|TRLBAR|CMDWIN), - EX(CMD_delcommand, "delcommand", ex_delcommand, - NEEDARG|WORD1|TRLBAR|CMDWIN), - EX(CMD_delfunction, "delfunction", ex_delfunction, - NEEDARG|WORD1|CMDWIN), - EX(CMD_display, "display", ex_display, - EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_diffupdate, "diffupdate", ex_diffupdate, - BANG|TRLBAR), - EX(CMD_diffget, "diffget", ex_diffgetput, - RANGE|EXTRA|TRLBAR|MODIFY), - EX(CMD_diffoff, "diffoff", ex_diffoff, - BANG|TRLBAR), - EX(CMD_diffpatch, "diffpatch", ex_diffpatch, - EXTRA|FILE1|TRLBAR|MODIFY), - EX(CMD_diffput, "diffput", ex_diffgetput, - RANGE|EXTRA|TRLBAR), - EX(CMD_diffsplit, "diffsplit", ex_diffsplit, - EXTRA|FILE1|TRLBAR), - EX(CMD_diffthis, "diffthis", ex_diffthis, - TRLBAR), - EX(CMD_digraphs, "digraphs", ex_digraphs, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_djump, "djump", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), - EX(CMD_dlist, "dlist", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_doautocmd, "doautocmd", ex_doautocmd, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_doautoall, "doautoall", ex_doautoall, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_drop, "drop", ex_drop, - FILES|EDITCMD|NEEDARG|ARGOPT|TRLBAR), - EX(CMD_dsearch, "dsearch", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_dsplit, "dsplit", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), - EX(CMD_edit, "edit", ex_edit, - BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_earlier, "earlier", ex_later, - TRLBAR|EXTRA|NOSPC|CMDWIN), - EX(CMD_echo, "echo", ex_echo, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_echoerr, "echoerr", ex_execute, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_echohl, "echohl", ex_echohl, - EXTRA|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_echomsg, "echomsg", ex_execute, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_echon, "echon", ex_echo, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_else, "else", ex_else, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_elseif, "elseif", ex_else, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_emenu, "emenu", ex_emenu, - NEEDARG|EXTRA|TRLBAR|NOTRLCOM|RANGE|NOTADR|CMDWIN), - EX(CMD_endif, "endif", ex_endif, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_endfunction, "endfunction", ex_endfunction, - TRLBAR|CMDWIN), - EX(CMD_endfor, "endfor", ex_endwhile, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_endtry, "endtry", ex_endtry, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_endwhile, "endwhile", ex_endwhile, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_enew, "enew", ex_edit, - BANG|TRLBAR), - EX(CMD_ex, "ex", ex_edit, - BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_execute, "execute", ex_execute, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_exit, "exit", ex_exit, - RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), - EX(CMD_exusage, "exusage", ex_exusage, - TRLBAR), - EX(CMD_file, "file", ex_file, - RANGE|NOTADR|ZEROR|BANG|FILE1|TRLBAR), - EX(CMD_files, "files", buflist_list, - BANG|TRLBAR|CMDWIN), - EX(CMD_filetype, "filetype", ex_filetype, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_find, "find", ex_find, - RANGE|NOTADR|BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_finally, "finally", ex_finally, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_finish, "finish", ex_finish, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_first, "first", ex_rewind, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_fixdel, "fixdel", do_fixdel, - TRLBAR|CMDWIN), - EX(CMD_fold, "fold", ex_fold, - RANGE|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_foldclose, "foldclose", ex_foldopen, - RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_folddoopen, "folddoopen", ex_folddo, - RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_folddoclosed, "folddoclosed", ex_folddo, - RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_foldopen, "foldopen", ex_foldopen, - RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_for, "for", ex_while, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_function, "function", ex_function, - EXTRA|BANG|CMDWIN), - EX(CMD_global, "global", ex_global, - RANGE|WHOLEFOLD|BANG|EXTRA|DFLALL|SBOXOK|CMDWIN), - EX(CMD_goto, "goto", ex_goto, - RANGE|NOTADR|COUNT|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_grep, "grep", ex_make, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_grepadd, "grepadd", ex_make, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_gui, "gui", ex_gui, - BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN), - EX(CMD_gvim, "gvim", ex_gui, - BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN), - EX(CMD_help, "help", ex_help, - BANG|EXTRA|NOTRLCOM), - EX(CMD_helpfind, "helpfind", ex_helpfind, - EXTRA|NOTRLCOM), - EX(CMD_helpgrep, "helpgrep", ex_helpgrep, - EXTRA|NOTRLCOM|NEEDARG), - EX(CMD_helptags, "helptags", ex_helptags, - NEEDARG|FILES|TRLBAR|CMDWIN), - EX(CMD_hardcopy, "hardcopy", ex_hardcopy, - RANGE|COUNT|EXTRA|TRLBAR|DFLALL|BANG), - EX(CMD_highlight, "highlight", ex_highlight, - BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_hide, "hide", ex_hide, - BANG|EXTRA|NOTRLCOM), - EX(CMD_history, "history", ex_history, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_insert, "insert", ex_append, - BANG|RANGE|TRLBAR|CMDWIN|MODIFY), - EX(CMD_iabbrev, "iabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_iabclear, "iabclear", ex_abclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_if, "if", ex_if, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_ijump, "ijump", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), - EX(CMD_ilist, "ilist", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_imap, "imap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_imapclear, "imapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_imenu, "imenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_inoremap, "inoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_inoreabbrev, "inoreabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_inoremenu, "inoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_intro, "intro", ex_intro, - TRLBAR|CMDWIN), - EX(CMD_isearch, "isearch", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_isplit, "isplit", ex_findpat, - BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), - EX(CMD_iunmap, "iunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_iunabbrev, "iunabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_iunmenu, "iunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_join, "join", ex_join, - BANG|RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), - EX(CMD_jumps, "jumps", ex_jumps, - TRLBAR|CMDWIN), - EX(CMD_k, "k", ex_mark, - RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_keepmarks, "keepmarks", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_keepjumps, "keepjumps", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_keeppatterns, "keeppatterns", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_keepalt, "keepalt", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_list, "list", ex_print, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), - EX(CMD_lNext, "lNext", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_lNfile, "lNfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_last, "last", ex_last, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_language, "language", ex_language, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_laddexpr, "laddexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR), - EX(CMD_laddbuffer, "laddbuffer", ex_cbuffer, - RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_laddfile, "laddfile", ex_cfile, - TRLBAR|FILE1), - EX(CMD_later, "later", ex_later, - TRLBAR|EXTRA|NOSPC|CMDWIN), - EX(CMD_lbuffer, "lbuffer", ex_cbuffer, - BANG|RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_lcd, "lcd", ex_cd, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_lchdir, "lchdir", ex_cd, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_lclose, "lclose", ex_cclose, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_lcscope, "lcscope", do_cscope, - EXTRA|NOTRLCOM|XFILE), - EX(CMD_left, "left", ex_align, - TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), - EX(CMD_leftabove, "leftabove", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_let, "let", ex_let, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_lexpr, "lexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG), - EX(CMD_lfile, "lfile", ex_cfile, - TRLBAR|FILE1|BANG), - EX(CMD_lfirst, "lfirst", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_lgetfile, "lgetfile", ex_cfile, - TRLBAR|FILE1), - EX(CMD_lgetbuffer, "lgetbuffer", ex_cbuffer, - RANGE|NOTADR|WORD1|TRLBAR), - EX(CMD_lgetexpr, "lgetexpr", ex_cexpr, - NEEDARG|WORD1|NOTRLCOM|TRLBAR), - EX(CMD_lgrep, "lgrep", ex_make, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_lgrepadd, "lgrepadd", ex_make, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_lhelpgrep, "lhelpgrep", ex_helpgrep, - EXTRA|NOTRLCOM|NEEDARG), - EX(CMD_ll, "ll", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_llast, "llast", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_llist, "llist", qf_list, - BANG|EXTRA|TRLBAR|CMDWIN), - EX(CMD_lmap, "lmap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_lmapclear, "lmapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_lmake, "lmake", ex_make, - BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_lnoremap, "lnoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_lnext, "lnext", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_lnewer, "lnewer", qf_age, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_lnfile, "lnfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_loadview, "loadview", ex_loadview, - FILE1|TRLBAR), - EX(CMD_loadkeymap, "loadkeymap", ex_loadkeymap, - CMDWIN), - EX(CMD_lockmarks, "lockmarks", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_lockvar, "lockvar", ex_lockvar, - BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), - EX(CMD_lolder, "lolder", qf_age, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_lopen, "lopen", ex_copen, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_lprevious, "lprevious", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_lpfile, "lpfile", ex_cnext, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_lrewind, "lrewind", ex_cc, - RANGE|NOTADR|COUNT|TRLBAR|BANG), - EX(CMD_ltag, "ltag", ex_tag, - NOTADR|TRLBAR|BANG|WORD1), - EX(CMD_lua, "lua", ex_lua, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_luado, "luado", ex_luado, - RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), - EX(CMD_luafile, "luafile", ex_luafile, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_lunmap, "lunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_lvimgrep, "lvimgrep", ex_vimgrep, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_lvimgrepadd, "lvimgrepadd", ex_vimgrep, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_lwindow, "lwindow", ex_cwindow, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_ls, "ls", buflist_list, - BANG|TRLBAR|CMDWIN), - EX(CMD_move, "move", ex_copymove, - RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), - EX(CMD_mark, "mark", ex_mark, - RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_make, "make", ex_make, - BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_map, "map", ex_map, - BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_mapclear, "mapclear", ex_mapclear, - EXTRA|BANG|TRLBAR|CMDWIN), - EX(CMD_marks, "marks", do_marks, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_match, "match", ex_match, - RANGE|NOTADR|EXTRA|CMDWIN), - EX(CMD_menu, "menu", ex_menu, - RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_menutranslate, "menutranslate", ex_menutranslate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_messages, "messages", ex_messages, - TRLBAR|CMDWIN), - EX(CMD_mkexrc, "mkexrc", ex_mkrc, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_mksession, "mksession", ex_mkrc, - BANG|FILE1|TRLBAR), - EX(CMD_mkspell, "mkspell", ex_mkspell, - BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_mkvimrc, "mkvimrc", ex_mkrc, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_mkview, "mkview", ex_mkrc, - BANG|FILE1|TRLBAR), - EX(CMD_mode, "mode", ex_mode, - WORD1|TRLBAR|CMDWIN), - EX(CMD_mzscheme, "mzscheme", ex_mzscheme, - RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK), - EX(CMD_mzfile, "mzfile", ex_mzfile, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_next, "next", ex_next, - RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_nbkey, "nbkey", ex_nbkey, - EXTRA|NOTADR|NEEDARG), - EX(CMD_nbclose, "nbclose", ex_nbclose, - TRLBAR|CMDWIN), - EX(CMD_nbstart, "nbstart", ex_nbstart, - WORD1|TRLBAR|CMDWIN), - EX(CMD_new, "new", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_nmap, "nmap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_nmapclear, "nmapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_nmenu, "nmenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_nnoremap, "nnoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_nnoremenu, "nnoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_noremap, "noremap", ex_map, - BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_noautocmd, "noautocmd", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_nohlsearch, "nohlsearch", ex_nohlsearch, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_noreabbrev, "noreabbrev", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_noremenu, "noremenu", ex_menu, - RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_normal, "normal", ex_normal, - RANGE|BANG|EXTRA|NEEDARG|NOTRLCOM|USECTRLV|SBOXOK|CMDWIN), - EX(CMD_number, "number", ex_print, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), - EX(CMD_nunmap, "nunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_nunmenu, "nunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_open, "open", ex_open, - RANGE|BANG|EXTRA), - EX(CMD_oldfiles, "oldfiles", ex_oldfiles, - BANG|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_omap, "omap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_omapclear, "omapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_omenu, "omenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_only, "only", ex_only, - BANG|TRLBAR), - EX(CMD_onoremap, "onoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_onoremenu, "onoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_options, "options", ex_options, - TRLBAR), - EX(CMD_ounmap, "ounmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_ounmenu, "ounmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_ownsyntax, "ownsyntax", ex_ownsyntax, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_print, "print", ex_print, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK), - EX(CMD_pclose, "pclose", ex_pclose, - BANG|TRLBAR), - EX(CMD_perl, "perl", ex_perl, - RANGE|EXTRA|DFLALL|NEEDARG|SBOXOK|CMDWIN), - EX(CMD_perldo, "perldo", ex_perldo, - RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN), - EX(CMD_pedit, "pedit", ex_pedit, - BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_pop, "pop", ex_tag, - RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR), - EX(CMD_popup, "popup", ex_popup, - NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN), - EX(CMD_ppop, "ppop", ex_ptag, - RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR), - EX(CMD_preserve, "preserve", ex_preserve, - TRLBAR), - EX(CMD_previous, "previous", ex_previous, - EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_promptfind, "promptfind", gui_mch_find_dialog, - EXTRA|NOTRLCOM|CMDWIN), - EX(CMD_promptrepl, "promptrepl", gui_mch_replace_dialog, - EXTRA|NOTRLCOM|CMDWIN), - EX(CMD_profile, "profile", ex_profile, - BANG|EXTRA|TRLBAR|CMDWIN), - EX(CMD_profdel, "profdel", ex_breakdel, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_psearch, "psearch", ex_psearch, - BANG|RANGE|WHOLEFOLD|DFLALL|EXTRA), - EX(CMD_ptag, "ptag", ex_ptag, - RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), - EX(CMD_ptNext, "ptNext", ex_ptag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_ptfirst, "ptfirst", ex_ptag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_ptjump, "ptjump", ex_ptag, - BANG|TRLBAR|WORD1), - EX(CMD_ptlast, "ptlast", ex_ptag, - BANG|TRLBAR), - EX(CMD_ptnext, "ptnext", ex_ptag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_ptprevious, "ptprevious", ex_ptag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_ptrewind, "ptrewind", ex_ptag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_ptselect, "ptselect", ex_ptag, - BANG|TRLBAR|WORD1), - EX(CMD_put, "put", ex_put, - RANGE|WHOLEFOLD|BANG|REGSTR|TRLBAR|ZEROR|CMDWIN|MODIFY), - EX(CMD_pwd, "pwd", ex_pwd, - TRLBAR|CMDWIN), - EX(CMD_python, "python", ex_python, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_pydo, "pydo", ex_pydo, - RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), - EX(CMD_pyfile, "pyfile", ex_pyfile, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_py3, "py3", ex_py3, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_py3do, "py3do", ex_py3do, - RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), - EX(CMD_python3, "python3", ex_py3, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_py3file, "py3file", ex_py3file, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_quit, "quit", ex_quit, - BANG|TRLBAR|CMDWIN), - EX(CMD_quitall, "quitall", ex_quit_all, - BANG|TRLBAR), - EX(CMD_qall, "qall", ex_quit_all, - BANG|TRLBAR|CMDWIN), - EX(CMD_read, "read", ex_read, - BANG|RANGE|WHOLEFOLD|FILE1|ARGOPT|TRLBAR|ZEROR|CMDWIN|MODIFY), - EX(CMD_recover, "recover", ex_recover, - BANG|FILE1|TRLBAR), - EX(CMD_redo, "redo", ex_redo, - TRLBAR|CMDWIN), - EX(CMD_redir, "redir", ex_redir, - BANG|FILES|TRLBAR|CMDWIN), - EX(CMD_redraw, "redraw", ex_redraw, - BANG|TRLBAR|CMDWIN), - EX(CMD_redrawstatus, "redrawstatus", ex_redrawstatus, - BANG|TRLBAR|CMDWIN), - EX(CMD_registers, "registers", ex_display, - EXTRA|NOTRLCOM|TRLBAR|CMDWIN), - EX(CMD_resize, "resize", ex_resize, - RANGE|NOTADR|TRLBAR|WORD1), - EX(CMD_retab, "retab", ex_retab, - TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY), - EX(CMD_return, "return", ex_return, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_rewind, "rewind", ex_rewind, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_right, "right", ex_align, - TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), - EX(CMD_rightbelow, "rightbelow", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_runtime, "runtime", ex_runtime, - BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_ruby, "ruby", ex_ruby, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_rubydo, "rubydo", ex_rubydo, - RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), - EX(CMD_rubyfile, "rubyfile", ex_rubyfile, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_rundo, "rundo", ex_rundo, - NEEDARG|FILE1), - EX(CMD_rviminfo, "rviminfo", ex_viminfo, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_substitute, "substitute", do_sub, - RANGE|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_sNext, "sNext", ex_previous, - EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_sargument, "sargument", ex_argument, - BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_sall, "sall", ex_all, - BANG|RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sandbox, "sandbox", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_saveas, "saveas", ex_write, - BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR), - EX(CMD_sbuffer, "sbuffer", ex_buffer, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), - EX(CMD_sbNext, "sbNext", ex_bprevious, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sball, "sball", ex_buffer_all, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sbfirst, "sbfirst", ex_brewind, - TRLBAR), - EX(CMD_sblast, "sblast", ex_blast, - TRLBAR), - EX(CMD_sbmodified, "sbmodified", ex_bmodified, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sbnext, "sbnext", ex_bnext, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sbprevious, "sbprevious", ex_bprevious, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sbrewind, "sbrewind", ex_brewind, - TRLBAR), - EX(CMD_scriptnames, "scriptnames", ex_scriptnames, - TRLBAR|CMDWIN), - EX(CMD_scriptencoding, "scriptencoding", ex_scriptencoding, - WORD1|TRLBAR|CMDWIN), - EX(CMD_scscope, "scscope", do_scscope, - EXTRA|NOTRLCOM), - EX(CMD_set, "set", ex_set, - TRLBAR|EXTRA|CMDWIN|SBOXOK), - EX(CMD_setfiletype, "setfiletype", ex_setfiletype, - TRLBAR|EXTRA|NEEDARG|CMDWIN), - EX(CMD_setglobal, "setglobal", ex_set, - TRLBAR|EXTRA|CMDWIN|SBOXOK), - EX(CMD_setlocal, "setlocal", ex_set, - TRLBAR|EXTRA|CMDWIN|SBOXOK), - EX(CMD_sfind, "sfind", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_sfirst, "sfirst", ex_rewind, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_shell, "shell", ex_shell, - TRLBAR|CMDWIN), - EX(CMD_simalt, "simalt", ex_simalt, - NEEDARG|WORD1|TRLBAR|CMDWIN), - EX(CMD_sign, "sign", ex_sign, - NEEDARG|RANGE|NOTADR|EXTRA|CMDWIN), - EX(CMD_silent, "silent", ex_wrongmodifier, - NEEDARG|EXTRA|BANG|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_sleep, "sleep", ex_sleep, - RANGE|NOTADR|COUNT|EXTRA|TRLBAR|CMDWIN), - EX(CMD_slast, "slast", ex_last, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_smagic, "smagic", ex_submagic, - RANGE|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_smap, "smap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_smapclear, "smapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_smenu, "smenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_snext, "snext", ex_next, - RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_sniff, "sniff", ex_sniff, - EXTRA|TRLBAR), - EX(CMD_snomagic, "snomagic", ex_submagic, - RANGE|WHOLEFOLD|EXTRA|CMDWIN), - EX(CMD_snoremap, "snoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_snoremenu, "snoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_source, "source", ex_source, - BANG|FILE1|TRLBAR|SBOXOK|CMDWIN), - EX(CMD_sort, "sort", ex_sort, - RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY), - EX(CMD_split, "split", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_spellgood, "spellgood", ex_spell, - BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), - EX(CMD_spelldump, "spelldump", ex_spelldump, - BANG|TRLBAR), - EX(CMD_spellinfo, "spellinfo", ex_spellinfo, - TRLBAR), - EX(CMD_spellrepall, "spellrepall", ex_spellrepall, - TRLBAR), - EX(CMD_spellundo, "spellundo", ex_spell, - BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), - EX(CMD_spellwrong, "spellwrong", ex_spell, - BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), - EX(CMD_sprevious, "sprevious", ex_previous, - EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_srewind, "srewind", ex_rewind, - EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_stop, "stop", ex_stop, - TRLBAR|BANG|CMDWIN), - EX(CMD_stag, "stag", ex_stag, - RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), - EX(CMD_startinsert, "startinsert", ex_startinsert, - BANG|TRLBAR|CMDWIN), - EX(CMD_startgreplace, "startgreplace", ex_startinsert, - BANG|TRLBAR|CMDWIN), - EX(CMD_startreplace, "startreplace", ex_startinsert, - BANG|TRLBAR|CMDWIN), - EX(CMD_stopinsert, "stopinsert", ex_stopinsert, - BANG|TRLBAR|CMDWIN), - EX(CMD_stjump, "stjump", ex_stag, - BANG|TRLBAR|WORD1), - EX(CMD_stselect, "stselect", ex_stag, - BANG|TRLBAR|WORD1), - EX(CMD_sunhide, "sunhide", ex_buffer_all, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_sunmap, "sunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_sunmenu, "sunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_suspend, "suspend", ex_stop, - TRLBAR|BANG|CMDWIN), - EX(CMD_sview, "sview", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_swapname, "swapname", ex_swapname, - TRLBAR|CMDWIN), - EX(CMD_syntax, "syntax", ex_syntax, - EXTRA|NOTRLCOM|CMDWIN), - EX(CMD_syntime, "syntime", ex_syntime, - NEEDARG|WORD1|TRLBAR|CMDWIN), - EX(CMD_syncbind, "syncbind", ex_syncbind, - TRLBAR), - EX(CMD_t, "t", ex_copymove, - RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), - EX(CMD_tNext, "tNext", ex_tag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_tag, "tag", ex_tag, - RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), - EX(CMD_tags, "tags", do_tags, - TRLBAR|CMDWIN), - EX(CMD_tab, "tab", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_tabclose, "tabclose", ex_tabclose, - RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN), - EX(CMD_tabdo, "tabdo", ex_listdo, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_tabedit, "tabedit", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_tabfind, "tabfind", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR), - EX(CMD_tabfirst, "tabfirst", ex_tabnext, - TRLBAR), - EX(CMD_tabmove, "tabmove", ex_tabmove, - RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR), - EX(CMD_tablast, "tablast", ex_tabnext, - TRLBAR), - EX(CMD_tabnext, "tabnext", ex_tabnext, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_tabnew, "tabnew", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_tabonly, "tabonly", ex_tabonly, - BANG|TRLBAR|CMDWIN), - EX(CMD_tabprevious, "tabprevious", ex_tabnext, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_tabNext, "tabNext", ex_tabnext, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_tabrewind, "tabrewind", ex_tabnext, - TRLBAR), - EX(CMD_tabs, "tabs", ex_tabs, - TRLBAR|CMDWIN), - EX(CMD_tcl, "tcl", ex_tcl, - RANGE|EXTRA|NEEDARG|CMDWIN), - EX(CMD_tcldo, "tcldo", ex_tcldo, - RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), - EX(CMD_tclfile, "tclfile", ex_tclfile, - RANGE|FILE1|NEEDARG|CMDWIN), - EX(CMD_tearoff, "tearoff", ex_tearoff, - NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN), - EX(CMD_tfirst, "tfirst", ex_tag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_throw, "throw", ex_throw, - EXTRA|NEEDARG|SBOXOK|CMDWIN), - EX(CMD_tjump, "tjump", ex_tag, - BANG|TRLBAR|WORD1), - EX(CMD_tlast, "tlast", ex_tag, - BANG|TRLBAR), - EX(CMD_tmenu, "tmenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_tnext, "tnext", ex_tag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_topleft, "topleft", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_tprevious, "tprevious", ex_tag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_trewind, "trewind", ex_tag, - RANGE|NOTADR|BANG|TRLBAR|ZEROR), - EX(CMD_try, "try", ex_try, - TRLBAR|SBOXOK|CMDWIN), - EX(CMD_tselect, "tselect", ex_tag, - BANG|TRLBAR|WORD1), - EX(CMD_tunmenu, "tunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_undo, "undo", ex_undo, - RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN), - EX(CMD_undojoin, "undojoin", ex_undojoin, - TRLBAR|CMDWIN), - EX(CMD_undolist, "undolist", ex_undolist, - TRLBAR|CMDWIN), - EX(CMD_unabbreviate, "unabbreviate", ex_abbreviate, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_unhide, "unhide", ex_buffer_all, - RANGE|NOTADR|COUNT|TRLBAR), - EX(CMD_unlet, "unlet", ex_unlet, - BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), - EX(CMD_unlockvar, "unlockvar", ex_lockvar, - BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), - EX(CMD_unmap, "unmap", ex_unmap, - BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_unmenu, "unmenu", ex_menu, - BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_unsilent, "unsilent", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_update, "update", ex_update, - RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR), - EX(CMD_vglobal, "vglobal", ex_global, - RANGE|WHOLEFOLD|EXTRA|DFLALL|CMDWIN), - EX(CMD_version, "version", ex_version, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_verbose, "verbose", ex_wrongmodifier, - NEEDARG|RANGE|NOTADR|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_vertical, "vertical", ex_wrongmodifier, - NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_visual, "visual", ex_edit, - BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_view, "view", ex_edit, - BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_vimgrep, "vimgrep", ex_vimgrep, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep, - RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), - EX(CMD_viusage, "viusage", ex_viusage, - TRLBAR), - EX(CMD_vmap, "vmap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_vmapclear, "vmapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_vmenu, "vmenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_vnoremap, "vnoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_vnew, "vnew", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_vnoremenu, "vnoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_vsplit, "vsplit", ex_splitview, - BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_vunmap, "vunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_vunmenu, "vunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_write, "write", ex_write, - RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), - EX(CMD_wNext, "wNext", ex_wnext, - RANGE|WHOLEFOLD|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), - EX(CMD_wall, "wall", do_wqall, - BANG|TRLBAR|CMDWIN), - EX(CMD_while, "while", ex_while, - EXTRA|NOTRLCOM|SBOXOK|CMDWIN), - EX(CMD_winsize, "winsize", ex_winsize, - EXTRA|NEEDARG|TRLBAR), - EX(CMD_wincmd, "wincmd", ex_wincmd, - NEEDARG|WORD1|RANGE|NOTADR), - EX(CMD_windo, "windo", ex_listdo, - BANG|NEEDARG|EXTRA|NOTRLCOM), - EX(CMD_winpos, "winpos", ex_winpos, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_wnext, "wnext", ex_wnext, - RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), - EX(CMD_wprevious, "wprevious", ex_wnext, - RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), - EX(CMD_wq, "wq", ex_exit, - RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR), - EX(CMD_wqall, "wqall", do_wqall, - BANG|FILE1|ARGOPT|DFLALL|TRLBAR), - EX(CMD_wsverb, "wsverb", ex_wsverb, - EXTRA|NOTADR|NEEDARG), - EX(CMD_wundo, "wundo", ex_wundo, - BANG|NEEDARG|FILE1), - EX(CMD_wviminfo, "wviminfo", ex_viminfo, - BANG|FILE1|TRLBAR|CMDWIN), - EX(CMD_xit, "xit", ex_exit, - RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), - EX(CMD_xall, "xall", do_wqall, - BANG|TRLBAR), - EX(CMD_xmap, "xmap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_xmapclear, "xmapclear", ex_mapclear, - EXTRA|TRLBAR|CMDWIN), - EX(CMD_xmenu, "xmenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_xnoremap, "xnoremap", ex_map, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_xnoremenu, "xnoremenu", ex_menu, - RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_xunmap, "xunmap", ex_unmap, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_xunmenu, "xunmenu", ex_menu, - EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), - EX(CMD_yank, "yank", ex_operators, - RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN), - EX(CMD_z, "z", ex_z, - RANGE|WHOLEFOLD|EXTRA|EXFLAGS|TRLBAR|CMDWIN), - - /* commands that don't start with a lowercase letter */ - EX(CMD_bang, "!", ex_bang, - RANGE|WHOLEFOLD|BANG|FILES|CMDWIN), - EX(CMD_pound, "#", ex_print, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), - EX(CMD_and, "&", do_sub, - RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), - EX(CMD_star, "*", ex_at, - RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN), - EX(CMD_lshift, "<", ex_operators, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), - EX(CMD_equal, "=", ex_equal, - RANGE|TRLBAR|DFLALL|EXFLAGS|CMDWIN), - EX(CMD_rshift, ">", ex_operators, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), - EX(CMD_at, "@", ex_at, - RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN), - EX(CMD_Next, "Next", ex_previous, - EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), - EX(CMD_Print, "Print", ex_print, - RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), - EX(CMD_X, "X", ex_X, - TRLBAR), - EX(CMD_tilde, "~", do_sub, - RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), - -#ifndef DO_DECLARE_EXCMD - CMD_SIZE, /* MUST be after all real commands! */ - CMD_USER = -1, /* User-defined command */ - CMD_USER_BUF = -2 /* User-defined command local to buffer */ -#endif -}; - -#define USER_CMDIDX(idx) ((int)(idx) < 0) - -#ifndef DO_DECLARE_EXCMD -typedef enum CMD_index cmdidx_T; - -/* - * Arguments used for Ex commands. - */ -struct exarg { - char_u *arg; /* argument of the command */ - char_u *nextcmd; /* next command (NULL if none) */ - char_u *cmd; /* the name of the command (except for :make) */ - char_u **cmdlinep; /* pointer to pointer of allocated cmdline */ - cmdidx_T cmdidx; /* the index for the command */ - long argt; /* flags for the command */ - int skip; /* don't execute the command, only parse it */ - int forceit; /* TRUE if ! present */ - int addr_count; /* the number of addresses given */ - linenr_T line1; /* the first line number */ - linenr_T line2; /* the second line number or count */ - int flags; /* extra flags after count: EXFLAG_ */ - char_u *do_ecmd_cmd; /* +command arg to be used in edited file */ - linenr_T do_ecmd_lnum; /* the line number in an edited file */ - int append; /* TRUE with ":w >>file" command */ - int usefilter; /* TRUE with ":w !command" and ":r!command" */ - int amount; /* number of '>' or '<' for shift command */ - int regname; /* register name (NUL if none) */ - int force_bin; /* 0, FORCE_BIN or FORCE_NOBIN */ - int read_edit; /* ++edit argument */ - int force_ff; /* ++ff= argument (index in cmd[]) */ - int force_enc; /* ++enc= argument (index in cmd[]) */ - int bad_char; /* BAD_KEEP, BAD_DROP or replacement byte */ - int useridx; /* user command index */ - char_u *errmsg; /* returned error message */ - char_u *(*getline)__ARGS((int, void *, int)); - void *cookie; /* argument for getline() */ - struct condstack *cstack; /* condition stack for ":if" etc. */ -}; - -#define FORCE_BIN 1 /* ":edit ++bin file" */ -#define FORCE_NOBIN 2 /* ":edit ++nobin file" */ - -/* Values for "flags" */ -#define EXFLAG_LIST 0x01 /* 'l': list */ -#define EXFLAG_NR 0x02 /* '#': number */ -#define EXFLAG_PRINT 0x04 /* 'p': print */ - -#endif +#ifndef NEOVIM_EX_CMDS_H +#define NEOVIM_EX_CMDS_H +/* ex_cmds.c */ + +void do_ascii __ARGS((exarg_T *eap)); +void ex_align __ARGS((exarg_T *eap)); +void ex_sort __ARGS((exarg_T *eap)); +void ex_retab __ARGS((exarg_T *eap)); +int do_move __ARGS((linenr_T line1, linenr_T line2, linenr_T dest)); +void ex_copy __ARGS((linenr_T line1, linenr_T line2, linenr_T n)); +void free_prev_shellcmd __ARGS((void)); +void do_bang __ARGS((int addr_count, exarg_T *eap, int forceit, int do_in, + int do_out)); +void do_shell __ARGS((char_u *cmd, int flags)); +char_u *make_filter_cmd __ARGS((char_u *cmd, char_u *itmp, char_u *otmp)); +void append_redir __ARGS((char_u *buf, int buflen, char_u *opt, char_u *fname)); +int viminfo_error __ARGS((char *errnum, char *message, char_u *line)); +int read_viminfo __ARGS((char_u *file, int flags)); +void write_viminfo __ARGS((char_u *file, int forceit)); +int viminfo_readline __ARGS((vir_T *virp)); +char_u *viminfo_readstring __ARGS((vir_T *virp, int off, int convert)); +void viminfo_writestring __ARGS((FILE *fd, char_u *p)); +void do_fixdel __ARGS((exarg_T *eap)); +void print_line_no_prefix __ARGS((linenr_T lnum, int use_number, int list)); +void print_line __ARGS((linenr_T lnum, int use_number, int list)); +int rename_buffer __ARGS((char_u *new_fname)); +void ex_file __ARGS((exarg_T *eap)); +void ex_update __ARGS((exarg_T *eap)); +void ex_write __ARGS((exarg_T *eap)); +int do_write __ARGS((exarg_T *eap)); +int check_overwrite __ARGS((exarg_T *eap, buf_T *buf, char_u *fname, char_u * + ffname, + int other)); +void ex_wnext __ARGS((exarg_T *eap)); +void do_wqall __ARGS((exarg_T *eap)); +int not_writing __ARGS((void)); +int getfile __ARGS((int fnum, char_u *ffname, char_u *sfname, int setpm, + linenr_T lnum, + int forceit)); +int do_ecmd __ARGS((int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, + linenr_T newlnum, int flags, + win_T *oldwin)); +void ex_append __ARGS((exarg_T *eap)); +void ex_change __ARGS((exarg_T *eap)); +void ex_z __ARGS((exarg_T *eap)); +int check_restricted __ARGS((void)); +int check_secure __ARGS((void)); +void do_sub __ARGS((exarg_T *eap)); +int do_sub_msg __ARGS((int count_only)); +void ex_global __ARGS((exarg_T *eap)); +void global_exe __ARGS((char_u *cmd)); +int read_viminfo_sub_string __ARGS((vir_T *virp, int force)); +void write_viminfo_sub_string __ARGS((FILE *fp)); +void free_old_sub __ARGS((void)); +int prepare_tagpreview __ARGS((int undo_sync)); +void ex_help __ARGS((exarg_T *eap)); +char_u *check_help_lang __ARGS((char_u *arg)); +int help_heuristic __ARGS((char_u *matched_string, int offset, int wrong_case)); +int find_help_tags __ARGS((char_u *arg, int *num_matches, char_u ***matches, + int keep_lang)); +void fix_help_buffer __ARGS((void)); +void ex_exusage __ARGS((exarg_T *eap)); +void ex_viusage __ARGS((exarg_T *eap)); +void ex_helptags __ARGS((exarg_T *eap)); +void ex_sign __ARGS((exarg_T *eap)); +void sign_gui_started __ARGS((void)); +int sign_get_attr __ARGS((int typenr, int line)); +char_u *sign_get_text __ARGS((int typenr)); +void *sign_get_image __ARGS((int typenr)); +char_u *sign_typenr2name __ARGS((int typenr)); +void free_signs __ARGS((void)); +char_u *get_sign_name __ARGS((expand_T *xp, int idx)); +void set_context_in_sign_cmd __ARGS((expand_T *xp, char_u *arg)); +void ex_drop __ARGS((exarg_T *eap)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EX_CMDS_H */ diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 4f5cd60da9..dfda02ff19 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -12,7 +12,32 @@ */ #include "vim.h" -#include "version.h" +#include "version_defs.h" +#include "ex_cmds2.h" +#include "buffer.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "getchar.h" +#include "mark.h" +#include "mbyte.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "term.h" +#include "undo.h" +#include "window.h" static void cmd_source __ARGS((char_u *fname, exarg_T *eap)); diff --git a/src/ex_cmds2.h b/src/ex_cmds2.h new file mode 100644 index 0000000000..a01096cfd7 --- /dev/null +++ b/src/ex_cmds2.h @@ -0,0 +1,96 @@ +#ifndef NEOVIM_EX_CMDS2_H +#define NEOVIM_EX_CMDS2_H +/* ex_cmds2.c */ +void do_debug __ARGS((char_u *cmd)); +void ex_debug __ARGS((exarg_T *eap)); +void dbg_check_breakpoint __ARGS((exarg_T *eap)); +int dbg_check_skipped __ARGS((exarg_T *eap)); +void ex_breakadd __ARGS((exarg_T *eap)); +void ex_debuggreedy __ARGS((exarg_T *eap)); +void ex_breakdel __ARGS((exarg_T *eap)); +void ex_breaklist __ARGS((exarg_T *eap)); +linenr_T dbg_find_breakpoint __ARGS((int file, char_u *fname, linenr_T after)); +int has_profiling __ARGS((int file, char_u *fname, int *fp)); +void dbg_breakpoint __ARGS((char_u *name, linenr_T lnum)); +void profile_start __ARGS((proftime_T *tm)); +void profile_end __ARGS((proftime_T *tm)); +void profile_sub __ARGS((proftime_T *tm, proftime_T *tm2)); +char *profile_msg __ARGS((proftime_T *tm)); +void profile_setlimit __ARGS((long msec, proftime_T *tm)); +int profile_passed_limit __ARGS((proftime_T *tm)); +void profile_zero __ARGS((proftime_T *tm)); +void profile_divide __ARGS((proftime_T *tm, int count, proftime_T *tm2)); +void profile_add __ARGS((proftime_T *tm, proftime_T *tm2)); +void profile_self __ARGS((proftime_T *self, proftime_T *total, + proftime_T *children)); +void profile_get_wait __ARGS((proftime_T *tm)); +void profile_sub_wait __ARGS((proftime_T *tm, proftime_T *tma)); +int profile_equal __ARGS((proftime_T *tm1, proftime_T *tm2)); +int profile_cmp __ARGS((const proftime_T *tm1, const proftime_T *tm2)); +void ex_profile __ARGS((exarg_T *eap)); +char_u *get_profile_name __ARGS((expand_T *xp, int idx)); +void set_context_in_profile_cmd __ARGS((expand_T *xp, char_u *arg)); +void profile_dump __ARGS((void)); +void script_prof_save __ARGS((proftime_T *tm)); +void script_prof_restore __ARGS((proftime_T *tm)); +void prof_inchar_enter __ARGS((void)); +void prof_inchar_exit __ARGS((void)); +int prof_def_func __ARGS((void)); +int autowrite __ARGS((buf_T *buf, int forceit)); +void autowrite_all __ARGS((void)); +int check_changed __ARGS((buf_T *buf, int flags)); +void browse_save_fname __ARGS((buf_T *buf)); +void dialog_changed __ARGS((buf_T *buf, int checkall)); +int can_abandon __ARGS((buf_T *buf, int forceit)); +int check_changed_any __ARGS((int hidden)); +int check_fname __ARGS((void)); +int buf_write_all __ARGS((buf_T *buf, int forceit)); +int get_arglist __ARGS((garray_T *gap, char_u *str)); +int get_arglist_exp __ARGS((char_u *str, int *fcountp, char_u ***fnamesp, + int wig)); +void set_arglist __ARGS((char_u *str)); +void check_arg_idx __ARGS((win_T *win)); +void ex_args __ARGS((exarg_T *eap)); +void ex_previous __ARGS((exarg_T *eap)); +void ex_rewind __ARGS((exarg_T *eap)); +void ex_last __ARGS((exarg_T *eap)); +void ex_argument __ARGS((exarg_T *eap)); +void do_argfile __ARGS((exarg_T *eap, int argn)); +void ex_next __ARGS((exarg_T *eap)); +void ex_argedit __ARGS((exarg_T *eap)); +void ex_argadd __ARGS((exarg_T *eap)); +void ex_argdelete __ARGS((exarg_T *eap)); +void ex_listdo __ARGS((exarg_T *eap)); +void ex_compiler __ARGS((exarg_T *eap)); +void ex_runtime __ARGS((exarg_T *eap)); +int source_runtime __ARGS((char_u *name, int all)); +int do_in_runtimepath __ARGS((char_u *name, int all, void (*callback)( + char_u *fname, void *ck), void *cookie)); +void ex_options __ARGS((exarg_T *eap)); +void ex_source __ARGS((exarg_T *eap)); +linenr_T *source_breakpoint __ARGS((void *cookie)); +int *source_dbg_tick __ARGS((void *cookie)); +int source_level __ARGS((void *cookie)); +int do_source __ARGS((char_u *fname, int check_other, int is_vimrc)); +void ex_scriptnames __ARGS((exarg_T *eap)); +void scriptnames_slash_adjust __ARGS((void)); +char_u *get_scriptname __ARGS((scid_T id)); +void free_scriptnames __ARGS((void)); +char *fgets_cr __ARGS((char *s, int n, FILE *stream)); +char_u *getsourceline __ARGS((int c, void *cookie, int indent)); +void script_line_start __ARGS((void)); +void script_line_exec __ARGS((void)); +void script_line_end __ARGS((void)); +void ex_scriptencoding __ARGS((exarg_T *eap)); +void ex_finish __ARGS((exarg_T *eap)); +void do_finish __ARGS((exarg_T *eap, int reanimate)); +int source_finished __ARGS((char_u *(*fgetline)(int, void *, int), void *cookie)); +void ex_checktime __ARGS((exarg_T *eap)); +char_u *get_mess_lang __ARGS((void)); +void set_lang_var __ARGS((void)); +void ex_language __ARGS((exarg_T *eap)); +void free_locales __ARGS((void)); +char_u *get_lang_arg __ARGS((expand_T *xp, int idx)); +char_u *get_locales __ARGS((expand_T *xp, int idx)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EX_CMDS2_H */ diff --git a/src/ex_cmds_defs.h b/src/ex_cmds_defs.h new file mode 100644 index 0000000000..a560789fef --- /dev/null +++ b/src/ex_cmds_defs.h @@ -0,0 +1,1191 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * This file defines the Ex commands. + * When DO_DECLARE_EXCMD is defined, the table with ex command names and + * options results. + * When DO_DECLARE_EXCMD is NOT defined, the enum with all the Ex commands + * results. + * This clever trick was invented by Ron Aaron. + */ + +/* + * When adding an Ex command: + * 1. Add an entry in the table below. Keep it sorted on the shortest + * version of the command name that works. If it doesn't start with a + * lower case letter, add it at the end. + * 2. Add a "case: CMD_xxx" in the big switch in ex_docmd.c. + * 3. Add an entry in the index for Ex commands at ":help ex-cmd-index". + * 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and + * long name of the command. + */ + +#ifdef RANGE +# undef RANGE /* SASC on Amiga defines it */ +#endif + +#define RANGE 0x001 /* allow a linespecs */ +#define BANG 0x002 /* allow a ! after the command name */ +#define EXTRA 0x004 /* allow extra args after command name */ +#define XFILE 0x008 /* expand wildcards in extra part */ +#define NOSPC 0x010 /* no spaces allowed in the extra part */ +#define DFLALL 0x020 /* default file range is 1,$ */ +#define WHOLEFOLD 0x040 /* extend range to include whole fold also + when less than two numbers given */ +#define NEEDARG 0x080 /* argument required */ +#define TRLBAR 0x100 /* check for trailing vertical bar */ +#define REGSTR 0x200 /* allow "x for register designation */ +#define COUNT 0x400 /* allow count in argument, after command */ +#define NOTRLCOM 0x800 /* no trailing comment allowed */ +#define ZEROR 0x1000 /* zero line number allowed */ +#define USECTRLV 0x2000 /* do not remove CTRL-V from argument */ +#define NOTADR 0x4000 /* number before command is not an address */ +#define EDITCMD 0x8000 /* allow "+command" argument */ +#define BUFNAME 0x10000L /* accepts buffer name */ +#define BUFUNL 0x20000L /* accepts unlisted buffer too */ +#define ARGOPT 0x40000L /* allow "++opt=val" argument */ +#define SBOXOK 0x80000L /* allowed in the sandbox */ +#define CMDWIN 0x100000L /* allowed in cmdline window */ +#define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */ +#define EXFLAGS 0x400000L /* allow flags after count in argument */ +#define FILES (XFILE | EXTRA) /* multiple extra files allowed */ +#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */ +#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */ + +#ifndef DO_DECLARE_EXCMD +typedef struct exarg exarg_T; +#endif + +/* + * This array maps ex command names to command codes. + * The order in which command names are listed below is significant -- + * ambiguous abbreviations are always resolved to be the first possible match + * (e.g. "r" is taken to mean "read", not "rewind", because "read" comes + * before "rewind"). + * Not supported commands are included to avoid ambiguities. + */ +#ifdef EX +# undef EX /* just in case */ +#endif +#ifdef DO_DECLARE_EXCMD +# define EX(a, b, c, d) {(char_u *)b, c, (long_u)(d)} + +typedef void (*ex_func_T) __ARGS ((exarg_T *eap)); + +static struct cmdname { + char_u *cmd_name; /* name of the command */ + ex_func_T cmd_func; /* function for this command */ + long_u cmd_argt; /* flags declared above */ +} +cmdnames[] = +#else +# define EX(a, b, c, d) a +enum CMD_index +#endif +{ + EX(CMD_append, "append", ex_append, + BANG|RANGE|ZEROR|TRLBAR|CMDWIN|MODIFY), + EX(CMD_abbreviate, "abbreviate", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_abclear, "abclear", ex_abclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_aboveleft, "aboveleft", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_all, "all", ex_all, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_amenu, "amenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_anoremenu, "anoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_args, "args", ex_args, + BANG|FILES|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_argadd, "argadd", ex_argadd, + BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|TRLBAR), + EX(CMD_argdelete, "argdelete", ex_argdelete, + BANG|RANGE|NOTADR|FILES|TRLBAR), + EX(CMD_argdo, "argdo", ex_listdo, + BANG|NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_argedit, "argedit", ex_argedit, + BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_argglobal, "argglobal", ex_args, + BANG|FILES|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_arglocal, "arglocal", ex_args, + BANG|FILES|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_argument, "argument", ex_argument, + BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_ascii, "ascii", do_ascii, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_autocmd, "autocmd", ex_autocmd, + BANG|EXTRA|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_augroup, "augroup", ex_autocmd, + BANG|WORD1|TRLBAR|CMDWIN), + EX(CMD_aunmenu, "aunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_buffer, "buffer", ex_buffer, + BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), + EX(CMD_bNext, "bNext", ex_bprevious, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_ball, "ball", ex_buffer_all, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_badd, "badd", ex_edit, + NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN), + EX(CMD_bdelete, "bdelete", ex_bunload, + BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), + EX(CMD_behave, "behave", ex_behave, + NEEDARG|WORD1|TRLBAR|CMDWIN), + EX(CMD_belowright, "belowright", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_bfirst, "bfirst", ex_brewind, + BANG|RANGE|NOTADR|TRLBAR), + EX(CMD_blast, "blast", ex_blast, + BANG|RANGE|NOTADR|TRLBAR), + EX(CMD_bmodified, "bmodified", ex_bmodified, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_bnext, "bnext", ex_bnext, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_botright, "botright", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_bprevious, "bprevious", ex_bprevious, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_brewind, "brewind", ex_brewind, + BANG|RANGE|NOTADR|TRLBAR), + EX(CMD_break, "break", ex_break, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_breakadd, "breakadd", ex_breakadd, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_breakdel, "breakdel", ex_breakdel, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_breaklist, "breaklist", ex_breaklist, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_browse, "browse", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM|CMDWIN), + EX(CMD_buffers, "buffers", buflist_list, + BANG|TRLBAR|CMDWIN), + EX(CMD_bufdo, "bufdo", ex_listdo, + BANG|NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_bunload, "bunload", ex_bunload, + BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), + EX(CMD_bwipeout, "bwipeout", ex_bunload, + BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), + EX(CMD_change, "change", ex_change, + BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY), + EX(CMD_cNext, "cNext", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cNfile, "cNfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cabbrev, "cabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cabclear, "cabclear", ex_abclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_caddbuffer, "caddbuffer", ex_cbuffer, + RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_caddexpr, "caddexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR), + EX(CMD_caddfile, "caddfile", ex_cfile, + TRLBAR|FILE1), + EX(CMD_call, "call", ex_call, + RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_catch, "catch", ex_catch, + EXTRA|SBOXOK|CMDWIN), + EX(CMD_cbuffer, "cbuffer", ex_cbuffer, + BANG|RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_cc, "cc", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cclose, "cclose", ex_cclose, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_cd, "cd", ex_cd, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_center, "center", ex_align, + TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), + EX(CMD_cexpr, "cexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG), + EX(CMD_cfile, "cfile", ex_cfile, + TRLBAR|FILE1|BANG), + EX(CMD_cfirst, "cfirst", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cgetfile, "cgetfile", ex_cfile, + TRLBAR|FILE1), + EX(CMD_cgetbuffer, "cgetbuffer", ex_cbuffer, + RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_cgetexpr, "cgetexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR), + EX(CMD_chdir, "chdir", ex_cd, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_changes, "changes", ex_changes, + TRLBAR|CMDWIN), + EX(CMD_checkpath, "checkpath", ex_checkpath, + TRLBAR|BANG|CMDWIN), + EX(CMD_checktime, "checktime", ex_checktime, + RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), + EX(CMD_clist, "clist", qf_list, + BANG|EXTRA|TRLBAR|CMDWIN), + EX(CMD_clast, "clast", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_close, "close", ex_close, + BANG|TRLBAR|CMDWIN), + EX(CMD_cmap, "cmap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cmapclear, "cmapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_cmenu, "cmenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cnext, "cnext", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cnewer, "cnewer", qf_age, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_cnfile, "cnfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cnoremap, "cnoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cnoreabbrev, "cnoreabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cnoremenu, "cnoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_copy, "copy", ex_copymove, + RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), + EX(CMD_colder, "colder", qf_age, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_colorscheme, "colorscheme", ex_colorscheme, + WORD1|TRLBAR|CMDWIN), + EX(CMD_command, "command", ex_command, + EXTRA|BANG|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_comclear, "comclear", ex_comclear, + TRLBAR|CMDWIN), + EX(CMD_compiler, "compiler", ex_compiler, + BANG|TRLBAR|WORD1|CMDWIN), + EX(CMD_continue, "continue", ex_continue, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_confirm, "confirm", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM|CMDWIN), + EX(CMD_copen, "copen", ex_copen, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_cprevious, "cprevious", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cpfile, "cpfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cquit, "cquit", ex_cquit, + TRLBAR|BANG), + EX(CMD_crewind, "crewind", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_cscope, "cscope", do_cscope, + EXTRA|NOTRLCOM|XFILE), + EX(CMD_cstag, "cstag", do_cstag, + BANG|TRLBAR|WORD1), + EX(CMD_cunmap, "cunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cunabbrev, "cunabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cunmenu, "cunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_cwindow, "cwindow", ex_cwindow, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_delete, "delete", ex_operators, + RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN|MODIFY), + EX(CMD_delmarks, "delmarks", ex_delmarks, + BANG|EXTRA|TRLBAR|CMDWIN), + EX(CMD_debug, "debug", ex_debug, + NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_debuggreedy, "debuggreedy", ex_debuggreedy, + RANGE|NOTADR|ZEROR|TRLBAR|CMDWIN), + EX(CMD_delcommand, "delcommand", ex_delcommand, + NEEDARG|WORD1|TRLBAR|CMDWIN), + EX(CMD_delfunction, "delfunction", ex_delfunction, + NEEDARG|WORD1|CMDWIN), + EX(CMD_display, "display", ex_display, + EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_diffupdate, "diffupdate", ex_diffupdate, + BANG|TRLBAR), + EX(CMD_diffget, "diffget", ex_diffgetput, + RANGE|EXTRA|TRLBAR|MODIFY), + EX(CMD_diffoff, "diffoff", ex_diffoff, + BANG|TRLBAR), + EX(CMD_diffpatch, "diffpatch", ex_diffpatch, + EXTRA|FILE1|TRLBAR|MODIFY), + EX(CMD_diffput, "diffput", ex_diffgetput, + RANGE|EXTRA|TRLBAR), + EX(CMD_diffsplit, "diffsplit", ex_diffsplit, + EXTRA|FILE1|TRLBAR), + EX(CMD_diffthis, "diffthis", ex_diffthis, + TRLBAR), + EX(CMD_digraphs, "digraphs", ex_digraphs, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_djump, "djump", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), + EX(CMD_dlist, "dlist", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_doautocmd, "doautocmd", ex_doautocmd, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_doautoall, "doautoall", ex_doautoall, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_drop, "drop", ex_drop, + FILES|EDITCMD|NEEDARG|ARGOPT|TRLBAR), + EX(CMD_dsearch, "dsearch", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_dsplit, "dsplit", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), + EX(CMD_edit, "edit", ex_edit, + BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_earlier, "earlier", ex_later, + TRLBAR|EXTRA|NOSPC|CMDWIN), + EX(CMD_echo, "echo", ex_echo, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_echoerr, "echoerr", ex_execute, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_echohl, "echohl", ex_echohl, + EXTRA|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_echomsg, "echomsg", ex_execute, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_echon, "echon", ex_echo, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_else, "else", ex_else, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_elseif, "elseif", ex_else, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_emenu, "emenu", ex_emenu, + NEEDARG|EXTRA|TRLBAR|NOTRLCOM|RANGE|NOTADR|CMDWIN), + EX(CMD_endif, "endif", ex_endif, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_endfunction, "endfunction", ex_endfunction, + TRLBAR|CMDWIN), + EX(CMD_endfor, "endfor", ex_endwhile, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_endtry, "endtry", ex_endtry, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_endwhile, "endwhile", ex_endwhile, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_enew, "enew", ex_edit, + BANG|TRLBAR), + EX(CMD_ex, "ex", ex_edit, + BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_execute, "execute", ex_execute, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_exit, "exit", ex_exit, + RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), + EX(CMD_exusage, "exusage", ex_exusage, + TRLBAR), + EX(CMD_file, "file", ex_file, + RANGE|NOTADR|ZEROR|BANG|FILE1|TRLBAR), + EX(CMD_files, "files", buflist_list, + BANG|TRLBAR|CMDWIN), + EX(CMD_filetype, "filetype", ex_filetype, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_find, "find", ex_find, + RANGE|NOTADR|BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_finally, "finally", ex_finally, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_finish, "finish", ex_finish, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_first, "first", ex_rewind, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_fixdel, "fixdel", do_fixdel, + TRLBAR|CMDWIN), + EX(CMD_fold, "fold", ex_fold, + RANGE|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_foldclose, "foldclose", ex_foldopen, + RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_folddoopen, "folddoopen", ex_folddo, + RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_folddoclosed, "folddoclosed", ex_folddo, + RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_foldopen, "foldopen", ex_foldopen, + RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_for, "for", ex_while, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_function, "function", ex_function, + EXTRA|BANG|CMDWIN), + EX(CMD_global, "global", ex_global, + RANGE|WHOLEFOLD|BANG|EXTRA|DFLALL|SBOXOK|CMDWIN), + EX(CMD_goto, "goto", ex_goto, + RANGE|NOTADR|COUNT|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_grep, "grep", ex_make, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_grepadd, "grepadd", ex_make, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_gui, "gui", ex_gui, + BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN), + EX(CMD_gvim, "gvim", ex_gui, + BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN), + EX(CMD_help, "help", ex_help, + BANG|EXTRA|NOTRLCOM), + EX(CMD_helpfind, "helpfind", ex_helpfind, + EXTRA|NOTRLCOM), + EX(CMD_helpgrep, "helpgrep", ex_helpgrep, + EXTRA|NOTRLCOM|NEEDARG), + EX(CMD_helptags, "helptags", ex_helptags, + NEEDARG|FILES|TRLBAR|CMDWIN), + EX(CMD_hardcopy, "hardcopy", ex_hardcopy, + RANGE|COUNT|EXTRA|TRLBAR|DFLALL|BANG), + EX(CMD_highlight, "highlight", ex_highlight, + BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_hide, "hide", ex_hide, + BANG|EXTRA|NOTRLCOM), + EX(CMD_history, "history", ex_history, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_insert, "insert", ex_append, + BANG|RANGE|TRLBAR|CMDWIN|MODIFY), + EX(CMD_iabbrev, "iabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_iabclear, "iabclear", ex_abclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_if, "if", ex_if, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_ijump, "ijump", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), + EX(CMD_ilist, "ilist", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_imap, "imap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_imapclear, "imapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_imenu, "imenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_inoremap, "inoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_inoreabbrev, "inoreabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_inoremenu, "inoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_intro, "intro", ex_intro, + TRLBAR|CMDWIN), + EX(CMD_isearch, "isearch", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_isplit, "isplit", ex_findpat, + BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA), + EX(CMD_iunmap, "iunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_iunabbrev, "iunabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_iunmenu, "iunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_join, "join", ex_join, + BANG|RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), + EX(CMD_jumps, "jumps", ex_jumps, + TRLBAR|CMDWIN), + EX(CMD_k, "k", ex_mark, + RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_keepmarks, "keepmarks", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_keepjumps, "keepjumps", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_keeppatterns, "keeppatterns", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_keepalt, "keepalt", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_list, "list", ex_print, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), + EX(CMD_lNext, "lNext", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_lNfile, "lNfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_last, "last", ex_last, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_language, "language", ex_language, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_laddexpr, "laddexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR), + EX(CMD_laddbuffer, "laddbuffer", ex_cbuffer, + RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_laddfile, "laddfile", ex_cfile, + TRLBAR|FILE1), + EX(CMD_later, "later", ex_later, + TRLBAR|EXTRA|NOSPC|CMDWIN), + EX(CMD_lbuffer, "lbuffer", ex_cbuffer, + BANG|RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_lcd, "lcd", ex_cd, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_lchdir, "lchdir", ex_cd, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_lclose, "lclose", ex_cclose, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_lcscope, "lcscope", do_cscope, + EXTRA|NOTRLCOM|XFILE), + EX(CMD_left, "left", ex_align, + TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), + EX(CMD_leftabove, "leftabove", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_let, "let", ex_let, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_lexpr, "lexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG), + EX(CMD_lfile, "lfile", ex_cfile, + TRLBAR|FILE1|BANG), + EX(CMD_lfirst, "lfirst", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_lgetfile, "lgetfile", ex_cfile, + TRLBAR|FILE1), + EX(CMD_lgetbuffer, "lgetbuffer", ex_cbuffer, + RANGE|NOTADR|WORD1|TRLBAR), + EX(CMD_lgetexpr, "lgetexpr", ex_cexpr, + NEEDARG|WORD1|NOTRLCOM|TRLBAR), + EX(CMD_lgrep, "lgrep", ex_make, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_lgrepadd, "lgrepadd", ex_make, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_lhelpgrep, "lhelpgrep", ex_helpgrep, + EXTRA|NOTRLCOM|NEEDARG), + EX(CMD_ll, "ll", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_llast, "llast", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_llist, "llist", qf_list, + BANG|EXTRA|TRLBAR|CMDWIN), + EX(CMD_lmap, "lmap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_lmapclear, "lmapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_lmake, "lmake", ex_make, + BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_lnoremap, "lnoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_lnext, "lnext", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_lnewer, "lnewer", qf_age, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_lnfile, "lnfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_loadview, "loadview", ex_loadview, + FILE1|TRLBAR), + EX(CMD_loadkeymap, "loadkeymap", ex_loadkeymap, + CMDWIN), + EX(CMD_lockmarks, "lockmarks", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_lockvar, "lockvar", ex_lockvar, + BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), + EX(CMD_lolder, "lolder", qf_age, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_lopen, "lopen", ex_copen, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_lprevious, "lprevious", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_lpfile, "lpfile", ex_cnext, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_lrewind, "lrewind", ex_cc, + RANGE|NOTADR|COUNT|TRLBAR|BANG), + EX(CMD_ltag, "ltag", ex_tag, + NOTADR|TRLBAR|BANG|WORD1), + EX(CMD_lua, "lua", ex_lua, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_luado, "luado", ex_luado, + RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), + EX(CMD_luafile, "luafile", ex_luafile, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_lunmap, "lunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_lvimgrep, "lvimgrep", ex_vimgrep, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_lvimgrepadd, "lvimgrepadd", ex_vimgrep, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_lwindow, "lwindow", ex_cwindow, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_ls, "ls", buflist_list, + BANG|TRLBAR|CMDWIN), + EX(CMD_move, "move", ex_copymove, + RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), + EX(CMD_mark, "mark", ex_mark, + RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_make, "make", ex_make, + BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_map, "map", ex_map, + BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_mapclear, "mapclear", ex_mapclear, + EXTRA|BANG|TRLBAR|CMDWIN), + EX(CMD_marks, "marks", do_marks, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_match, "match", ex_match, + RANGE|NOTADR|EXTRA|CMDWIN), + EX(CMD_menu, "menu", ex_menu, + RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_menutranslate, "menutranslate", ex_menutranslate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_messages, "messages", ex_messages, + TRLBAR|CMDWIN), + EX(CMD_mkexrc, "mkexrc", ex_mkrc, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_mksession, "mksession", ex_mkrc, + BANG|FILE1|TRLBAR), + EX(CMD_mkspell, "mkspell", ex_mkspell, + BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_mkvimrc, "mkvimrc", ex_mkrc, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_mkview, "mkview", ex_mkrc, + BANG|FILE1|TRLBAR), + EX(CMD_mode, "mode", ex_mode, + WORD1|TRLBAR|CMDWIN), + EX(CMD_mzscheme, "mzscheme", ex_mzscheme, + RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK), + EX(CMD_mzfile, "mzfile", ex_mzfile, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_next, "next", ex_next, + RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_nbkey, "nbkey", ex_nbkey, + EXTRA|NOTADR|NEEDARG), + EX(CMD_nbclose, "nbclose", ex_nbclose, + TRLBAR|CMDWIN), + EX(CMD_nbstart, "nbstart", ex_nbstart, + WORD1|TRLBAR|CMDWIN), + EX(CMD_new, "new", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_nmap, "nmap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_nmapclear, "nmapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_nmenu, "nmenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_nnoremap, "nnoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_nnoremenu, "nnoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_noremap, "noremap", ex_map, + BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_noautocmd, "noautocmd", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_nohlsearch, "nohlsearch", ex_nohlsearch, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_noreabbrev, "noreabbrev", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_noremenu, "noremenu", ex_menu, + RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_normal, "normal", ex_normal, + RANGE|BANG|EXTRA|NEEDARG|NOTRLCOM|USECTRLV|SBOXOK|CMDWIN), + EX(CMD_number, "number", ex_print, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), + EX(CMD_nunmap, "nunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_nunmenu, "nunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_open, "open", ex_open, + RANGE|BANG|EXTRA), + EX(CMD_oldfiles, "oldfiles", ex_oldfiles, + BANG|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_omap, "omap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_omapclear, "omapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_omenu, "omenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_only, "only", ex_only, + BANG|TRLBAR), + EX(CMD_onoremap, "onoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_onoremenu, "onoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_options, "options", ex_options, + TRLBAR), + EX(CMD_ounmap, "ounmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_ounmenu, "ounmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_ownsyntax, "ownsyntax", ex_ownsyntax, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_print, "print", ex_print, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK), + EX(CMD_pclose, "pclose", ex_pclose, + BANG|TRLBAR), + EX(CMD_perl, "perl", ex_perl, + RANGE|EXTRA|DFLALL|NEEDARG|SBOXOK|CMDWIN), + EX(CMD_perldo, "perldo", ex_perldo, + RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN), + EX(CMD_pedit, "pedit", ex_pedit, + BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_pop, "pop", ex_tag, + RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR), + EX(CMD_popup, "popup", ex_popup, + NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN), + EX(CMD_ppop, "ppop", ex_ptag, + RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR), + EX(CMD_preserve, "preserve", ex_preserve, + TRLBAR), + EX(CMD_previous, "previous", ex_previous, + EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_promptfind, "promptfind", gui_mch_find_dialog, + EXTRA|NOTRLCOM|CMDWIN), + EX(CMD_promptrepl, "promptrepl", gui_mch_replace_dialog, + EXTRA|NOTRLCOM|CMDWIN), + EX(CMD_profile, "profile", ex_profile, + BANG|EXTRA|TRLBAR|CMDWIN), + EX(CMD_profdel, "profdel", ex_breakdel, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_psearch, "psearch", ex_psearch, + BANG|RANGE|WHOLEFOLD|DFLALL|EXTRA), + EX(CMD_ptag, "ptag", ex_ptag, + RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), + EX(CMD_ptNext, "ptNext", ex_ptag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_ptfirst, "ptfirst", ex_ptag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_ptjump, "ptjump", ex_ptag, + BANG|TRLBAR|WORD1), + EX(CMD_ptlast, "ptlast", ex_ptag, + BANG|TRLBAR), + EX(CMD_ptnext, "ptnext", ex_ptag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_ptprevious, "ptprevious", ex_ptag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_ptrewind, "ptrewind", ex_ptag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_ptselect, "ptselect", ex_ptag, + BANG|TRLBAR|WORD1), + EX(CMD_put, "put", ex_put, + RANGE|WHOLEFOLD|BANG|REGSTR|TRLBAR|ZEROR|CMDWIN|MODIFY), + EX(CMD_pwd, "pwd", ex_pwd, + TRLBAR|CMDWIN), + EX(CMD_python, "python", ex_python, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_pydo, "pydo", ex_pydo, + RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), + EX(CMD_pyfile, "pyfile", ex_pyfile, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_py3, "py3", ex_py3, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_py3do, "py3do", ex_py3do, + RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), + EX(CMD_python3, "python3", ex_py3, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_py3file, "py3file", ex_py3file, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_quit, "quit", ex_quit, + BANG|TRLBAR|CMDWIN), + EX(CMD_quitall, "quitall", ex_quit_all, + BANG|TRLBAR), + EX(CMD_qall, "qall", ex_quit_all, + BANG|TRLBAR|CMDWIN), + EX(CMD_read, "read", ex_read, + BANG|RANGE|WHOLEFOLD|FILE1|ARGOPT|TRLBAR|ZEROR|CMDWIN|MODIFY), + EX(CMD_recover, "recover", ex_recover, + BANG|FILE1|TRLBAR), + EX(CMD_redo, "redo", ex_redo, + TRLBAR|CMDWIN), + EX(CMD_redir, "redir", ex_redir, + BANG|FILES|TRLBAR|CMDWIN), + EX(CMD_redraw, "redraw", ex_redraw, + BANG|TRLBAR|CMDWIN), + EX(CMD_redrawstatus, "redrawstatus", ex_redrawstatus, + BANG|TRLBAR|CMDWIN), + EX(CMD_registers, "registers", ex_display, + EXTRA|NOTRLCOM|TRLBAR|CMDWIN), + EX(CMD_resize, "resize", ex_resize, + RANGE|NOTADR|TRLBAR|WORD1), + EX(CMD_retab, "retab", ex_retab, + TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY), + EX(CMD_return, "return", ex_return, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_rewind, "rewind", ex_rewind, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_right, "right", ex_align, + TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), + EX(CMD_rightbelow, "rightbelow", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_runtime, "runtime", ex_runtime, + BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_ruby, "ruby", ex_ruby, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_rubydo, "rubydo", ex_rubydo, + RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), + EX(CMD_rubyfile, "rubyfile", ex_rubyfile, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_rundo, "rundo", ex_rundo, + NEEDARG|FILE1), + EX(CMD_rviminfo, "rviminfo", ex_viminfo, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_substitute, "substitute", do_sub, + RANGE|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_sNext, "sNext", ex_previous, + EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_sargument, "sargument", ex_argument, + BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_sall, "sall", ex_all, + BANG|RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sandbox, "sandbox", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_saveas, "saveas", ex_write, + BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR), + EX(CMD_sbuffer, "sbuffer", ex_buffer, + BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), + EX(CMD_sbNext, "sbNext", ex_bprevious, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sball, "sball", ex_buffer_all, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sbfirst, "sbfirst", ex_brewind, + TRLBAR), + EX(CMD_sblast, "sblast", ex_blast, + TRLBAR), + EX(CMD_sbmodified, "sbmodified", ex_bmodified, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sbnext, "sbnext", ex_bnext, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sbprevious, "sbprevious", ex_bprevious, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sbrewind, "sbrewind", ex_brewind, + TRLBAR), + EX(CMD_scriptnames, "scriptnames", ex_scriptnames, + TRLBAR|CMDWIN), + EX(CMD_scriptencoding, "scriptencoding", ex_scriptencoding, + WORD1|TRLBAR|CMDWIN), + EX(CMD_scscope, "scscope", do_scscope, + EXTRA|NOTRLCOM), + EX(CMD_set, "set", ex_set, + TRLBAR|EXTRA|CMDWIN|SBOXOK), + EX(CMD_setfiletype, "setfiletype", ex_setfiletype, + TRLBAR|EXTRA|NEEDARG|CMDWIN), + EX(CMD_setglobal, "setglobal", ex_set, + TRLBAR|EXTRA|CMDWIN|SBOXOK), + EX(CMD_setlocal, "setlocal", ex_set, + TRLBAR|EXTRA|CMDWIN|SBOXOK), + EX(CMD_sfind, "sfind", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_sfirst, "sfirst", ex_rewind, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_shell, "shell", ex_shell, + TRLBAR|CMDWIN), + EX(CMD_simalt, "simalt", ex_simalt, + NEEDARG|WORD1|TRLBAR|CMDWIN), + EX(CMD_sign, "sign", ex_sign, + NEEDARG|RANGE|NOTADR|EXTRA|CMDWIN), + EX(CMD_silent, "silent", ex_wrongmodifier, + NEEDARG|EXTRA|BANG|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_sleep, "sleep", ex_sleep, + RANGE|NOTADR|COUNT|EXTRA|TRLBAR|CMDWIN), + EX(CMD_slast, "slast", ex_last, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_smagic, "smagic", ex_submagic, + RANGE|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_smap, "smap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_smapclear, "smapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_smenu, "smenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_snext, "snext", ex_next, + RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_sniff, "sniff", ex_sniff, + EXTRA|TRLBAR), + EX(CMD_snomagic, "snomagic", ex_submagic, + RANGE|WHOLEFOLD|EXTRA|CMDWIN), + EX(CMD_snoremap, "snoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_snoremenu, "snoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_source, "source", ex_source, + BANG|FILE1|TRLBAR|SBOXOK|CMDWIN), + EX(CMD_sort, "sort", ex_sort, + RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY), + EX(CMD_split, "split", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_spellgood, "spellgood", ex_spell, + BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), + EX(CMD_spelldump, "spelldump", ex_spelldump, + BANG|TRLBAR), + EX(CMD_spellinfo, "spellinfo", ex_spellinfo, + TRLBAR), + EX(CMD_spellrepall, "spellrepall", ex_spellrepall, + TRLBAR), + EX(CMD_spellundo, "spellundo", ex_spell, + BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), + EX(CMD_spellwrong, "spellwrong", ex_spell, + BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR), + EX(CMD_sprevious, "sprevious", ex_previous, + EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_srewind, "srewind", ex_rewind, + EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_stop, "stop", ex_stop, + TRLBAR|BANG|CMDWIN), + EX(CMD_stag, "stag", ex_stag, + RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), + EX(CMD_startinsert, "startinsert", ex_startinsert, + BANG|TRLBAR|CMDWIN), + EX(CMD_startgreplace, "startgreplace", ex_startinsert, + BANG|TRLBAR|CMDWIN), + EX(CMD_startreplace, "startreplace", ex_startinsert, + BANG|TRLBAR|CMDWIN), + EX(CMD_stopinsert, "stopinsert", ex_stopinsert, + BANG|TRLBAR|CMDWIN), + EX(CMD_stjump, "stjump", ex_stag, + BANG|TRLBAR|WORD1), + EX(CMD_stselect, "stselect", ex_stag, + BANG|TRLBAR|WORD1), + EX(CMD_sunhide, "sunhide", ex_buffer_all, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_sunmap, "sunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_sunmenu, "sunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_suspend, "suspend", ex_stop, + TRLBAR|BANG|CMDWIN), + EX(CMD_sview, "sview", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_swapname, "swapname", ex_swapname, + TRLBAR|CMDWIN), + EX(CMD_syntax, "syntax", ex_syntax, + EXTRA|NOTRLCOM|CMDWIN), + EX(CMD_syntime, "syntime", ex_syntime, + NEEDARG|WORD1|TRLBAR|CMDWIN), + EX(CMD_syncbind, "syncbind", ex_syncbind, + TRLBAR), + EX(CMD_t, "t", ex_copymove, + RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY), + EX(CMD_tNext, "tNext", ex_tag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_tag, "tag", ex_tag, + RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), + EX(CMD_tags, "tags", do_tags, + TRLBAR|CMDWIN), + EX(CMD_tab, "tab", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_tabclose, "tabclose", ex_tabclose, + RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN), + EX(CMD_tabdo, "tabdo", ex_listdo, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_tabedit, "tabedit", ex_splitview, + BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_tabfind, "tabfind", ex_splitview, + BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR), + EX(CMD_tabfirst, "tabfirst", ex_tabnext, + TRLBAR), + EX(CMD_tabmove, "tabmove", ex_tabmove, + RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR), + EX(CMD_tablast, "tablast", ex_tabnext, + TRLBAR), + EX(CMD_tabnext, "tabnext", ex_tabnext, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_tabnew, "tabnew", ex_splitview, + BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_tabonly, "tabonly", ex_tabonly, + BANG|TRLBAR|CMDWIN), + EX(CMD_tabprevious, "tabprevious", ex_tabnext, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_tabNext, "tabNext", ex_tabnext, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_tabrewind, "tabrewind", ex_tabnext, + TRLBAR), + EX(CMD_tabs, "tabs", ex_tabs, + TRLBAR|CMDWIN), + EX(CMD_tcl, "tcl", ex_tcl, + RANGE|EXTRA|NEEDARG|CMDWIN), + EX(CMD_tcldo, "tcldo", ex_tcldo, + RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN), + EX(CMD_tclfile, "tclfile", ex_tclfile, + RANGE|FILE1|NEEDARG|CMDWIN), + EX(CMD_tearoff, "tearoff", ex_tearoff, + NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN), + EX(CMD_tfirst, "tfirst", ex_tag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_throw, "throw", ex_throw, + EXTRA|NEEDARG|SBOXOK|CMDWIN), + EX(CMD_tjump, "tjump", ex_tag, + BANG|TRLBAR|WORD1), + EX(CMD_tlast, "tlast", ex_tag, + BANG|TRLBAR), + EX(CMD_tmenu, "tmenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_tnext, "tnext", ex_tag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_topleft, "topleft", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_tprevious, "tprevious", ex_tag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_trewind, "trewind", ex_tag, + RANGE|NOTADR|BANG|TRLBAR|ZEROR), + EX(CMD_try, "try", ex_try, + TRLBAR|SBOXOK|CMDWIN), + EX(CMD_tselect, "tselect", ex_tag, + BANG|TRLBAR|WORD1), + EX(CMD_tunmenu, "tunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_undo, "undo", ex_undo, + RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN), + EX(CMD_undojoin, "undojoin", ex_undojoin, + TRLBAR|CMDWIN), + EX(CMD_undolist, "undolist", ex_undolist, + TRLBAR|CMDWIN), + EX(CMD_unabbreviate, "unabbreviate", ex_abbreviate, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_unhide, "unhide", ex_buffer_all, + RANGE|NOTADR|COUNT|TRLBAR), + EX(CMD_unlet, "unlet", ex_unlet, + BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), + EX(CMD_unlockvar, "unlockvar", ex_lockvar, + BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), + EX(CMD_unmap, "unmap", ex_unmap, + BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_unmenu, "unmenu", ex_menu, + BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_unsilent, "unsilent", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_update, "update", ex_update, + RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR), + EX(CMD_vglobal, "vglobal", ex_global, + RANGE|WHOLEFOLD|EXTRA|DFLALL|CMDWIN), + EX(CMD_version, "version", ex_version, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_verbose, "verbose", ex_wrongmodifier, + NEEDARG|RANGE|NOTADR|EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_vertical, "vertical", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_visual, "visual", ex_edit, + BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_view, "view", ex_edit, + BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_vimgrep, "vimgrep", ex_vimgrep, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep, + RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), + EX(CMD_viusage, "viusage", ex_viusage, + TRLBAR), + EX(CMD_vmap, "vmap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_vmapclear, "vmapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_vmenu, "vmenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_vnoremap, "vnoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_vnew, "vnew", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_vnoremenu, "vnoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_vsplit, "vsplit", ex_splitview, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_vunmap, "vunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_vunmenu, "vunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_write, "write", ex_write, + RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), + EX(CMD_wNext, "wNext", ex_wnext, + RANGE|WHOLEFOLD|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), + EX(CMD_wall, "wall", do_wqall, + BANG|TRLBAR|CMDWIN), + EX(CMD_while, "while", ex_while, + EXTRA|NOTRLCOM|SBOXOK|CMDWIN), + EX(CMD_winsize, "winsize", ex_winsize, + EXTRA|NEEDARG|TRLBAR), + EX(CMD_wincmd, "wincmd", ex_wincmd, + NEEDARG|WORD1|RANGE|NOTADR), + EX(CMD_windo, "windo", ex_listdo, + BANG|NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_winpos, "winpos", ex_winpos, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_wnext, "wnext", ex_wnext, + RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), + EX(CMD_wprevious, "wprevious", ex_wnext, + RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR), + EX(CMD_wq, "wq", ex_exit, + RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR), + EX(CMD_wqall, "wqall", do_wqall, + BANG|FILE1|ARGOPT|DFLALL|TRLBAR), + EX(CMD_wsverb, "wsverb", ex_wsverb, + EXTRA|NOTADR|NEEDARG), + EX(CMD_wundo, "wundo", ex_wundo, + BANG|NEEDARG|FILE1), + EX(CMD_wviminfo, "wviminfo", ex_viminfo, + BANG|FILE1|TRLBAR|CMDWIN), + EX(CMD_xit, "xit", ex_exit, + RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN), + EX(CMD_xall, "xall", do_wqall, + BANG|TRLBAR), + EX(CMD_xmap, "xmap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_xmapclear, "xmapclear", ex_mapclear, + EXTRA|TRLBAR|CMDWIN), + EX(CMD_xmenu, "xmenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_xnoremap, "xnoremap", ex_map, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_xnoremenu, "xnoremenu", ex_menu, + RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_xunmap, "xunmap", ex_unmap, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_xunmenu, "xunmenu", ex_menu, + EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), + EX(CMD_yank, "yank", ex_operators, + RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN), + EX(CMD_z, "z", ex_z, + RANGE|WHOLEFOLD|EXTRA|EXFLAGS|TRLBAR|CMDWIN), + + /* commands that don't start with a lowercase letter */ + EX(CMD_bang, "!", ex_bang, + RANGE|WHOLEFOLD|BANG|FILES|CMDWIN), + EX(CMD_pound, "#", ex_print, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), + EX(CMD_and, "&", do_sub, + RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), + EX(CMD_star, "*", ex_at, + RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN), + EX(CMD_lshift, "<", ex_operators, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), + EX(CMD_equal, "=", ex_equal, + RANGE|TRLBAR|DFLALL|EXFLAGS|CMDWIN), + EX(CMD_rshift, ">", ex_operators, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY), + EX(CMD_at, "@", ex_at, + RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN), + EX(CMD_Next, "Next", ex_previous, + EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), + EX(CMD_Print, "Print", ex_print, + RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN), + EX(CMD_X, "X", ex_X, + TRLBAR), + EX(CMD_tilde, "~", do_sub, + RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY), + +#ifndef DO_DECLARE_EXCMD + CMD_SIZE, /* MUST be after all real commands! */ + CMD_USER = -1, /* User-defined command */ + CMD_USER_BUF = -2 /* User-defined command local to buffer */ +#endif +}; + +#define USER_CMDIDX(idx) ((int)(idx) < 0) + +#ifndef DO_DECLARE_EXCMD +typedef enum CMD_index cmdidx_T; + +/* + * Arguments used for Ex commands. + */ +struct exarg { + char_u *arg; /* argument of the command */ + char_u *nextcmd; /* next command (NULL if none) */ + char_u *cmd; /* the name of the command (except for :make) */ + char_u **cmdlinep; /* pointer to pointer of allocated cmdline */ + cmdidx_T cmdidx; /* the index for the command */ + long argt; /* flags for the command */ + int skip; /* don't execute the command, only parse it */ + int forceit; /* TRUE if ! present */ + int addr_count; /* the number of addresses given */ + linenr_T line1; /* the first line number */ + linenr_T line2; /* the second line number or count */ + int flags; /* extra flags after count: EXFLAG_ */ + char_u *do_ecmd_cmd; /* +command arg to be used in edited file */ + linenr_T do_ecmd_lnum; /* the line number in an edited file */ + int append; /* TRUE with ":w >>file" command */ + int usefilter; /* TRUE with ":w !command" and ":r!command" */ + int amount; /* number of '>' or '<' for shift command */ + int regname; /* register name (NUL if none) */ + int force_bin; /* 0, FORCE_BIN or FORCE_NOBIN */ + int read_edit; /* ++edit argument */ + int force_ff; /* ++ff= argument (index in cmd[]) */ + int force_enc; /* ++enc= argument (index in cmd[]) */ + int bad_char; /* BAD_KEEP, BAD_DROP or replacement byte */ + int useridx; /* user command index */ + char_u *errmsg; /* returned error message */ + char_u *(*getline)__ARGS((int, void *, int)); + void *cookie; /* argument for getline() */ + struct condstack *cstack; /* condition stack for ":if" etc. */ +}; + +#define FORCE_BIN 1 /* ":edit ++bin file" */ +#define FORCE_NOBIN 2 /* ":edit ++nobin file" */ + +/* Values for "flags" */ +#define EXFLAG_LIST 0x01 /* 'l': list */ +#define EXFLAG_NR 0x02 /* '#': number */ +#define EXFLAG_PRINT 0x04 /* 'p': print */ + +#endif diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 0a31ccc108..35aa970aac 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -12,6 +12,48 @@ */ #include "vim.h" +#include "ex_docmd.h" +#include "blowfish.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "digraph.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hardcopy.h" +#include "if_cscope.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "menu.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "version.h" +#include "window.h" #include "os/os.h" static int quitmore = 0; @@ -223,7 +265,7 @@ static void ex_folddo __ARGS((exarg_T *eap)); * Declare cmdnames[]. */ #define DO_DECLARE_EXCMD -#include "ex_cmds.h" +#include "ex_cmds_defs.h" /* * Table used to quickly search for a command, based on its first character. diff --git a/src/ex_docmd.h b/src/ex_docmd.h new file mode 100644 index 0000000000..f3f9ca16ec --- /dev/null +++ b/src/ex_docmd.h @@ -0,0 +1,72 @@ +#ifndef NEOVIM_EX_DOCMD_H +#define NEOVIM_EX_DOCMD_H +/* ex_docmd.c */ +void do_exmode __ARGS((int improved)); +int do_cmdline_cmd __ARGS((char_u *cmd)); +int do_cmdline __ARGS((char_u *cmdline, char_u * + (*fgetline)(int, void *, int), void *cookie, + int flags)); +int getline_equal __ARGS((char_u * + (*fgetline)(int, void *, + int), void *cookie, char_u * + (*func)(int, void *, + int))); +void *getline_cookie __ARGS((char_u *(*fgetline)(int, void *, int), + void *cookie)); +int checkforcmd __ARGS((char_u **pp, char *cmd, int len)); +int modifier_len __ARGS((char_u *cmd)); +int cmd_exists __ARGS((char_u *name)); +char_u *set_one_cmd_context __ARGS((expand_T *xp, char_u *buff)); +char_u *skip_range __ARGS((char_u *cmd, int *ctx)); +void ex_ni __ARGS((exarg_T *eap)); +int expand_filename __ARGS((exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)); +void separate_nextcmd __ARGS((exarg_T *eap)); +int ends_excmd __ARGS((int c)); +char_u *find_nextcmd __ARGS((char_u *p)); +char_u *check_nextcmd __ARGS((char_u *p)); +char_u *get_command_name __ARGS((expand_T *xp, int idx)); +void ex_comclear __ARGS((exarg_T *eap)); +void uc_clear __ARGS((garray_T *gap)); +char_u *get_user_commands __ARGS((expand_T *xp, int idx)); +char_u *get_user_cmd_flags __ARGS((expand_T *xp, int idx)); +char_u *get_user_cmd_nargs __ARGS((expand_T *xp, int idx)); +char_u *get_user_cmd_complete __ARGS((expand_T *xp, int idx)); +int parse_compl_arg __ARGS((char_u *value, int vallen, int *complp, long *argt, + char_u **compl_arg)); +void not_exiting __ARGS((void)); +void tabpage_close __ARGS((int forceit)); +void tabpage_close_other __ARGS((tabpage_T *tp, int forceit)); +void ex_all __ARGS((exarg_T *eap)); +void handle_drop __ARGS((int filec, char_u **filev, int split)); +void alist_clear __ARGS((alist_T *al)); +void alist_init __ARGS((alist_T *al)); +void alist_unlink __ARGS((alist_T *al)); +void alist_new __ARGS((void)); +void alist_expand __ARGS((int *fnum_list, int fnum_len)); +void alist_set __ARGS((alist_T *al, int count, char_u **files, int use_curbuf, + int *fnum_list, + int fnum_len)); +void alist_add __ARGS((alist_T *al, char_u *fname, int set_fnum)); +void alist_slash_adjust __ARGS((void)); +void ex_splitview __ARGS((exarg_T *eap)); +void tabpage_new __ARGS((void)); +void do_exedit __ARGS((exarg_T *eap, win_T *old_curwin)); +void free_cd_dir __ARGS((void)); +void post_chdir __ARGS((int local)); +void ex_cd __ARGS((exarg_T *eap)); +void do_sleep __ARGS((long msec)); +int vim_mkdir_emsg __ARGS((char_u *name, int prot)); +FILE *open_exfile __ARGS((char_u *fname, int forceit, char *mode)); +void update_topline_cursor __ARGS((void)); +void exec_normal_cmd __ARGS((char_u *cmd, int remap, int silent)); +int find_cmdline_var __ARGS((char_u *src, int *usedlen)); +char_u *eval_vars __ARGS((char_u *src, char_u *srcstart, int *usedlen, + linenr_T *lnump, char_u **errormsg, + int *escaped)); +char_u *expand_sfile __ARGS((char_u *arg)); +int put_eol __ARGS((FILE *fd)); +int put_line __ARGS((FILE *fd, char *s)); +void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname)); +char_u *get_behave_arg __ARGS((expand_T *xp, int idx)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EX_DOCMD_H */ diff --git a/src/ex_eval.c b/src/ex_eval.c index 3ccac9e84f..e4148068f5 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -12,6 +12,14 @@ */ #include "vim.h" +#include "ex_eval.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "message.h" +#include "misc2.h" +#include "regexp.h" static void free_msglist __ARGS((struct msglist *l)); diff --git a/src/ex_eval.h b/src/ex_eval.h new file mode 100644 index 0000000000..3685899063 --- /dev/null +++ b/src/ex_eval.h @@ -0,0 +1,41 @@ +#ifndef NEOVIM_EX_EVAL_H +#define NEOVIM_EX_EVAL_H +/* ex_eval.c */ +int aborting __ARGS((void)); +void update_force_abort __ARGS((void)); +int should_abort __ARGS((int retcode)); +int aborted_in_try __ARGS((void)); +int cause_errthrow __ARGS((char_u *mesg, int severe, int *ignore)); +void free_global_msglist __ARGS((void)); +void do_errthrow __ARGS((struct condstack *cstack, char_u *cmdname)); +int do_intthrow __ARGS((struct condstack *cstack)); +char_u *get_exception_string __ARGS((void *value, int type, char_u *cmdname, + int *should_free)); +void discard_current_exception __ARGS((void)); +void report_make_pending __ARGS((int pending, void *value)); +void report_resume_pending __ARGS((int pending, void *value)); +void report_discard_pending __ARGS((int pending, void *value)); +void ex_if __ARGS((exarg_T *eap)); +void ex_endif __ARGS((exarg_T *eap)); +void ex_else __ARGS((exarg_T *eap)); +void ex_while __ARGS((exarg_T *eap)); +void ex_continue __ARGS((exarg_T *eap)); +void ex_break __ARGS((exarg_T *eap)); +void ex_endwhile __ARGS((exarg_T *eap)); +void ex_throw __ARGS((exarg_T *eap)); +void do_throw __ARGS((struct condstack *cstack)); +void ex_try __ARGS((exarg_T *eap)); +void ex_catch __ARGS((exarg_T *eap)); +void ex_finally __ARGS((exarg_T *eap)); +void ex_endtry __ARGS((exarg_T *eap)); +void enter_cleanup __ARGS((cleanup_T *csp)); +void leave_cleanup __ARGS((cleanup_T *csp)); +int cleanup_conditionals __ARGS((struct condstack *cstack, int searched_cond, + int inclusive)); +void rewind_conditionals __ARGS((struct condstack *cstack, int idx, + int cond_type, + int *cond_level)); +void ex_endfunction __ARGS((exarg_T *eap)); +int has_loop_cmd __ARGS((char_u *p)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EX_EVAL_H */ diff --git a/src/ex_getln.c b/src/ex_getln.c index 83a0fd3dcc..c3f389e279 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -12,6 +12,37 @@ */ #include "vim.h" +#include "ex_getln.h" +#include "buffer.h" +#include "charset.h" +#include "digraph.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "fileio.h" +#include "getchar.h" +#include "if_cscope.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "menu.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "window.h" #include "os/os.h" /* diff --git a/src/ex_getln.h b/src/ex_getln.h new file mode 100644 index 0000000000..bf04476e2f --- /dev/null +++ b/src/ex_getln.h @@ -0,0 +1,69 @@ +#ifndef NEOVIM_EX_GETLN_H +#define NEOVIM_EX_GETLN_H +/* ex_getln.c */ +char_u *getcmdline __ARGS((int firstc, long count, int indent)); +char_u *getcmdline_prompt __ARGS((int firstc, char_u *prompt, int attr, + int xp_context, + char_u *xp_arg)); +int text_locked __ARGS((void)); +void text_locked_msg __ARGS((void)); +int curbuf_locked __ARGS((void)); +int allbuf_locked __ARGS((void)); +char_u *getexline __ARGS((int c, void *cookie, int indent)); +char_u *getexmodeline __ARGS((int promptc, void *cookie, int indent)); +int cmdline_overstrike __ARGS((void)); +int cmdline_at_end __ARGS((void)); +colnr_T cmdline_getvcol_cursor __ARGS((void)); +void free_cmdline_buf __ARGS((void)); +void putcmdline __ARGS((int c, int shift)); +void unputcmdline __ARGS((void)); +int put_on_cmdline __ARGS((char_u *str, int len, int redraw)); +char_u *save_cmdline_alloc __ARGS((void)); +void restore_cmdline_alloc __ARGS((char_u *p)); +void cmdline_paste_str __ARGS((char_u *s, int literally)); +void redrawcmdline __ARGS((void)); +void redrawcmd __ARGS((void)); +void compute_cmdrow __ARGS((void)); +void gotocmdline __ARGS((int clr)); +char_u *ExpandOne __ARGS((expand_T *xp, char_u *str, char_u *orig, int options, + int mode)); +void ExpandInit __ARGS((expand_T *xp)); +void ExpandCleanup __ARGS((expand_T *xp)); +void ExpandEscape __ARGS((expand_T *xp, char_u *str, int numfiles, char_u * + *files, + int options)); +char_u *vim_strsave_fnameescape __ARGS((char_u *fname, int shell)); +void tilde_replace __ARGS((char_u *orig_pat, int num_files, char_u **files)); +char_u *sm_gettail __ARGS((char_u *s)); +char_u *addstar __ARGS((char_u *fname, int len, int context)); +void set_cmd_context __ARGS((expand_T *xp, char_u *str, int len, int col)); +int expand_cmdline __ARGS((expand_T *xp, char_u *str, int col, int *matchcount, + char_u ***matches)); +int ExpandGeneric __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, + char_u ***file, char_u *((*func)(expand_T *, int)), + int escaped)); +char_u *globpath __ARGS((char_u *path, char_u *file, int expand_options)); +void init_history __ARGS((void)); +int get_histtype __ARGS((char_u *name)); +void add_to_history __ARGS((int histype, char_u *new_entry, int in_map, int sep)); +int get_history_idx __ARGS((int histype)); +char_u *get_cmdline_str __ARGS((void)); +int get_cmdline_pos __ARGS((void)); +int set_cmdline_pos __ARGS((int pos)); +int get_cmdline_type __ARGS((void)); +char_u *get_history_entry __ARGS((int histype, int idx)); +int clr_history __ARGS((int histype)); +int del_history_entry __ARGS((int histype, char_u *str)); +int del_history_idx __ARGS((int histype, int idx)); +void remove_key_from_history __ARGS((void)); +int get_list_range __ARGS((char_u **str, int *num1, int *num2)); +void ex_history __ARGS((exarg_T *eap)); +void prepare_viminfo_history __ARGS((int asklen, int writing)); +int read_viminfo_history __ARGS((vir_T *virp, int writing)); +void finish_viminfo_history __ARGS((void)); +void write_viminfo_history __ARGS((FILE *fp, int merge)); +void cmd_pchar __ARGS((int c, int offset)); +int cmd_gchar __ARGS((int offset)); +char_u *script_get __ARGS((exarg_T *eap, char_u *cmd)); +/* vim: set ft=c : */ +#endif /* NEOVIM_EX_GETLN_H */ diff --git a/src/farsi.c b/src/farsi.c index 9c28284166..f3c55216f2 100644 --- a/src/farsi.c +++ b/src/farsi.c @@ -7,6 +7,10 @@ * See README.txt for an overview of the Vim source code. */ +#include "farsi.h" +#include "edit.h" +#include "ex_getln.h" + /* * farsi.c: functions for Farsi language * diff --git a/src/farsi.h b/src/farsi.h index a9dd2fb79f..84c3402431 100644 --- a/src/farsi.h +++ b/src/farsi.h @@ -6,6 +6,9 @@ * Do ":help credits" in Vim to see a list of people who contributed. */ +#ifndef NEOVIM_FARSI_H +#define NEOVIM_FARSI_H + /* * Farsi characters are categorized into following types: * @@ -224,3 +227,5 @@ EXTERN char_u farsi_text_5[] = { ' ', YE_, _SIN, RE, ALEF_, _FE, '\0'} #endif ; + +#endif /* NEOVIM_FARSI_H */ diff --git a/src/fileio.c b/src/fileio.c index 8dc31c31c6..482c47e17d 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -12,6 +12,37 @@ */ #include "vim.h" +#include "fileio.h" +#include "blowfish.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "mbyte.h" +#include "memfile.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "sha256.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" #include "os/os.h" diff --git a/src/fileio.h b/src/fileio.h new file mode 100644 index 0000000000..add97d37d6 --- /dev/null +++ b/src/fileio.h @@ -0,0 +1,85 @@ +#ifndef NEOVIM_FILEIO_H +#define NEOVIM_FILEIO_H +/* fileio.c */ +void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr)); +int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, + linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T * + eap, + int flags)); +int prep_exarg __ARGS((exarg_T *eap, buf_T *buf)); +void set_file_options __ARGS((int set_options, exarg_T *eap)); +void set_forced_fenc __ARGS((exarg_T *eap)); +int prepare_crypt_read __ARGS((FILE *fp)); +char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp)); +int check_file_readonly __ARGS((char_u *fname, int perm)); +int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, + linenr_T end, exarg_T *eap, int append, int forceit, + int reset_changed, + int filtering)); +void msg_add_fname __ARGS((buf_T *buf, char_u *fname)); +void msg_add_lines __ARGS((int insert_space, long lnum, off_t nchars)); +char_u *shorten_fname1 __ARGS((char_u *full_path)); +char_u *shorten_fname __ARGS((char_u *full_path, char_u *dir_name)); +void shorten_fnames __ARGS((int force)); +void shorten_filenames __ARGS((char_u **fnames, int count)); +char_u *modname __ARGS((char_u *fname, char_u *ext, int prepend_dot)); +char_u *buf_modname __ARGS((int shortname, char_u *fname, char_u *ext, + int prepend_dot)); +int vim_fgets __ARGS((char_u *buf, int size, FILE *fp)); +int tag_fgets __ARGS((char_u *buf, int size, FILE *fp)); +int vim_rename __ARGS((char_u *from, char_u *to)); +int check_timestamps __ARGS((int focus)); +int buf_check_timestamp __ARGS((buf_T *buf, int focus)); +void buf_reload __ARGS((buf_T *buf, int orig_mode)); +void buf_store_time __ARGS((buf_T *buf, struct stat *st, char_u *fname)); +void write_lnum_adjust __ARGS((linenr_T offset)); +void vim_deltempdir __ARGS((void)); +char_u *vim_tempname __ARGS((int extra_char)); +void forward_slash __ARGS((char_u *fname)); +void aubuflocal_remove __ARGS((buf_T *buf)); +int au_has_group __ARGS((char_u *name)); +void do_augroup __ARGS((char_u *arg, int del_group)); +void free_all_autocmds __ARGS((void)); +int check_ei __ARGS((void)); +char_u *au_event_disable __ARGS((char *what)); +void au_event_restore __ARGS((char_u *old_ei)); +void do_autocmd __ARGS((char_u *arg, int forceit)); +int do_doautocmd __ARGS((char_u *arg, int do_msg)); +void ex_doautoall __ARGS((exarg_T *eap)); +int check_nomodeline __ARGS((char_u **argp)); +void aucmd_prepbuf __ARGS((aco_save_T *aco, buf_T *buf)); +void aucmd_restbuf __ARGS((aco_save_T *aco)); +int apply_autocmds __ARGS((event_T event, char_u *fname, char_u *fname_io, + int force, + buf_T *buf)); +int apply_autocmds_retval __ARGS((event_T event, char_u *fname, char_u * + fname_io, int force, buf_T *buf, + int *retval)); +int has_cursorhold __ARGS((void)); +int trigger_cursorhold __ARGS((void)); +int has_cursormoved __ARGS((void)); +int has_cursormovedI __ARGS((void)); +int has_textchanged __ARGS((void)); +int has_textchangedI __ARGS((void)); +int has_insertcharpre __ARGS((void)); +void block_autocmds __ARGS((void)); +void unblock_autocmds __ARGS((void)); +int is_autocmd_blocked __ARGS((void)); +char_u *getnextac __ARGS((int c, void *cookie, int indent)); +int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf)); +char_u *get_augroup_name __ARGS((expand_T *xp, int idx)); +char_u *set_context_in_autocmd __ARGS((expand_T *xp, char_u *arg, int doautocmd)); +char_u *get_event_name __ARGS((expand_T *xp, int idx)); +int autocmd_supported __ARGS((char_u *name)); +int au_exists __ARGS((char_u *arg)); +int match_file_pat __ARGS((char_u *pattern, regprog_T *prog, char_u *fname, + char_u *sfname, char_u *tail, + int allow_dirs)); +int match_file_list __ARGS((char_u *list, char_u *sfname, char_u *ffname)); +char_u *file_pat_to_reg_pat __ARGS((char_u *pat, char_u *pat_end, + char *allow_dirs, + int no_bslash)); +long read_eintr __ARGS((int fd, void *buf, size_t bufsize)); +long write_eintr __ARGS((int fd, void *buf, size_t bufsize)); +/* vim: set ft=c : */ +#endif /* NEOVIM_FILEIO_H */ diff --git a/src/fold.c b/src/fold.c index 7a967d8be0..47e5cdfdd2 100644 --- a/src/fold.c +++ b/src/fold.c @@ -13,7 +13,21 @@ */ #include "vim.h" - +#include "fold.h" +#include "charset.h" +#include "diff.h" +#include "eval.h" +#include "ex_docmd.h" +#include "mark.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "screen.h" +#include "syntax.h" +#include "undo.h" /* local declarations. {{{1 */ /* typedef fold_T {{{2 */ diff --git a/src/fold.h b/src/fold.h new file mode 100644 index 0000000000..3ad08b01e5 --- /dev/null +++ b/src/fold.h @@ -0,0 +1,53 @@ +#ifndef NEOVIM_FOLD_H +#define NEOVIM_FOLD_H +/* fold.c */ +void copyFoldingState __ARGS((win_T *wp_from, win_T *wp_to)); +int hasAnyFolding __ARGS((win_T *win)); +int hasFolding __ARGS((linenr_T lnum, linenr_T *firstp, linenr_T *lastp)); +int hasFoldingWin __ARGS((win_T *win, linenr_T lnum, linenr_T *firstp, + linenr_T *lastp, int cache, + foldinfo_T *infop)); +int foldLevel __ARGS((linenr_T lnum)); +int lineFolded __ARGS((win_T *win, linenr_T lnum)); +long foldedCount __ARGS((win_T *win, linenr_T lnum, foldinfo_T *infop)); +int foldmethodIsManual __ARGS((win_T *wp)); +int foldmethodIsIndent __ARGS((win_T *wp)); +int foldmethodIsExpr __ARGS((win_T *wp)); +int foldmethodIsMarker __ARGS((win_T *wp)); +int foldmethodIsSyntax __ARGS((win_T *wp)); +int foldmethodIsDiff __ARGS((win_T *wp)); +void closeFold __ARGS((linenr_T lnum, long count)); +void closeFoldRecurse __ARGS((linenr_T lnum)); +void opFoldRange __ARGS((linenr_T first, linenr_T last, int opening, + int recurse, + int had_visual)); +void openFold __ARGS((linenr_T lnum, long count)); +void openFoldRecurse __ARGS((linenr_T lnum)); +void foldOpenCursor __ARGS((void)); +void newFoldLevel __ARGS((void)); +void foldCheckClose __ARGS((void)); +int foldManualAllowed __ARGS((int create)); +void foldCreate __ARGS((linenr_T start, linenr_T end)); +void deleteFold __ARGS((linenr_T start, linenr_T end, int recursive, + int had_visual)); +void clearFolding __ARGS((win_T *win)); +void foldUpdate __ARGS((win_T *wp, linenr_T top, linenr_T bot)); +void foldUpdateAll __ARGS((win_T *win)); +int foldMoveTo __ARGS((int updown, int dir, long count)); +void foldInitWin __ARGS((win_T *new_win)); +int find_wl_entry __ARGS((win_T *win, linenr_T lnum)); +void foldAdjustVisual __ARGS((void)); +void foldAdjustCursor __ARGS((void)); +void cloneFoldGrowArray __ARGS((garray_T *from, garray_T *to)); +void deleteFoldRecurse __ARGS((garray_T *gap)); +void foldMarkAdjust __ARGS((win_T *wp, linenr_T line1, linenr_T line2, + long amount, + long amount_after)); +int getDeepestNesting __ARGS((void)); +char_u *get_foldtext __ARGS((win_T *wp, linenr_T lnum, linenr_T lnume, + foldinfo_T *foldinfo, + char_u *buf)); +void foldtext_cleanup __ARGS((char_u *str)); +int put_folds __ARGS((FILE *fd, win_T *wp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_FOLD_H */ diff --git a/src/getchar.c b/src/getchar.c index 91779b348a..7303e3739e 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -17,6 +17,27 @@ */ #include "vim.h" +#include "getchar.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "regexp.h" +#include "screen.h" +#include "term.h" +#include "ui.h" +#include "undo.h" /* * These buffers are used for storing: diff --git a/src/getchar.h b/src/getchar.h new file mode 100644 index 0000000000..131286ee50 --- /dev/null +++ b/src/getchar.h @@ -0,0 +1,77 @@ +#ifndef NEOVIM_GETCHAR_H +#define NEOVIM_GETCHAR_H +/* getchar.c */ +void free_buff __ARGS((struct buffheader *buf)); +char_u *get_recorded __ARGS((void)); +char_u *get_inserted __ARGS((void)); +int stuff_empty __ARGS((void)); +void typeahead_noflush __ARGS((int c)); +void flush_buffers __ARGS((int flush_typeahead)); +void ResetRedobuff __ARGS((void)); +void CancelRedo __ARGS((void)); +void saveRedobuff __ARGS((void)); +void restoreRedobuff __ARGS((void)); +void AppendToRedobuff __ARGS((char_u *s)); +void AppendToRedobuffLit __ARGS((char_u *str, int len)); +void AppendCharToRedobuff __ARGS((int c)); +void AppendNumberToRedobuff __ARGS((long n)); +void stuffReadbuff __ARGS((char_u *s)); +void stuffReadbuffLen __ARGS((char_u *s, long len)); +void stuffReadbuffSpec __ARGS((char_u *s)); +void stuffcharReadbuff __ARGS((int c)); +void stuffnumReadbuff __ARGS((long n)); +int start_redo __ARGS((long count, int old_redo)); +int start_redo_ins __ARGS((void)); +void stop_redo_ins __ARGS((void)); +int ins_typebuf __ARGS((char_u *str, int noremap, int offset, int nottyped, + int silent)); +void ins_char_typebuf __ARGS((int c)); +int typebuf_changed __ARGS((int tb_change_cnt)); +int typebuf_typed __ARGS((void)); +int typebuf_maplen __ARGS((void)); +void del_typebuf __ARGS((int len, int offset)); +int alloc_typebuf __ARGS((void)); +void free_typebuf __ARGS((void)); +int save_typebuf __ARGS((void)); +void save_typeahead __ARGS((tasave_T *tp)); +void restore_typeahead __ARGS((tasave_T *tp)); +void openscript __ARGS((char_u *name, int directly)); +void close_all_scripts __ARGS((void)); +int using_script __ARGS((void)); +void before_blocking __ARGS((void)); +void updatescript __ARGS((int c)); +int vgetc __ARGS((void)); +int safe_vgetc __ARGS((void)); +int plain_vgetc __ARGS((void)); +int vpeekc __ARGS((void)); +int vpeekc_nomap __ARGS((void)); +int vpeekc_any __ARGS((void)); +int char_avail __ARGS((void)); +void vungetc __ARGS((int c)); +int inchar __ARGS((char_u *buf, int maxlen, long wait_time, int tb_change_cnt)); +int fix_input_buffer __ARGS((char_u *buf, int len, int script)); +int input_available __ARGS((void)); +int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev)); +int get_map_mode __ARGS((char_u **cmdp, int forceit)); +void map_clear __ARGS((char_u *cmdp, char_u *arg, int forceit, int abbr)); +void map_clear_int __ARGS((buf_T *buf, int mode, int local, int abbr)); +char_u *map_mode_to_chars __ARGS((int mode)); +int map_to_exists __ARGS((char_u *str, char_u *modechars, int abbr)); +int map_to_exists_mode __ARGS((char_u *rhs, int mode, int abbr)); +char_u *set_context_in_map_cmd __ARGS((expand_T *xp, char_u *cmd, char_u *arg, + int forceit, int isabbrev, int isunmap, + cmdidx_T cmdidx)); +int ExpandMappings __ARGS((regmatch_T *regmatch, int *num_file, char_u ***file)); +int check_abbr __ARGS((int c, char_u *ptr, int col, int mincol)); +char_u *vim_strsave_escape_csi __ARGS((char_u *p)); +void vim_unescape_csi __ARGS((char_u *p)); +int makemap __ARGS((FILE *fd, buf_T *buf)); +int put_escstr __ARGS((FILE *fd, char_u *strstart, int what)); +void check_map_keycodes __ARGS((void)); +char_u *check_map __ARGS((char_u *keys, int mode, int exact, int ign_mod, + int abbr, mapblock_T **mp_ptr, + int *local_ptr)); +void init_mappings __ARGS((void)); +void add_map __ARGS((char_u *map, int mode)); +/* vim: set ft=c : */ +#endif /* NEOVIM_GETCHAR_H */ diff --git a/src/globals.h b/src/globals.h index e6db0d866b..056c098368 100644 --- a/src/globals.h +++ b/src/globals.h @@ -6,6 +6,11 @@ * Do ":help credits" in Vim to see a list of people who contributed. */ +#ifndef NEOVIM_GLOBALS_H +#define NEOVIM_GLOBALS_H + +#include "mbyte.h" + /* * definition of global variables */ @@ -1197,3 +1202,5 @@ EXTERN char *ignoredp; * Optional Arabic support. Include it here, so EXTERN and INIT are defined. */ # include "arabic.h" + +#endif /* NEOVIM_GLOBALS_H */ diff --git a/src/hangulin.c b/src/hangulin.c index c04a1800ba..185bf0a5bd 100644 --- a/src/hangulin.c +++ b/src/hangulin.c @@ -8,6 +8,12 @@ */ #include "vim.h" +#include "hangulin.h" +#include "message.h" +#include "misc1.h" +#include "screen.h" +#include "term.h" +#include "ui.h" #ifndef HANGUL_DEFAULT_KEYBOARD # define HANGUL_DEFAULT_KEYBOARD 3 diff --git a/src/hangulin.h b/src/hangulin.h new file mode 100644 index 0000000000..1023955c0d --- /dev/null +++ b/src/hangulin.h @@ -0,0 +1,12 @@ +#ifndef NEOVIM_HANGULIN_H +#define NEOVIM_HANGULIN_H +/* hangulin.c */ +int hangul_input_state_get __ARGS((void)); +void hangul_input_state_set __ARGS((int state)); +int im_get_status __ARGS((void)); +void hangul_input_state_toggle __ARGS((void)); +void hangul_keyboard_set __ARGS((void)); +int hangul_input_process __ARGS((char_u *s, int len)); +void hangul_input_clear __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_HANGULIN_H */ diff --git a/src/hardcopy.c b/src/hardcopy.c index 9ebe087bca..4f5ef53799 100644 --- a/src/hardcopy.c +++ b/src/hardcopy.c @@ -12,7 +12,24 @@ */ #include "vim.h" -#include "version.h" +#include "version_defs.h" +#include "hardcopy.h" +#include "buffer.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "fileio.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "screen.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" /* * To implement printing on a platform, the following functions must be diff --git a/src/hardcopy.h b/src/hardcopy.h new file mode 100644 index 0000000000..84cbe02be8 --- /dev/null +++ b/src/hardcopy.h @@ -0,0 +1,24 @@ +#ifndef NEOVIM_HARDCOPY_H +#define NEOVIM_HARDCOPY_H +/* hardcopy.c */ +char_u *parse_printoptions __ARGS((void)); +char_u *parse_printmbfont __ARGS((void)); +int prt_header_height __ARGS((void)); +int prt_use_number __ARGS((void)); +int prt_get_unit __ARGS((int idx)); +void ex_hardcopy __ARGS((exarg_T *eap)); +void mch_print_cleanup __ARGS((void)); +int mch_print_init __ARGS((prt_settings_T *psettings, char_u *jobname, + int forceit)); +int mch_print_begin __ARGS((prt_settings_T *psettings)); +void mch_print_end __ARGS((prt_settings_T *psettings)); +int mch_print_end_page __ARGS((void)); +int mch_print_begin_page __ARGS((char_u *str)); +int mch_print_blank_page __ARGS((void)); +void mch_print_start_line __ARGS((int margin, int page_line)); +int mch_print_text_out __ARGS((char_u *p, int len)); +void mch_print_set_font __ARGS((int iBold, int iItalic, int iUnderline)); +void mch_print_set_bg __ARGS((long_u bgcol)); +void mch_print_set_fg __ARGS((long_u fgcol)); +/* vim: set ft=c : */ +#endif /* NEOVIM_HARDCOPY_H */ diff --git a/src/hashtab.c b/src/hashtab.c index 2682885113..cdea743777 100644 --- a/src/hashtab.c +++ b/src/hashtab.c @@ -28,8 +28,9 @@ */ #include "vim.h" - - +#include "hashtab.h" +#include "message.h" +#include "misc2.h" /* Magic value for algorithm that walks through the array. */ #define PERTURB_SHIFT 5 diff --git a/src/hashtab.h b/src/hashtab.h new file mode 100644 index 0000000000..a1dfa63162 --- /dev/null +++ b/src/hashtab.h @@ -0,0 +1,18 @@ +#ifndef NEOVIM_HASHTAB_H +#define NEOVIM_HASHTAB_H +/* hashtab.c */ +void hash_init __ARGS((hashtab_T *ht)); +void hash_clear __ARGS((hashtab_T *ht)); +void hash_clear_all __ARGS((hashtab_T *ht, int off)); +hashitem_T *hash_find __ARGS((hashtab_T *ht, char_u *key)); +hashitem_T *hash_lookup __ARGS((hashtab_T *ht, char_u *key, hash_T hash)); +void hash_debug_results __ARGS((void)); +int hash_add __ARGS((hashtab_T *ht, char_u *key)); +int hash_add_item __ARGS((hashtab_T *ht, hashitem_T *hi, char_u *key, + hash_T hash)); +void hash_remove __ARGS((hashtab_T *ht, hashitem_T *hi)); +void hash_lock __ARGS((hashtab_T *ht)); +void hash_unlock __ARGS((hashtab_T *ht)); +hash_T hash_hash __ARGS((char_u *key)); +/* vim: set ft=c : */ +#endif /* NEOVIM_HASHTAB_H */ diff --git a/src/if_cscope.c b/src/if_cscope.c index cbdcf6b255..47a835a314 100644 --- a/src/if_cscope.c +++ b/src/if_cscope.c @@ -10,14 +10,25 @@ */ #include "vim.h" - +#include "if_cscope.h" +#include "charset.h" +#include "eval.h" +#include "fileio.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "os_unix.h" +#include "quickfix.h" +#include "tag.h" +#include "ui.h" +#include "window.h" #include #include #if defined(UNIX) # include #endif -#include "if_cscope.h" +#include "if_cscope_defs.h" static void cs_usage_msg __ARGS((csid_e x)); static int cs_add __ARGS((exarg_T *eap)); @@ -542,7 +553,7 @@ staterr: #if defined(UNIX) else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) #else - /* WIN32 - substitute define S_ISREG from os_unix.h */ + /* WIN32 - substitute define S_ISREG from os_unix_defs.h */ else if (((statbuf.st_mode) & S_IFMT) == S_IFREG) #endif { diff --git a/src/if_cscope.h b/src/if_cscope.h index 3ed89715fc..35cf432c46 100644 --- a/src/if_cscope.h +++ b/src/if_cscope.h @@ -1,72 +1,16 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * CSCOPE support for Vim added by Andy Kahn - * Ported to Win32 by Sergey Khorev - * - * The basic idea/structure of cscope for Vim was borrowed from Nvi. - * There might be a few lines of code that look similar to what Nvi - * has. If this is a problem and requires inclusion of the annoying - * BSD license, then sue me; I'm not worth much anyway. - */ - - -#if defined(UNIX) -# include /* pid_t */ -# include /* dev_t, ino_t */ -#else -#endif - -#define CSCOPE_SUCCESS 0 -#define CSCOPE_FAILURE -1 - -#define CSCOPE_DBFILE "cscope.out" -#define CSCOPE_PROMPT ">> " - -/* - * s 0name Find this C symbol - * g 1name Find this definition - * d 2name Find functions called by this function - * c 3name Find functions calling this function - * t 4string find text string (cscope 12.9) - * t 4name Find assignments to (cscope 13.3) - * 5pattern change pattern -- NOT USED - * e 6pattern Find this egrep pattern - * f 7name Find this file - * i 8name Find files #including this file - */ - -typedef struct { - char * name; - int (*func)__ARGS((exarg_T *eap)); - char * help; - char * usage; - int cansplit; /* if supports splitting window */ -} cscmd_T; - -typedef struct csi { - char * fname; /* cscope db name */ - char * ppath; /* path to prepend (the -P option) */ - char * flags; /* additional cscope flags/options (e.g, -p2) */ -#if defined(UNIX) - pid_t pid; /* PID of the connected cscope process. */ - dev_t st_dev; /* ID of dev containing cscope db */ - ino_t st_ino; /* inode number of cscope db */ -#else -#endif - - FILE * fr_fp; /* from cscope: FILE. */ - FILE * to_fp; /* to cscope: FILE. */ -} csinfo_T; - -typedef enum { Add, Find, Help, Kill, Reset, Show } csid_e; - -typedef enum { - Store, - Get, - Free, - Print -} mcmd_e; - - - -/* the end */ +#ifndef NEOVIM_IF_CSCOPE_H +#define NEOVIM_IF_CSCOPE_H +/* if_cscope.c */ +char_u *get_cscope_name __ARGS((expand_T *xp, int idx)); +void set_context_in_cscope_cmd __ARGS((expand_T *xp, char_u *arg, + cmdidx_T cmdidx)); +void do_cscope __ARGS((exarg_T *eap)); +void do_scscope __ARGS((exarg_T *eap)); +void do_cstag __ARGS((exarg_T *eap)); +int cs_fgets __ARGS((char_u *buf, int size)); +void cs_free_tags __ARGS((void)); +void cs_print_tags __ARGS((void)); +int cs_connection __ARGS((int num, char_u *dbpath, char_u *ppath)); +void cs_end __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_IF_CSCOPE_H */ diff --git a/src/if_cscope_defs.h b/src/if_cscope_defs.h new file mode 100644 index 0000000000..3ed89715fc --- /dev/null +++ b/src/if_cscope_defs.h @@ -0,0 +1,72 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * CSCOPE support for Vim added by Andy Kahn + * Ported to Win32 by Sergey Khorev + * + * The basic idea/structure of cscope for Vim was borrowed from Nvi. + * There might be a few lines of code that look similar to what Nvi + * has. If this is a problem and requires inclusion of the annoying + * BSD license, then sue me; I'm not worth much anyway. + */ + + +#if defined(UNIX) +# include /* pid_t */ +# include /* dev_t, ino_t */ +#else +#endif + +#define CSCOPE_SUCCESS 0 +#define CSCOPE_FAILURE -1 + +#define CSCOPE_DBFILE "cscope.out" +#define CSCOPE_PROMPT ">> " + +/* + * s 0name Find this C symbol + * g 1name Find this definition + * d 2name Find functions called by this function + * c 3name Find functions calling this function + * t 4string find text string (cscope 12.9) + * t 4name Find assignments to (cscope 13.3) + * 5pattern change pattern -- NOT USED + * e 6pattern Find this egrep pattern + * f 7name Find this file + * i 8name Find files #including this file + */ + +typedef struct { + char * name; + int (*func)__ARGS((exarg_T *eap)); + char * help; + char * usage; + int cansplit; /* if supports splitting window */ +} cscmd_T; + +typedef struct csi { + char * fname; /* cscope db name */ + char * ppath; /* path to prepend (the -P option) */ + char * flags; /* additional cscope flags/options (e.g, -p2) */ +#if defined(UNIX) + pid_t pid; /* PID of the connected cscope process. */ + dev_t st_dev; /* ID of dev containing cscope db */ + ino_t st_ino; /* inode number of cscope db */ +#else +#endif + + FILE * fr_fp; /* from cscope: FILE. */ + FILE * to_fp; /* to cscope: FILE. */ +} csinfo_T; + +typedef enum { Add, Find, Help, Kill, Reset, Show } csid_e; + +typedef enum { + Store, + Get, + Free, + Print +} mcmd_e; + + + +/* the end */ diff --git a/src/keymap.h b/src/keymap.h index 766413c30c..140eee5322 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -14,7 +14,7 @@ /* * For MSDOS some keys produce codes larger than 0xff. They are split into two - * chars, the first one is K_NUL (same value used in term.h). + * chars, the first one is K_NUL (same value used in term_defs.h). */ #define K_NUL (0xce) /* for MSDOS: special key follows */ diff --git a/src/main.c b/src/main.c index f6093a5b38..418c579209 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,38 @@ #define EXTERN #include "vim.h" +#include "main.h" +#include "blowfish.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "if_cscope.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "ops.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "screen.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" +#include "version.h" +#include "window.h" /* Maximum number of commands from + or -c arguments. */ #define MAX_ARG_CMDS 10 diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000000..1e407ae154 --- /dev/null +++ b/src/main.h @@ -0,0 +1,30 @@ +#ifndef NEOVIM_MAIN_H +#define NEOVIM_MAIN_H +/* main.c */ +void main_loop __ARGS((int cmdwin, int noexmode)); +void getout_preserve_modified __ARGS((int exitval)); +void getout __ARGS((int exitval)); +int process_env __ARGS((char_u *env, int is_viminit)); +void mainerr_arg_missing __ARGS((char_u *str)); +void time_push __ARGS((void *tv_rel, void *tv_start)); +void time_pop __ARGS((void *tp)); +void time_msg __ARGS((char *mesg, void *tv_start)); +void server_to_input_buf __ARGS((char_u *str)); +char_u *eval_client_expr_to_string __ARGS((char_u *expr)); +char_u *serverConvert __ARGS((char_u *client_enc, char_u *data, char_u **tofree)); +int toF_TyA __ARGS((int c)); +int fkmap __ARGS((int c)); +void conv_to_pvim __ARGS((void)); +void conv_to_pstd __ARGS((void)); +char_u *lrswap __ARGS((char_u *ibuf)); +char_u *lrFswap __ARGS((char_u *cmdbuf, int len)); +char_u *lrF_sub __ARGS((char_u *ibuf)); +int cmdl_fkmap __ARGS((int c)); +int F_isalpha __ARGS((int c)); +int F_isdigit __ARGS((int c)); +int F_ischar __ARGS((int c)); +void farsi_fkey __ARGS((cmdarg_T *cap)); +int arabic_shape __ARGS((int c, int *ccp, int *c1p, int prev_c, int prev_c1, + int next_c)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MAIN_H */ diff --git a/src/mark.c b/src/mark.c index 52f51b7679..db274cda50 100644 --- a/src/mark.c +++ b/src/mark.c @@ -12,6 +12,24 @@ */ #include "vim.h" +#include "mark.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "eval.h" +#include "ex_cmds.h" +#include "fileio.h" +#include "fold.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "quickfix.h" +#include "search.h" +#include "term.h" +#include "ui.h" #include "os/os.h" /* diff --git a/src/mark.h b/src/mark.h new file mode 100644 index 0000000000..f78a41bbc4 --- /dev/null +++ b/src/mark.h @@ -0,0 +1,37 @@ +#ifndef NEOVIM_MARK_H +#define NEOVIM_MARK_H +/* mark.c */ +int setmark __ARGS((int c)); +int setmark_pos __ARGS((int c, pos_T *pos, int fnum)); +void setpcmark __ARGS((void)); +void checkpcmark __ARGS((void)); +pos_T *movemark __ARGS((int count)); +pos_T *movechangelist __ARGS((int count)); +pos_T *getmark_buf __ARGS((buf_T *buf, int c, int changefile)); +pos_T *getmark __ARGS((int c, int changefile)); +pos_T *getmark_buf_fnum __ARGS((buf_T *buf, int c, int changefile, int *fnum)); +pos_T *getnextmark __ARGS((pos_T *startpos, int dir, int begin_line)); +void fmarks_check_names __ARGS((buf_T *buf)); +int check_mark __ARGS((pos_T *pos)); +void clrallmarks __ARGS((buf_T *buf)); +char_u *fm_getname __ARGS((fmark_T *fmark, int lead_len)); +void do_marks __ARGS((exarg_T *eap)); +void ex_delmarks __ARGS((exarg_T *eap)); +void ex_jumps __ARGS((exarg_T *eap)); +void ex_changes __ARGS((exarg_T *eap)); +void mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, + long amount_after)); +void mark_col_adjust __ARGS((linenr_T lnum, colnr_T mincol, long lnum_amount, + long col_amount)); +void copy_jumplist __ARGS((win_T *from, win_T *to)); +void free_jumplist __ARGS((win_T *wp)); +void set_last_cursor __ARGS((win_T *win)); +void free_all_marks __ARGS((void)); +int read_viminfo_filemark __ARGS((vir_T *virp, int force)); +void write_viminfo_filemarks __ARGS((FILE *fp)); +int removable __ARGS((char_u *name)); +int write_viminfo_marks __ARGS((FILE *fp_out)); +void copy_viminfo_marks __ARGS((vir_T *virp, FILE *fp_out, int count, int eof, + int flags)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MARK_H */ diff --git a/src/mbyte.c b/src/mbyte.c index dfbaf29f1b..8a1fbef901 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -78,6 +78,17 @@ */ #include "vim.h" +#include "mbyte.h" +#include "charset.h" +#include "fileio.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "screen.h" +#include "spell.h" +#include "ui.h" # define WINBYTE BYTE diff --git a/src/mbyte.h b/src/mbyte.h new file mode 100644 index 0000000000..b9b5aa05d7 --- /dev/null +++ b/src/mbyte.h @@ -0,0 +1,103 @@ +#ifndef NEOVIM_MBYTE_H +#define NEOVIM_MBYTE_H +/* mbyte.c */ +int enc_canon_props __ARGS((char_u *name)); +char_u *mb_init __ARGS((void)); +int bomb_size __ARGS((void)); +void remove_bom __ARGS((char_u *s)); +int mb_get_class __ARGS((char_u *p)); +int mb_get_class_buf __ARGS((char_u *p, buf_T *buf)); +int dbcs_class __ARGS((unsigned lead, unsigned trail)); +int latin_char2len __ARGS((int c)); +int latin_char2bytes __ARGS((int c, char_u *buf)); +int latin_ptr2len __ARGS((char_u *p)); +int latin_ptr2len_len __ARGS((char_u *p, int size)); +int utf_char2cells __ARGS((int c)); +int latin_ptr2cells __ARGS((char_u *p)); +int utf_ptr2cells __ARGS((char_u *p)); +int dbcs_ptr2cells __ARGS((char_u *p)); +int latin_ptr2cells_len __ARGS((char_u *p, int size)); +int latin_char2cells __ARGS((int c)); +int mb_string2cells __ARGS((char_u *p, int len)); +int latin_off2cells __ARGS((unsigned off, unsigned max_off)); +int dbcs_off2cells __ARGS((unsigned off, unsigned max_off)); +int utf_off2cells __ARGS((unsigned off, unsigned max_off)); +int latin_ptr2char __ARGS((char_u *p)); +int utf_ptr2char __ARGS((char_u *p)); +int mb_ptr2char_adv __ARGS((char_u **pp)); +int mb_cptr2char_adv __ARGS((char_u **pp)); +int arabic_combine __ARGS((int one, int two)); +int arabic_maycombine __ARGS((int two)); +int utf_composinglike __ARGS((char_u *p1, char_u *p2)); +int utfc_ptr2char __ARGS((char_u *p, int *pcc)); +int utfc_ptr2char_len __ARGS((char_u *p, int *pcc, int maxlen)); +int utfc_char2bytes __ARGS((int off, char_u *buf)); +int utf_ptr2len __ARGS((char_u *p)); +int utf_byte2len __ARGS((int b)); +int utf_ptr2len_len __ARGS((char_u *p, int size)); +int utfc_ptr2len __ARGS((char_u *p)); +int utfc_ptr2len_len __ARGS((char_u *p, int size)); +int utf_char2len __ARGS((int c)); +int utf_char2bytes __ARGS((int c, char_u *buf)); +int utf_iscomposing __ARGS((int c)); +int utf_printable __ARGS((int c)); +int utf_class __ARGS((int c)); +int utf_fold __ARGS((int a)); +int utf_toupper __ARGS((int a)); +int utf_islower __ARGS((int a)); +int utf_tolower __ARGS((int a)); +int utf_isupper __ARGS((int a)); +int mb_strnicmp __ARGS((char_u *s1, char_u *s2, size_t nn)); +void show_utf8 __ARGS((void)); +int latin_head_off __ARGS((char_u *base, char_u *p)); +int dbcs_head_off __ARGS((char_u *base, char_u *p)); +int dbcs_screen_head_off __ARGS((char_u *base, char_u *p)); +int utf_head_off __ARGS((char_u *base, char_u *p)); +void mb_copy_char __ARGS((char_u **fp, char_u **tp)); +int mb_off_next __ARGS((char_u *base, char_u *p)); +int mb_tail_off __ARGS((char_u *base, char_u *p)); +void utf_find_illegal __ARGS((void)); +int utf_valid_string __ARGS((char_u *s, char_u *end)); +int dbcs_screen_tail_off __ARGS((char_u *base, char_u *p)); +void mb_adjust_cursor __ARGS((void)); +void mb_adjustpos __ARGS((buf_T *buf, pos_T *lp)); +char_u *mb_prevptr __ARGS((char_u *line, char_u *p)); +int mb_charlen __ARGS((char_u *str)); +int mb_charlen_len __ARGS((char_u *str, int len)); +char_u *mb_unescape __ARGS((char_u **pp)); +int mb_lefthalve __ARGS((int row, int col)); +int mb_fix_col __ARGS((int col, int row)); +char_u *enc_skip __ARGS((char_u *p)); +char_u *enc_canonize __ARGS((char_u *enc)); +char_u *enc_locale __ARGS((void)); +int encname2codepage __ARGS((char_u *name)); +void *my_iconv_open __ARGS((char_u *to, char_u *from)); +int iconv_enabled __ARGS((int verbose)); +void iconv_end __ARGS((void)); +void im_set_active __ARGS((int active)); +void xim_set_focus __ARGS((int focus)); +void im_set_position __ARGS((int row, int col)); +void xim_set_preedit __ARGS((void)); +int im_get_feedback_attr __ARGS((int col)); +void xim_init __ARGS((void)); +void im_shutdown __ARGS((void)); +int im_xim_isvalid_imactivate __ARGS((void)); +void xim_reset __ARGS((void)); +int xim_queue_key_press_event __ARGS((GdkEventKey *event, int down)); +int im_get_status __ARGS((void)); +int preedit_get_status __ARGS((void)); +int im_is_preediting __ARGS((void)); +void xim_set_status_area __ARGS((void)); +int xim_get_status_area_height __ARGS((void)); +int convert_setup __ARGS((vimconv_T *vcp, char_u *from, char_u *to)); +int convert_setup_ext __ARGS((vimconv_T *vcp, char_u *from, + int from_unicode_is_utf8, char_u *to, + int to_unicode_is_utf8)); +int convert_input __ARGS((char_u *ptr, int len, int maxlen)); +int convert_input_safe __ARGS((char_u *ptr, int len, int maxlen, char_u **restp, + int *restlenp)); +char_u *string_convert __ARGS((vimconv_T *vcp, char_u *ptr, int *lenp)); +char_u *string_convert_ext __ARGS((vimconv_T *vcp, char_u *ptr, int *lenp, + int *unconvlenp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MBYTE_H */ diff --git a/src/memfile.c b/src/memfile.c index f4a49b1cef..d3b8bed6cc 100644 --- a/src/memfile.c +++ b/src/memfile.c @@ -33,6 +33,14 @@ */ #include "vim.h" +#include "memfile.h" +#include "fileio.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "os_unix.h" +#include "ui.h" /* * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize diff --git a/src/memfile.h b/src/memfile.h new file mode 100644 index 0000000000..0ea6b9fd17 --- /dev/null +++ b/src/memfile.h @@ -0,0 +1,21 @@ +#ifndef NEOVIM_MEMFILE_H +#define NEOVIM_MEMFILE_H +/* memfile.c */ +memfile_T *mf_open __ARGS((char_u *fname, int flags)); +int mf_open_file __ARGS((memfile_T *mfp, char_u *fname)); +void mf_close __ARGS((memfile_T *mfp, int del_file)); +void mf_close_file __ARGS((buf_T *buf, int getlines)); +void mf_new_page_size __ARGS((memfile_T *mfp, unsigned new_size)); +bhdr_T *mf_new __ARGS((memfile_T *mfp, int negative, int page_count)); +bhdr_T *mf_get __ARGS((memfile_T *mfp, blocknr_T nr, int page_count)); +void mf_put __ARGS((memfile_T *mfp, bhdr_T *hp, int dirty, int infile)); +void mf_free __ARGS((memfile_T *mfp, bhdr_T *hp)); +int mf_sync __ARGS((memfile_T *mfp, int flags)); +void mf_set_dirty __ARGS((memfile_T *mfp)); +int mf_release_all __ARGS((void)); +blocknr_T mf_trans_del __ARGS((memfile_T *mfp, blocknr_T old_nr)); +void mf_set_ffname __ARGS((memfile_T *mfp)); +void mf_fullname __ARGS((memfile_T *mfp)); +int mf_need_trans __ARGS((memfile_T *mfp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MEMFILE_H */ diff --git a/src/memline.c b/src/memline.c index 09818a5115..292d09a37a 100644 --- a/src/memline.c +++ b/src/memline.c @@ -43,9 +43,30 @@ */ #include "vim.h" +#include "memline.h" +#include "blowfish.h" +#include "buffer.h" +#include "eval.h" +#include "fileio.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memfile.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "os_unix.h" +#include "screen.h" +#include "sha256.h" +#include "spell.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" #include "os/os.h" -#ifndef UNIX /* it's in os_unix.h for Unix */ +#ifndef UNIX /* it's in os_unix_defs.h for Unix */ # include #endif diff --git a/src/memline.h b/src/memline.h new file mode 100644 index 0000000000..7a18633d25 --- /dev/null +++ b/src/memline.h @@ -0,0 +1,44 @@ +#ifndef NEOVIM_MEMLINE_H +#define NEOVIM_MEMLINE_H +/* memline.c */ +int ml_open __ARGS((buf_T *buf)); +void ml_set_crypt_key __ARGS((buf_T *buf, char_u *old_key, int old_cm)); +void ml_setname __ARGS((buf_T *buf)); +void ml_open_files __ARGS((void)); +void ml_open_file __ARGS((buf_T *buf)); +void check_need_swap __ARGS((int newfile)); +void ml_close __ARGS((buf_T *buf, int del_file)); +void ml_close_all __ARGS((int del_file)); +void ml_close_notmod __ARGS((void)); +void ml_timestamp __ARGS((buf_T *buf)); +void ml_recover __ARGS((void)); +int recover_names __ARGS((char_u *fname, int list, int nr, char_u **fname_out)); +void ml_sync_all __ARGS((int check_file, int check_char)); +void ml_preserve __ARGS((buf_T *buf, int message)); +char_u *ml_get __ARGS((linenr_T lnum)); +char_u *ml_get_pos __ARGS((pos_T *pos)); +char_u *ml_get_curline __ARGS((void)); +char_u *ml_get_cursor __ARGS((void)); +char_u *ml_get_buf __ARGS((buf_T *buf, linenr_T lnum, int will_change)); +int ml_line_alloced __ARGS((void)); +int ml_append __ARGS((linenr_T lnum, char_u *line, colnr_T len, int newfile)); +int ml_append_buf __ARGS((buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, + int newfile)); +int ml_replace __ARGS((linenr_T lnum, char_u *line, int copy)); +int ml_delete __ARGS((linenr_T lnum, int message)); +void ml_setmarked __ARGS((linenr_T lnum)); +linenr_T ml_firstmarked __ARGS((void)); +void ml_clearmarked __ARGS((void)); +int resolve_symlink __ARGS((char_u *fname, char_u *buf)); +char_u *makeswapname __ARGS((char_u *fname, char_u *ffname, buf_T *buf, + char_u *dir_name)); +char_u *get_file_in_dir __ARGS((char_u *fname, char_u *dname)); +void ml_setflags __ARGS((buf_T *buf)); +char_u *ml_encrypt_data __ARGS((memfile_T *mfp, char_u *data, off_t offset, + unsigned size)); +void ml_decrypt_data __ARGS((memfile_T *mfp, char_u *data, off_t offset, + unsigned size)); +long ml_find_line_or_offset __ARGS((buf_T *buf, linenr_T lnum, long *offp)); +void goto_byte __ARGS((long cnt)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MEMLINE_H */ diff --git a/src/menu.c b/src/menu.c index bb62296a61..95ac7bd5f5 100644 --- a/src/menu.c +++ b/src/menu.c @@ -13,6 +13,15 @@ */ #include "vim.h" +#include "menu.h" +#include "charset.h" +#include "eval.h" +#include "ex_docmd.h" +#include "getchar.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "term.h" #define MENUDEPTH 10 /* maximum depth of menus */ diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000000..0d76b523bd --- /dev/null +++ b/src/menu.h @@ -0,0 +1,26 @@ +#ifndef NEOVIM_MENU_H +#define NEOVIM_MENU_H +/* menu.c */ +void ex_menu __ARGS((exarg_T *eap)); +char_u *set_context_in_menu_cmd __ARGS((expand_T *xp, char_u *cmd, char_u *arg, + int forceit)); +char_u *get_menu_name __ARGS((expand_T *xp, int idx)); +char_u *get_menu_names __ARGS((expand_T *xp, int idx)); +char_u *menu_name_skip __ARGS((char_u *name)); +int get_menu_index __ARGS((vimmenu_T *menu, int state)); +int menu_is_menubar __ARGS((char_u *name)); +int menu_is_popup __ARGS((char_u *name)); +int menu_is_child_of_popup __ARGS((vimmenu_T *menu)); +int menu_is_toolbar __ARGS((char_u *name)); +int menu_is_separator __ARGS((char_u *name)); +int check_menu_pointer __ARGS((vimmenu_T *root, vimmenu_T *menu_to_check)); +void gui_create_initial_menus __ARGS((vimmenu_T *menu)); +void gui_update_menus __ARGS((int modes)); +int gui_is_menu_shortcut __ARGS((int key)); +void gui_show_popupmenu __ARGS((void)); +void gui_mch_toggle_tearoffs __ARGS((int enable)); +void ex_emenu __ARGS((exarg_T *eap)); +vimmenu_T *gui_find_menu __ARGS((char_u *path_name)); +void ex_menutranslate __ARGS((exarg_T *eap)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MENU_H */ diff --git a/src/message.c b/src/message.c index 062a196636..99d52380a4 100644 --- a/src/message.c +++ b/src/message.c @@ -14,6 +14,20 @@ #define MESSAGE_FILE /* don't include prototype for smsg() */ #include "vim.h" +#include "message.h" +#include "charset.h" +#include "eval.h" +#include "ex_eval.h" +#include "fileio.h" +#include "getchar.h" +#include "mbyte.h" +#include "misc1.h" +#include "misc2.h" +#include "ops.h" +#include "option.h" +#include "screen.h" +#include "term.h" +#include "ui.h" #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) # include diff --git a/src/message.h b/src/message.h new file mode 100644 index 0000000000..bd1ef4242c --- /dev/null +++ b/src/message.h @@ -0,0 +1,83 @@ +#ifndef NEOVIM_MESSAGE_H +#define NEOVIM_MESSAGE_H +/* message.c */ +int msg __ARGS((char_u *s)); +int verb_msg __ARGS((char_u *s)); +int msg_attr __ARGS((char_u *s, int attr)); +int msg_attr_keep __ARGS((char_u *s, int attr, int keep)); +char_u *msg_strtrunc __ARGS((char_u *s, int force)); +void trunc_string __ARGS((char_u *s, char_u *buf, int room, int buflen)); +void reset_last_sourcing __ARGS((void)); +void msg_source __ARGS((int attr)); +int emsg_not_now __ARGS((void)); +int emsg __ARGS((char_u *s)); +int emsg2 __ARGS((char_u *s, char_u *a1)); +void emsg_invreg __ARGS((int name)); +char_u *msg_trunc_attr __ARGS((char_u *s, int force, int attr)); +char_u *msg_may_trunc __ARGS((int force, char_u *s)); +int delete_first_msg __ARGS((void)); +void ex_messages __ARGS((exarg_T *eap)); +void msg_end_prompt __ARGS((void)); +void wait_return __ARGS((int redraw)); +void set_keep_msg __ARGS((char_u *s, int attr)); +void set_keep_msg_from_hist __ARGS((void)); +void msg_start __ARGS((void)); +void msg_starthere __ARGS((void)); +void msg_putchar __ARGS((int c)); +void msg_putchar_attr __ARGS((int c, int attr)); +void msg_outnum __ARGS((long n)); +void msg_home_replace __ARGS((char_u *fname)); +void msg_home_replace_hl __ARGS((char_u *fname)); +int msg_outtrans __ARGS((char_u *str)); +int msg_outtrans_attr __ARGS((char_u *str, int attr)); +int msg_outtrans_len __ARGS((char_u *str, int len)); +char_u *msg_outtrans_one __ARGS((char_u *p, int attr)); +int msg_outtrans_len_attr __ARGS((char_u *msgstr, int len, int attr)); +void msg_make __ARGS((char_u *arg)); +int msg_outtrans_special __ARGS((char_u *strstart, int from)); +char_u *str2special_save __ARGS((char_u *str, int is_lhs)); +char_u *str2special __ARGS((char_u **sp, int from)); +void str2specialbuf __ARGS((char_u *sp, char_u *buf, int len)); +void msg_prt_line __ARGS((char_u *s, int list)); +void msg_puts __ARGS((char_u *s)); +void msg_puts_title __ARGS((char_u *s)); +void msg_puts_long_attr __ARGS((char_u *longstr, int attr)); +void msg_puts_long_len_attr __ARGS((char_u *longstr, int len, int attr)); +void msg_puts_attr __ARGS((char_u *s, int attr)); +void may_clear_sb_text __ARGS((void)); +void clear_sb_text __ARGS((void)); +void show_sb_text __ARGS((void)); +void msg_sb_eol __ARGS((void)); +int msg_use_printf __ARGS((void)); +void mch_errmsg __ARGS((char *str)); +void mch_msg __ARGS((char *str)); +void msg_moremsg __ARGS((int full)); +void repeat_message __ARGS((void)); +void msg_clr_eos __ARGS((void)); +void msg_clr_eos_force __ARGS((void)); +void msg_clr_cmdline __ARGS((void)); +int msg_end __ARGS((void)); +void msg_check __ARGS((void)); +int redirecting __ARGS((void)); +void verbose_enter __ARGS((void)); +void verbose_leave __ARGS((void)); +void verbose_enter_scroll __ARGS((void)); +void verbose_leave_scroll __ARGS((void)); +void verbose_stop __ARGS((void)); +int verbose_open __ARGS((void)); +void give_warning __ARGS((char_u *message, int hl)); +void msg_advance __ARGS((int col)); +int do_dialog __ARGS((int type, char_u *title, char_u *message, char_u *buttons, + int dfltbutton, char_u *textfield, + int ex_cmd)); +void display_confirm_msg __ARGS((void)); +int vim_dialog_yesno __ARGS((int type, char_u *title, char_u *message, int dflt)); +int vim_dialog_yesnocancel __ARGS((int type, char_u *title, char_u *message, + int dflt)); +int vim_dialog_yesnoallcancel __ARGS((int type, char_u *title, char_u *message, + int dflt)); +char_u *do_browse __ARGS((int flags, char_u *title, char_u *dflt, char_u *ext, + char_u *initdir, char_u *filter, + buf_T *buf)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MESSAGE_H */ diff --git a/src/misc1.c b/src/misc1.c index 98ed65a08b..2d59948e60 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -12,7 +12,36 @@ */ #include "vim.h" -#include "version.h" +#include "version_defs.h" +#include "misc1.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" #include "os/os.h" static char_u *vim_version_dir __ARGS((char_u *vimdir)); diff --git a/src/misc1.h b/src/misc1.h new file mode 100644 index 0000000000..ea7cb1b7e7 --- /dev/null +++ b/src/misc1.h @@ -0,0 +1,120 @@ +#ifndef NEOVIM_MISC1_H +#define NEOVIM_MISC1_H +/* misc1.c */ +int get_indent __ARGS((void)); +int get_indent_lnum __ARGS((linenr_T lnum)); +int get_indent_buf __ARGS((buf_T *buf, linenr_T lnum)); +int get_indent_str __ARGS((char_u *ptr, int ts)); +int set_indent __ARGS((int size, int flags)); +int get_number_indent __ARGS((linenr_T lnum)); +int open_line __ARGS((int dir, int flags, int second_line_indent)); +int get_leader_len __ARGS((char_u *line, char_u **flags, int backward, + int include_space)); +int get_last_leader_offset __ARGS((char_u *line, char_u **flags)); +int plines __ARGS((linenr_T lnum)); +int plines_win __ARGS((win_T *wp, linenr_T lnum, int winheight)); +int plines_nofill __ARGS((linenr_T lnum)); +int plines_win_nofill __ARGS((win_T *wp, linenr_T lnum, int winheight)); +int plines_win_nofold __ARGS((win_T *wp, linenr_T lnum)); +int plines_win_col __ARGS((win_T *wp, linenr_T lnum, long column)); +int plines_m_win __ARGS((win_T *wp, linenr_T first, linenr_T last)); +void ins_bytes __ARGS((char_u *p)); +void ins_bytes_len __ARGS((char_u *p, int len)); +void ins_char __ARGS((int c)); +void ins_char_bytes __ARGS((char_u *buf, int charlen)); +void ins_str __ARGS((char_u *s)); +int del_char __ARGS((int fixpos)); +int del_chars __ARGS((long count, int fixpos)); +int del_bytes __ARGS((long count, int fixpos_arg, int use_delcombine)); +int truncate_line __ARGS((int fixpos)); +void del_lines __ARGS((long nlines, int undo)); +int gchar_pos __ARGS((pos_T *pos)); +int gchar_cursor __ARGS((void)); +void pchar_cursor __ARGS((int c)); +int inindent __ARGS((int extra)); +char_u *skip_to_option_part __ARGS((char_u *p)); +void changed __ARGS((void)); +void changed_int __ARGS((void)); +void changed_bytes __ARGS((linenr_T lnum, colnr_T col)); +void appended_lines __ARGS((linenr_T lnum, long count)); +void appended_lines_mark __ARGS((linenr_T lnum, long count)); +void deleted_lines __ARGS((linenr_T lnum, long count)); +void deleted_lines_mark __ARGS((linenr_T lnum, long count)); +void changed_lines __ARGS((linenr_T lnum, colnr_T col, linenr_T lnume, + long xtra)); +void unchanged __ARGS((buf_T *buf, int ff)); +void check_status __ARGS((buf_T *buf)); +void change_warning __ARGS((int col)); +int ask_yesno __ARGS((char_u *str, int direct)); +int is_mouse_key __ARGS((int c)); +int get_keystroke __ARGS((void)); +int get_number __ARGS((int colon, int *mouse_used)); +int prompt_for_number __ARGS((int *mouse_used)); +void msgmore __ARGS((long n)); +void beep_flush __ARGS((void)); +void vim_beep __ARGS((void)); +void init_homedir __ARGS((void)); +void free_homedir __ARGS((void)); +void free_users __ARGS((void)); +char_u *expand_env_save __ARGS((char_u *src)); +char_u *expand_env_save_opt __ARGS((char_u *src, int one)); +void expand_env __ARGS((char_u *src, char_u *dst, int dstlen)); +void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, + int one, + char_u *startstr)); +char_u *vim_getenv __ARGS((char_u *name, int *mustfree)); +void vim_setenv __ARGS((char_u *name, char_u *val)); +char_u *get_env_name __ARGS((expand_T *xp, int idx)); +char_u *get_users __ARGS((expand_T *xp, int idx)); +int match_user __ARGS((char_u *name)); +void home_replace __ARGS((buf_T *buf, char_u *src, char_u *dst, int dstlen, + int one)); +char_u *home_replace_save __ARGS((buf_T *buf, char_u *src)); +int fullpathcmp __ARGS((char_u *s1, char_u *s2, int checkname)); +char_u *gettail __ARGS((char_u *fname)); +char_u *gettail_sep __ARGS((char_u *fname)); +char_u *getnextcomp __ARGS((char_u *fname)); +char_u *get_past_head __ARGS((char_u *path)); +int vim_ispathsep __ARGS((int c)); +int vim_ispathsep_nocolon __ARGS((int c)); +int vim_ispathlistsep __ARGS((int c)); +void shorten_dir __ARGS((char_u *str)); +int dir_of_file_exists __ARGS((char_u *fname)); +int vim_fnamecmp __ARGS((char_u *x, char_u *y)); +int vim_fnamencmp __ARGS((char_u *x, char_u *y, size_t len)); +char_u *concat_fnames __ARGS((char_u *fname1, char_u *fname2, int sep)); +char_u *concat_str __ARGS((char_u *str1, char_u *str2)); +void add_pathsep __ARGS((char_u *p)); +char_u *FullName_save __ARGS((char_u *fname, int force)); +pos_T *find_start_comment __ARGS((int ind_maxcomment)); +void do_c_expr_indent __ARGS((void)); +int cin_islabel __ARGS((void)); +int cin_iscase __ARGS((char_u *s, int strict)); +int cin_isscopedecl __ARGS((char_u *s)); +void parse_cino __ARGS((buf_T *buf)); +int get_c_indent __ARGS((void)); +int get_expr_indent __ARGS((void)); +int get_lisp_indent __ARGS((void)); +void prepare_to_exit __ARGS((void)); +void preserve_exit __ARGS((void)); +int vim_fexists __ARGS((char_u *fname)); +void line_breakcheck __ARGS((void)); +void fast_breakcheck __ARGS((void)); +int expand_wildcards_eval __ARGS((char_u **pat, int *num_file, char_u ***file, + int flags)); +int expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u * + **file, + int flags)); +int match_suffix __ARGS((char_u *fname)); +int unix_expandpath __ARGS((garray_T *gap, char_u *path, int wildoff, int flags, + int didstar)); +void remove_duplicates __ARGS((garray_T *gap)); +int gen_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, + char_u ***file, + int flags)); +void addfile __ARGS((garray_T *gap, char_u *f, int flags)); +char_u *get_cmd_output __ARGS((char_u *cmd, char_u *infile, int flags)); +void FreeWild __ARGS((int count, char_u **files)); +int goto_im __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MISC1_H */ diff --git a/src/misc2.c b/src/misc2.c index da90eedb55..544a45a315 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -11,6 +11,28 @@ * misc2.c: Various functions. */ #include "vim.h" +#include "misc2.h" +#include "blowfish.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "mbyte.h" +#include "memfile.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "move.h" +#include "option.h" +#include "os_unix.h" +#include "screen.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "window.h" #include "os/os.h" static char_u *username = NULL; /* cached result of mch_get_user_name() */ diff --git a/src/misc2.h b/src/misc2.h new file mode 100644 index 0000000000..7beb681661 --- /dev/null +++ b/src/misc2.h @@ -0,0 +1,136 @@ +#ifndef NEOVIM_MISC2_H +#define NEOVIM_MISC2_H +/* misc2.c */ +int virtual_active __ARGS((void)); +int getviscol __ARGS((void)); +int getviscol2 __ARGS((colnr_T col, colnr_T coladd)); +int coladvance_force __ARGS((colnr_T wcol)); +int coladvance __ARGS((colnr_T wcol)); +int getvpos __ARGS((pos_T *pos, colnr_T wcol)); +int inc_cursor __ARGS((void)); +int inc __ARGS((pos_T *lp)); +int incl __ARGS((pos_T *lp)); +int dec_cursor __ARGS((void)); +int dec __ARGS((pos_T *lp)); +int decl __ARGS((pos_T *lp)); +linenr_T get_cursor_rel_lnum __ARGS((win_T *wp, linenr_T lnum)); +void check_cursor_lnum __ARGS((void)); +void check_cursor_col __ARGS((void)); +void check_cursor_col_win __ARGS((win_T *win)); +void check_cursor __ARGS((void)); +void adjust_cursor_col __ARGS((void)); +int leftcol_changed __ARGS((void)); +void vim_mem_profile_dump __ARGS((void)); +char_u *alloc __ARGS((unsigned size)); +char_u *alloc_clear __ARGS((unsigned size)); +char_u *alloc_check __ARGS((unsigned size)); +char_u *lalloc_clear __ARGS((long_u size, int message)); +char_u *lalloc __ARGS((long_u size, int message)); +void *mem_realloc __ARGS((void *ptr, size_t size)); +void do_outofmem_msg __ARGS((long_u size)); +void free_all_mem __ARGS((void)); +char_u *vim_strsave __ARGS((char_u *string)); +char_u *vim_strnsave __ARGS((char_u *string, int len)); +char_u *vim_strsave_escaped __ARGS((char_u *string, char_u *esc_chars)); +char_u *vim_strsave_escaped_ext __ARGS((char_u *string, char_u *esc_chars, + int cc, + int bsl)); +int csh_like_shell __ARGS((void)); +char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special)); +char_u *vim_strsave_up __ARGS((char_u *string)); +char_u *vim_strnsave_up __ARGS((char_u *string, int len)); +void vim_strup __ARGS((char_u *p)); +char_u *strup_save __ARGS((char_u *orig)); +void copy_spaces __ARGS((char_u *ptr, size_t count)); +void copy_chars __ARGS((char_u *ptr, size_t count, int c)); +void del_trailing_spaces __ARGS((char_u *ptr)); +void vim_strncpy __ARGS((char_u *to, char_u *from, size_t len)); +void vim_strcat __ARGS((char_u *to, char_u *from, size_t tosize)); +int copy_option_part __ARGS((char_u **option, char_u *buf, int maxlen, + char *sep_chars)); +void vim_free __ARGS((void *x)); +int vim_stricmp __ARGS((char *s1, char *s2)); +int vim_strnicmp __ARGS((char *s1, char *s2, size_t len)); +char_u *vim_strchr __ARGS((char_u *string, int c)); +char_u *vim_strbyte __ARGS((char_u *string, int c)); +char_u *vim_strrchr __ARGS((char_u *string, int c)); +int vim_isspace __ARGS((int x)); +void ga_clear __ARGS((garray_T *gap)); +void ga_clear_strings __ARGS((garray_T *gap)); +void ga_init __ARGS((garray_T *gap)); +void ga_init2 __ARGS((garray_T *gap, int itemsize, int growsize)); +int ga_grow __ARGS((garray_T *gap, int n)); +char_u *ga_concat_strings __ARGS((garray_T *gap)); +void ga_concat __ARGS((garray_T *gap, char_u *s)); +void ga_append __ARGS((garray_T *gap, int c)); +void append_ga_line __ARGS((garray_T *gap)); +int name_to_mod_mask __ARGS((int c)); +int simplify_key __ARGS((int key, int *modifiers)); +int handle_x_keys __ARGS((int key)); +char_u *get_special_key_name __ARGS((int c, int modifiers)); +int trans_special __ARGS((char_u **srcp, char_u *dst, int keycode)); +int find_special_key __ARGS((char_u **srcp, int *modp, int keycode, + int keep_x_key)); +int extract_modifiers __ARGS((int key, int *modp)); +int find_special_key_in_table __ARGS((int c)); +int get_special_key_code __ARGS((char_u *name)); +char_u *get_key_name __ARGS((int i)); +int get_mouse_button __ARGS((int code, int *is_click, int *is_drag)); +int get_pseudo_mouse_code __ARGS((int button, int is_click, int is_drag)); +int get_fileformat __ARGS((buf_T *buf)); +int get_fileformat_force __ARGS((buf_T *buf, exarg_T *eap)); +void set_fileformat __ARGS((int t, int opt_flags)); +int default_fileformat __ARGS((void)); +int call_shell __ARGS((char_u *cmd, int opt)); +int get_real_state __ARGS((void)); +int after_pathsep __ARGS((char_u *b, char_u *p)); +int same_directory __ARGS((char_u *f1, char_u *f2)); +int vim_chdirfile __ARGS((char_u *fname)); +int illegal_slash __ARGS((char *name)); +char_u *parse_shape_opt __ARGS((int what)); +int get_shape_idx __ARGS((int mouse)); +void update_mouseshape __ARGS((int shape_idx)); +int crypt_method_from_string __ARGS((char_u *s)); +int get_crypt_method __ARGS((buf_T *buf)); +void set_crypt_method __ARGS((buf_T *buf, int method)); +void crypt_push_state __ARGS((void)); +void crypt_pop_state __ARGS((void)); +void crypt_encode __ARGS((char_u *from, size_t len, char_u *to)); +void crypt_decode __ARGS((char_u *ptr, long len)); +void crypt_init_keys __ARGS((char_u *passwd)); +void free_crypt_key __ARGS((char_u *key)); +char_u *get_crypt_key __ARGS((int store, int twice)); +void *vim_findfile_init __ARGS((char_u *path, char_u *filename, char_u * + stopdirs, int level, int free_visited, + int find_what, void *search_ctx_arg, + int tagfile, + char_u *rel_fname)); +char_u *vim_findfile_stopdir __ARGS((char_u *buf)); +void vim_findfile_cleanup __ARGS((void *ctx)); +char_u *vim_findfile __ARGS((void *search_ctx_arg)); +void vim_findfile_free_visited __ARGS((void *search_ctx_arg)); +char_u *find_file_in_path __ARGS((char_u *ptr, int len, int options, int first, + char_u *rel_fname)); +char_u *find_directory_in_path __ARGS((char_u *ptr, int len, int options, + char_u *rel_fname)); +char_u *find_file_in_path_option __ARGS((char_u *ptr, int len, int options, + int first, char_u *path_option, + int find_what, char_u *rel_fname, + char_u *suffixes)); +int vim_chdir __ARGS((char_u *new_dir)); +int get_user_name __ARGS((char_u *buf, int len)); +void sort_strings __ARGS((char_u **files, int count)); +int pathcmp __ARGS((const char *p, const char *q, int maxlen)); +int filewritable __ARGS((char_u *fname)); +int emsg3 __ARGS((char_u *s, char_u *a1, char_u *a2)); +int emsgn __ARGS((char_u *s, long n)); +int get2c __ARGS((FILE *fd)); +int get3c __ARGS((FILE *fd)); +int get4c __ARGS((FILE *fd)); +time_t get8ctime __ARGS((FILE *fd)); +char_u *read_string __ARGS((FILE *fd, int cnt)); +int put_bytes __ARGS((FILE *fd, long_u nr, int len)); +void put_time __ARGS((FILE *fd, time_t the_time)); +int has_non_ascii __ARGS((char_u *s)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MISC2_H */ diff --git a/src/move.c b/src/move.c index 60547e4a94..d83cfc6b13 100644 --- a/src/move.c +++ b/src/move.c @@ -18,6 +18,17 @@ */ #include "vim.h" +#include "move.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "fold.h" +#include "mbyte.h" +#include "memline.h" +#include "misc1.h" +#include "misc2.h" +#include "popupmnu.h" +#include "screen.h" static void comp_botline __ARGS((win_T *wp)); static int scrolljump_value __ARGS((void)); diff --git a/src/move.h b/src/move.h new file mode 100644 index 0000000000..bf3371fa2d --- /dev/null +++ b/src/move.h @@ -0,0 +1,44 @@ +#ifndef NEOVIM_MOVE_H +#define NEOVIM_MOVE_H +/* move.c */ +void update_topline_redraw __ARGS((void)); +void update_topline __ARGS((void)); +void update_curswant __ARGS((void)); +void check_cursor_moved __ARGS((win_T *wp)); +void changed_window_setting __ARGS((void)); +void changed_window_setting_win __ARGS((win_T *wp)); +void set_topline __ARGS((win_T *wp, linenr_T lnum)); +void changed_cline_bef_curs __ARGS((void)); +void changed_cline_bef_curs_win __ARGS((win_T *wp)); +void changed_line_abv_curs __ARGS((void)); +void changed_line_abv_curs_win __ARGS((win_T *wp)); +void validate_botline __ARGS((void)); +void invalidate_botline __ARGS((void)); +void invalidate_botline_win __ARGS((win_T *wp)); +void approximate_botline_win __ARGS((win_T *wp)); +int cursor_valid __ARGS((void)); +void validate_cursor __ARGS((void)); +void validate_cline_row __ARGS((void)); +void validate_virtcol __ARGS((void)); +void validate_virtcol_win __ARGS((win_T *wp)); +void validate_cursor_col __ARGS((void)); +int win_col_off __ARGS((win_T *wp)); +int curwin_col_off __ARGS((void)); +int win_col_off2 __ARGS((win_T *wp)); +int curwin_col_off2 __ARGS((void)); +void curs_columns __ARGS((int may_scroll)); +void scrolldown __ARGS((long line_count, int byfold)); +void scrollup __ARGS((long line_count, int byfold)); +void check_topfill __ARGS((win_T *wp, int down)); +void scrolldown_clamp __ARGS((void)); +void scrollup_clamp __ARGS((void)); +void scroll_cursor_top __ARGS((int min_scroll, int always)); +void set_empty_rows __ARGS((win_T *wp, int used)); +void scroll_cursor_bot __ARGS((int min_scroll, int set_topbot)); +void scroll_cursor_halfway __ARGS((int atend)); +void cursor_correct __ARGS((void)); +int onepage __ARGS((int dir, long count)); +void halfpage __ARGS((int flag, linenr_T Prenum)); +void do_check_cursorbind __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_MOVE_H */ diff --git a/src/normal.c b/src/normal.c index 2a8327a451..75b9319d95 100644 --- a/src/normal.c +++ b/src/normal.c @@ -13,6 +13,39 @@ */ #include "vim.h" +#include "normal.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "digraph.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mark.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "ops.h" +#include "option.h" +#include "quickfix.h" +#include "screen.h" +#include "search.h" +#include "spell.h" +#include "syntax.h" +#include "tag.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" /* * The Visual area is remembered for reselection. diff --git a/src/normal.h b/src/normal.h new file mode 100644 index 0000000000..171c4c928d --- /dev/null +++ b/src/normal.h @@ -0,0 +1,32 @@ +#ifndef NEOVIM_NORMAL_H +#define NEOVIM_NORMAL_H +/* normal.c */ +void init_normal_cmds __ARGS((void)); +void normal_cmd __ARGS((oparg_T *oap, int toplevel)); +void do_pending_operator __ARGS((cmdarg_T *cap, int old_col, int gui_yank)); +int do_mouse __ARGS((oparg_T *oap, int c, int dir, long count, int fixindent)); +void check_visual_highlight __ARGS((void)); +void end_visual_mode __ARGS((void)); +void reset_VIsual_and_resel __ARGS((void)); +void reset_VIsual __ARGS((void)); +int find_ident_under_cursor __ARGS((char_u **string, int find_type)); +int find_ident_at_pos __ARGS((win_T *wp, linenr_T lnum, colnr_T startcol, + char_u **string, + int find_type)); +void clear_showcmd __ARGS((void)); +int add_to_showcmd __ARGS((int c)); +void add_to_showcmd_c __ARGS((int c)); +void push_showcmd __ARGS((void)); +void pop_showcmd __ARGS((void)); +void do_check_scrollbind __ARGS((int check)); +void check_scrollbind __ARGS((linenr_T topline_diff, long leftcol_diff)); +int find_decl __ARGS((char_u *ptr, int len, int locally, int thisblock, + int searchflags)); +void scroll_redraw __ARGS((int up, long count)); +void handle_tabmenu __ARGS((void)); +void do_nv_ident __ARGS((int c1, int c2)); +int get_visual_text __ARGS((cmdarg_T *cap, char_u **pp, int *lenp)); +void start_selection __ARGS((void)); +void may_start_select __ARGS((int c)); +/* vim: set ft=c : */ +#endif /* NEOVIM_NORMAL_H */ diff --git a/src/ops.c b/src/ops.c index 8b2a728acb..5fb256e30d 100644 --- a/src/ops.c +++ b/src/ops.c @@ -13,6 +13,31 @@ */ #include "vim.h" +#include "ops.h" +#include "buffer.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_getln.h" +#include "fold.h" +#include "getchar.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "screen.h" +#include "search.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" /* * Number of registers. diff --git a/src/ops.h b/src/ops.h new file mode 100644 index 0000000000..f9fcbb2656 --- /dev/null +++ b/src/ops.h @@ -0,0 +1,69 @@ +#ifndef NEOVIM_OPS_H +#define NEOVIM_OPS_H +/* ops.c */ +int get_op_type __ARGS((int char1, int char2)); +int op_on_lines __ARGS((int op)); +int get_op_char __ARGS((int optype)); +int get_extra_op_char __ARGS((int optype)); +void op_shift __ARGS((oparg_T *oap, int curs_top, int amount)); +void shift_line __ARGS((int left, int round, int amount, int call_changed_bytes)); +void op_reindent __ARGS((oparg_T *oap, int (*how)(void))); +int get_expr_register __ARGS((void)); +void set_expr_line __ARGS((char_u *new_line)); +char_u *get_expr_line __ARGS((void)); +char_u *get_expr_line_src __ARGS((void)); +int valid_yank_reg __ARGS((int regname, int writing)); +void get_yank_register __ARGS((int regname, int writing)); +int may_get_selection __ARGS((int regname)); +void *get_register __ARGS((int name, int copy)); +void put_register __ARGS((int name, void *reg)); +void free_register __ARGS((void *reg)); +int yank_register_mline __ARGS((int regname)); +int do_record __ARGS((int c)); +int do_execreg __ARGS((int regname, int colon, int addcr, int silent)); +int insert_reg __ARGS((int regname, int literally)); +int get_spec_reg __ARGS((int regname, char_u **argp, int *allocated, int errmsg)); +int cmdline_paste_reg __ARGS((int regname, int literally, int remcr)); +void adjust_clip_reg __ARGS((int *rp)); +int op_delete __ARGS((oparg_T *oap)); +int op_replace __ARGS((oparg_T *oap, int c)); +void op_tilde __ARGS((oparg_T *oap)); +int swapchar __ARGS((int op_type, pos_T *pos)); +void op_insert __ARGS((oparg_T *oap, long count1)); +int op_change __ARGS((oparg_T *oap)); +void init_yank __ARGS((void)); +void clear_registers __ARGS((void)); +int op_yank __ARGS((oparg_T *oap, int deleting, int mess)); +void do_put __ARGS((int regname, int dir, long count, int flags)); +void adjust_cursor_eol __ARGS((void)); +int preprocs_left __ARGS((void)); +int get_register_name __ARGS((int num)); +void ex_display __ARGS((exarg_T *eap)); +int do_join __ARGS((long count, int insert_space, int save_undo, + int use_formatoptions)); +void op_format __ARGS((oparg_T *oap, int keep_cursor)); +void op_formatexpr __ARGS((oparg_T *oap)); +int fex_format __ARGS((linenr_T lnum, long count, int c)); +void format_lines __ARGS((linenr_T line_count, int avoid_fex)); +int paragraph_start __ARGS((linenr_T lnum)); +int do_addsub __ARGS((int command, linenr_T Prenum1)); +int read_viminfo_register __ARGS((vir_T *virp, int force)); +void write_viminfo_registers __ARGS((FILE *fp)); +void x11_export_final_selection __ARGS((void)); +void clip_free_selection __ARGS((VimClipboard *cbd)); +void clip_get_selection __ARGS((VimClipboard *cbd)); +void clip_yank_selection __ARGS((int type, char_u *str, long len, + VimClipboard *cbd)); +int clip_convert_selection __ARGS((char_u **str, long_u *len, VimClipboard *cbd)); +void dnd_yank_drag_data __ARGS((char_u *str, long len)); +char_u get_reg_type __ARGS((int regname, long *reglen)); +char_u *get_reg_contents __ARGS((int regname, int allowexpr, int expr_src)); +void write_reg_contents __ARGS((int name, char_u *str, int maxlen, + int must_append)); +void write_reg_contents_ex __ARGS((int name, char_u *str, int maxlen, + int must_append, int yank_type, + long block_len)); +void clear_oparg __ARGS((oparg_T *oap)); +void cursor_pos_info __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_OPS_H */ diff --git a/src/option.c b/src/option.c index 60bf6a663f..ded6fc1314 100644 --- a/src/option.c +++ b/src/option.c @@ -11,7 +11,7 @@ * Code to handle user-settable options. This is all pretty much table- * driven. Checklist for adding a new option: * - Put it in the options array below (copy an existing entry). - * - For a global option: Add a variable for it in option.h. + * - For a global option: Add a variable for it in option_defs.h. * - For a buffer or window local option: * - Add a PV_XX entry to the enum below. * - Add a variable to the window or buffer struct in structs.h. @@ -33,6 +33,37 @@ #define IN_OPTION_C #include "vim.h" +#include "option.h" +#include "blowfish.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "digraph.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hardcopy.h" +#include "mbyte.h" +#include "memfile.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "os_unix.h" +#include "regexp.h" +#include "screen.h" +#include "spell.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "window.h" /* * The options that are local to a window or buffer have "indir" set to one of @@ -52,7 +83,7 @@ /* * Definition of the PV_ values for buffer-local options. - * The BV_ values are defined in option.h. + * The BV_ values are defined in option_defs.h. */ #define PV_AI OPT_BUF(BV_AI) #define PV_AR OPT_BOTH(OPT_BUF(BV_AR)) @@ -130,7 +161,7 @@ /* * Definition of the PV_ values for window-local options. - * The WV_ values are defined in option.h. + * The WV_ values are defined in option_defs.h. */ #define PV_LIST OPT_WIN(WV_LIST) # define PV_ARAB OPT_WIN(WV_ARAB) diff --git a/src/option.h b/src/option.h index 6cc0cce362..e8332cd2aa 100644 --- a/src/option.h +++ b/src/option.h @@ -1,768 +1,77 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * option.h: definition of global variables for settable options - */ - -/* - * Default values for 'errorformat'. - * The "%f|%l| %m" one is used for when the contents of the quickfix window is - * written to a file. - */ -#define DFLT_EFM \ - "%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%D%*\\a: Entering directory %*[`']%f',%X%*\\a: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m" - -#define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m" - -/* default values for b_p_ff 'fileformat' and p_ffs 'fileformats' */ -#define FF_DOS "dos" -#define FF_MAC "mac" -#define FF_UNIX "unix" - -#ifdef USE_CRNL -# define DFLT_FF "dos" -# define DFLT_FFS_VIM "dos,unix" -# define DFLT_FFS_VI "dos,unix" /* also autodetect in compatible mode */ -# define DFLT_TEXTAUTO TRUE -#else -# ifdef USE_CR -# define DFLT_FF "mac" -# define DFLT_FFS_VIM "mac,unix,dos" -# define DFLT_FFS_VI "mac,unix,dos" -# define DFLT_TEXTAUTO TRUE -# else -# define DFLT_FF "unix" -# define DFLT_FFS_VIM "unix,dos" -# define DFLT_FFS_VI "" -# define DFLT_TEXTAUTO FALSE -# endif -#endif - - -/* Possible values for 'encoding' */ -# define ENC_UCSBOM "ucs-bom" /* check for BOM at start of file */ - -/* default value for 'encoding' */ -# define ENC_DFLT "latin1" - -/* end-of-line style */ -#define EOL_UNKNOWN -1 /* not defined yet */ -#define EOL_UNIX 0 /* NL */ -#define EOL_DOS 1 /* CR NL */ -#define EOL_MAC 2 /* CR */ - -/* Formatting options for p_fo 'formatoptions' */ -#define FO_WRAP 't' -#define FO_WRAP_COMS 'c' -#define FO_RET_COMS 'r' -#define FO_OPEN_COMS 'o' -#define FO_Q_COMS 'q' -#define FO_Q_NUMBER 'n' -#define FO_Q_SECOND '2' -#define FO_INS_VI 'v' -#define FO_INS_LONG 'l' -#define FO_INS_BLANK 'b' -#define FO_MBYTE_BREAK 'm' /* break before/after multi-byte char */ -#define FO_MBYTE_JOIN 'M' /* no space before/after multi-byte char */ -#define FO_MBYTE_JOIN2 'B' /* no space between multi-byte chars */ -#define FO_ONE_LETTER '1' -#define FO_WHITE_PAR 'w' /* trailing white space continues paragr. */ -#define FO_AUTO 'a' /* automatic formatting */ -#define FO_REMOVE_COMS 'j' /* remove comment leaders when joining lines */ - -#define DFLT_FO_VI "vt" -#define DFLT_FO_VIM "tcq" -#define FO_ALL "tcroq2vlb1mMBn,awj" /* for do_set() */ - -/* characters for the p_cpo option: */ -#define CPO_ALTREAD 'a' /* ":read" sets alternate file name */ -#define CPO_ALTWRITE 'A' /* ":write" sets alternate file name */ -#define CPO_BAR 'b' /* "\|" ends a mapping */ -#define CPO_BSLASH 'B' /* backslash in mapping is not special */ -#define CPO_SEARCH 'c' -#define CPO_CONCAT 'C' /* Don't concatenate sourced lines */ -#define CPO_DOTTAG 'd' /* "./tags" in 'tags' is in current dir */ -#define CPO_DIGRAPH 'D' /* No digraph after "r", "f", etc. */ -#define CPO_EXECBUF 'e' -#define CPO_EMPTYREGION 'E' /* operating on empty region is an error */ -#define CPO_FNAMER 'f' /* set file name for ":r file" */ -#define CPO_FNAMEW 'F' /* set file name for ":w file" */ -#define CPO_GOTO1 'g' /* goto line 1 for ":edit" */ -#define CPO_INSEND 'H' /* "I" inserts before last blank in line */ -#define CPO_INTMOD 'i' /* interrupt a read makes buffer modified */ -#define CPO_INDENT 'I' /* remove auto-indent more often */ -#define CPO_JOINSP 'j' /* only use two spaces for join after '.' */ -#define CPO_ENDOFSENT 'J' /* need two spaces to detect end of sentence */ -#define CPO_KEYCODE 'k' /* don't recognize raw key code in mappings */ -#define CPO_KOFFSET 'K' /* don't wait for key code in mappings */ -#define CPO_LITERAL 'l' /* take char after backslash in [] literal */ -#define CPO_LISTWM 'L' /* 'list' changes wrapmargin */ -#define CPO_SHOWMATCH 'm' -#define CPO_MATCHBSL 'M' /* "%" ignores use of backslashes */ -#define CPO_NUMCOL 'n' /* 'number' column also used for text */ -#define CPO_LINEOFF 'o' -#define CPO_OVERNEW 'O' /* silently overwrite new file */ -#define CPO_LISP 'p' /* 'lisp' indenting */ -#define CPO_FNAMEAPP 'P' /* set file name for ":w >>file" */ -#define CPO_JOINCOL 'q' /* with "3J" use column after first join */ -#define CPO_REDO 'r' -#define CPO_REMMARK 'R' /* remove marks when filtering */ -#define CPO_BUFOPT 's' -#define CPO_BUFOPTGLOB 'S' -#define CPO_TAGPAT 't' -#define CPO_UNDO 'u' /* "u" undoes itself */ -#define CPO_BACKSPACE 'v' /* "v" keep deleted text */ -#define CPO_CW 'w' /* "cw" only changes one blank */ -#define CPO_FWRITE 'W' /* "w!" doesn't overwrite readonly files */ -#define CPO_ESC 'x' -#define CPO_REPLCNT 'X' /* "R" with a count only deletes chars once */ -#define CPO_YANK 'y' -#define CPO_KEEPRO 'Z' /* don't reset 'readonly' on ":w!" */ -#define CPO_DOLLAR '$' -#define CPO_FILTER '!' -#define CPO_MATCH '%' -#define CPO_STAR '*' /* ":*" means ":@" */ -#define CPO_PLUS '+' /* ":write file" resets 'modified' */ -#define CPO_MINUS '-' /* "9-" fails at and before line 9 */ -#define CPO_SPECI '<' /* don't recognize <> in mappings */ -#define CPO_REGAPPEND '>' /* insert NL when appending to a register */ -/* POSIX flags */ -#define CPO_HASH '#' /* "D", "o" and "O" do not use a count */ -#define CPO_PARA '{' /* "{" is also a paragraph boundary */ -#define CPO_TSIZE '|' /* $LINES and $COLUMNS overrule term size */ -#define CPO_PRESERVE '&' /* keep swap file after :preserve */ -#define CPO_SUBPERCENT '/' /* % in :s string uses previous one */ -#define CPO_BACKSL '\\' /* \ is not special in [] */ -#define CPO_CHDIR '.' /* don't chdir if buffer is modified */ -#define CPO_SCOLON ';' /* using "," and ";" will skip over char if - * cursor would not move */ -/* default values for Vim, Vi and POSIX */ -#define CPO_VIM "aABceFs" -#define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;" -#define CPO_ALL \ - "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\\.;" - -/* characters for p_ww option: */ -#define WW_ALL "bshl<>[],~" - -/* characters for p_mouse option: */ -#define MOUSE_NORMAL 'n' /* use mouse in Normal mode */ -#define MOUSE_VISUAL 'v' /* use mouse in Visual/Select mode */ -#define MOUSE_INSERT 'i' /* use mouse in Insert mode */ -#define MOUSE_COMMAND 'c' /* use mouse in Command-line mode */ -#define MOUSE_HELP 'h' /* use mouse in help buffers */ -#define MOUSE_RETURN 'r' /* use mouse for hit-return message */ -#define MOUSE_A "nvich" /* used for 'a' flag */ -#define MOUSE_ALL "anvichr" /* all possible characters */ -#define MOUSE_NONE ' ' /* don't use Visual selection */ -#define MOUSE_NONEF 'x' /* forced modeless selection */ - -#define COCU_ALL "nvic" /* flags for 'concealcursor' */ - -/* characters for p_shm option: */ -#define SHM_RO 'r' /* readonly */ -#define SHM_MOD 'm' /* modified */ -#define SHM_FILE 'f' /* (file 1 of 2) */ -#define SHM_LAST 'i' /* last line incomplete */ -#define SHM_TEXT 'x' /* tx instead of textmode */ -#define SHM_LINES 'l' /* "L" instead of "lines" */ -#define SHM_NEW 'n' /* "[New]" instead of "[New file]" */ -#define SHM_WRI 'w' /* "[w]" instead of "written" */ -#define SHM_A "rmfixlnw" /* represented by 'a' flag */ -#define SHM_WRITE 'W' /* don't use "written" at all */ -#define SHM_TRUNC 't' /* trunctate file messages */ -#define SHM_TRUNCALL 'T' /* trunctate all messages */ -#define SHM_OVER 'o' /* overwrite file messages */ -#define SHM_OVERALL 'O' /* overwrite more messages */ -#define SHM_SEARCH 's' /* no search hit bottom messages */ -#define SHM_ATTENTION 'A' /* no ATTENTION messages */ -#define SHM_INTRO 'I' /* intro messages */ -#define SHM_ALL "rmfixlnwaWtToOsAI" /* all possible flags for 'shm' */ - -/* characters for p_go: */ -#define GO_ASEL 'a' /* autoselect */ -#define GO_ASELML 'A' /* autoselect modeless selection */ -#define GO_BOT 'b' /* use bottom scrollbar */ -#define GO_CONDIALOG 'c' /* use console dialog */ -#define GO_TABLINE 'e' /* may show tabline */ -#define GO_FORG 'f' /* start GUI in foreground */ -#define GO_GREY 'g' /* use grey menu items */ -#define GO_HORSCROLL 'h' /* flexible horizontal scrolling */ -#define GO_ICON 'i' /* use Vim icon */ -#define GO_LEFT 'l' /* use left scrollbar */ -#define GO_VLEFT 'L' /* left scrollbar with vert split */ -#define GO_MENUS 'm' /* use menu bar */ -#define GO_NOSYSMENU 'M' /* don't source system menu */ -#define GO_POINTER 'p' /* pointer enter/leave callbacks */ -#define GO_ASELPLUS 'P' /* autoselectPlus */ -#define GO_RIGHT 'r' /* use right scrollbar */ -#define GO_VRIGHT 'R' /* right scrollbar with vert split */ -#define GO_TEAROFF 't' /* add tear-off menu items */ -#define GO_TOOLBAR 'T' /* add toolbar */ -#define GO_FOOTER 'F' /* add footer */ -#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */ -#define GO_ALL "aAbcefFghilmMprtTv" /* all possible flags for 'go' */ - -/* flags for 'comments' option */ -#define COM_NEST 'n' /* comments strings nest */ -#define COM_BLANK 'b' /* needs blank after string */ -#define COM_START 's' /* start of comment */ -#define COM_MIDDLE 'm' /* middle of comment */ -#define COM_END 'e' /* end of comment */ -#define COM_AUTO_END 'x' /* last char of end closes comment */ -#define COM_FIRST 'f' /* first line comment only */ -#define COM_LEFT 'l' /* left adjusted */ -#define COM_RIGHT 'r' /* right adjusted */ -#define COM_NOBACK 'O' /* don't use for "O" command */ -#define COM_ALL "nbsmexflrO" /* all flags for 'comments' option */ -#define COM_MAX_LEN 50 /* maximum length of a part */ - -/* flags for 'statusline' option */ -#define STL_FILEPATH 'f' /* path of file in buffer */ -#define STL_FULLPATH 'F' /* full path of file in buffer */ -#define STL_FILENAME 't' /* last part (tail) of file path */ -#define STL_COLUMN 'c' /* column og cursor*/ -#define STL_VIRTCOL 'v' /* virtual column */ -#define STL_VIRTCOL_ALT 'V' /* - with 'if different' display */ -#define STL_LINE 'l' /* line number of cursor */ -#define STL_NUMLINES 'L' /* number of lines in buffer */ -#define STL_BUFNO 'n' /* current buffer number */ -#define STL_KEYMAP 'k' /* 'keymap' when active */ -#define STL_OFFSET 'o' /* offset of character under cursor*/ -#define STL_OFFSET_X 'O' /* - in hexadecimal */ -#define STL_BYTEVAL 'b' /* byte value of character */ -#define STL_BYTEVAL_X 'B' /* - in hexadecimal */ -#define STL_ROFLAG 'r' /* readonly flag */ -#define STL_ROFLAG_ALT 'R' /* - other display */ -#define STL_HELPFLAG 'h' /* window is showing a help file */ -#define STL_HELPFLAG_ALT 'H' /* - other display */ -#define STL_FILETYPE 'y' /* 'filetype' */ -#define STL_FILETYPE_ALT 'Y' /* - other display */ -#define STL_PREVIEWFLAG 'w' /* window is showing the preview buf */ -#define STL_PREVIEWFLAG_ALT 'W' /* - other display */ -#define STL_MODIFIED 'm' /* modified flag */ -#define STL_MODIFIED_ALT 'M' /* - other display */ -#define STL_QUICKFIX 'q' /* quickfix window description */ -#define STL_PERCENTAGE 'p' /* percentage through file */ -#define STL_ALTPERCENT 'P' /* percentage as TOP BOT ALL or NN% */ -#define STL_ARGLISTSTAT 'a' /* argument list status as (x of y) */ -#define STL_PAGENUM 'N' /* page number (when printing)*/ -#define STL_VIM_EXPR '{' /* start of expression to substitute */ -#define STL_MIDDLEMARK '=' /* separation between left and right */ -#define STL_TRUNCMARK '<' /* truncation mark if line is too long*/ -#define STL_USER_HL '*' /* highlight from (User)1..9 or 0 */ -#define STL_HIGHLIGHT '#' /* highlight name */ -#define STL_TABPAGENR 'T' /* tab page label nr */ -#define STL_TABCLOSENR 'X' /* tab page close nr */ -#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#") - -/* flags used for parsed 'wildmode' */ -#define WIM_FULL 1 -#define WIM_LONGEST 2 -#define WIM_LIST 4 - -/* arguments for can_bs() */ -#define BS_INDENT 'i' /* "Indent" */ -#define BS_EOL 'o' /* "eOl" */ -#define BS_START 's' /* "Start" */ - -#define LISPWORD_VALUE \ - "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object" - -/* - * The following are actual variables for the options - */ - -EXTERN long p_aleph; /* 'aleph' */ -EXTERN int p_acd; /* 'autochdir' */ -EXTERN char_u *p_ambw; /* 'ambiwidth' */ -EXTERN int p_ar; /* 'autoread' */ -EXTERN int p_aw; /* 'autowrite' */ -EXTERN int p_awa; /* 'autowriteall' */ -EXTERN char_u *p_bs; /* 'backspace' */ -EXTERN char_u *p_bg; /* 'background' */ -EXTERN int p_bk; /* 'backup' */ -EXTERN char_u *p_bkc; /* 'backupcopy' */ -EXTERN unsigned bkc_flags; -#ifdef IN_OPTION_C -static char *(p_bkc_values[]) = -{"yes", "auto", "no", "breaksymlink", "breakhardlink", NULL}; -#endif -# define BKC_YES 0x001 -# define BKC_AUTO 0x002 -# define BKC_NO 0x004 -# define BKC_BREAKSYMLINK 0x008 -# define BKC_BREAKHARDLINK 0x010 -EXTERN char_u *p_bdir; /* 'backupdir' */ -EXTERN char_u *p_bex; /* 'backupext' */ -EXTERN char_u *p_bsk; /* 'backupskip' */ -EXTERN char_u *p_cm; /* 'cryptmethod' */ -EXTERN char_u *p_breakat; /* 'breakat' */ -EXTERN char_u *p_cmp; /* 'casemap' */ -EXTERN unsigned cmp_flags; -# ifdef IN_OPTION_C -static char *(p_cmp_values[]) = {"internal", "keepascii", NULL}; -# endif -# define CMP_INTERNAL 0x001 -# define CMP_KEEPASCII 0x002 -EXTERN char_u *p_enc; /* 'encoding' */ -EXTERN int p_deco; /* 'delcombine' */ -EXTERN char_u *p_ccv; /* 'charconvert' */ -EXTERN char_u *p_cedit; /* 'cedit' */ -EXTERN long p_cwh; /* 'cmdwinheight' */ -EXTERN long p_ch; /* 'cmdheight' */ -EXTERN int p_confirm; /* 'confirm' */ -EXTERN int p_cp; /* 'compatible' */ -EXTERN char_u *p_cot; /* 'completeopt' */ -EXTERN long p_ph; /* 'pumheight' */ -EXTERN char_u *p_cpo; /* 'cpoptions' */ -EXTERN char_u *p_csprg; /* 'cscopeprg' */ -EXTERN int p_csre; /* 'cscoperelative' */ -EXTERN char_u *p_csqf; /* 'cscopequickfix' */ -# define CSQF_CMDS "sgdctefi" -# define CSQF_FLAGS "+-0" -EXTERN int p_cst; /* 'cscopetag' */ -EXTERN long p_csto; /* 'cscopetagorder' */ -EXTERN long p_cspc; /* 'cscopepathcomp' */ -EXTERN int p_csverbose; /* 'cscopeverbose' */ -EXTERN char_u *p_debug; /* 'debug' */ -EXTERN char_u *p_def; /* 'define' */ -EXTERN char_u *p_inc; -EXTERN char_u *p_dip; /* 'diffopt' */ -EXTERN char_u *p_dex; /* 'diffexpr' */ -EXTERN char_u *p_dict; /* 'dictionary' */ -EXTERN int p_dg; /* 'digraph' */ -EXTERN char_u *p_dir; /* 'directory' */ -EXTERN char_u *p_dy; /* 'display' */ -EXTERN unsigned dy_flags; -#ifdef IN_OPTION_C -static char *(p_dy_values[]) = {"lastline", "uhex", NULL}; -#endif -#define DY_LASTLINE 0x001 -#define DY_UHEX 0x002 -EXTERN int p_ed; /* 'edcompatible' */ -EXTERN char_u *p_ead; /* 'eadirection' */ -EXTERN int p_ea; /* 'equalalways' */ -EXTERN char_u *p_ep; /* 'equalprg' */ -EXTERN int p_eb; /* 'errorbells' */ -EXTERN char_u *p_ef; /* 'errorfile' */ -EXTERN char_u *p_efm; /* 'errorformat' */ -EXTERN char_u *p_gefm; /* 'grepformat' */ -EXTERN char_u *p_gp; /* 'grepprg' */ -EXTERN char_u *p_ei; /* 'eventignore' */ -EXTERN int p_ek; /* 'esckeys' */ -EXTERN int p_exrc; /* 'exrc' */ -EXTERN char_u *p_fencs; /* 'fileencodings' */ -EXTERN char_u *p_ffs; /* 'fileformats' */ -EXTERN long p_fic; /* 'fileignorecase' */ -EXTERN char_u *p_fcl; /* 'foldclose' */ -EXTERN long p_fdls; /* 'foldlevelstart' */ -EXTERN char_u *p_fdo; /* 'foldopen' */ -EXTERN unsigned fdo_flags; -# ifdef IN_OPTION_C -static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent", - "quickfix", "search", "tag", "insert", - "undo", "jump", NULL}; -# endif -# define FDO_ALL 0x001 -# define FDO_BLOCK 0x002 -# define FDO_HOR 0x004 -# define FDO_MARK 0x008 -# define FDO_PERCENT 0x010 -# define FDO_QUICKFIX 0x020 -# define FDO_SEARCH 0x040 -# define FDO_TAG 0x080 -# define FDO_INSERT 0x100 -# define FDO_UNDO 0x200 -# define FDO_JUMP 0x400 -EXTERN char_u *p_fp; /* 'formatprg' */ -#ifdef HAVE_FSYNC -EXTERN int p_fs; /* 'fsync' */ -#endif -EXTERN int p_gd; /* 'gdefault' */ -EXTERN char_u *p_pdev; /* 'printdevice' */ -EXTERN char_u *p_penc; /* 'printencoding' */ -EXTERN char_u *p_pexpr; /* 'printexpr' */ -EXTERN char_u *p_pmfn; /* 'printmbfont' */ -EXTERN char_u *p_pmcs; /* 'printmbcharset' */ -EXTERN char_u *p_pfn; /* 'printfont' */ -EXTERN char_u *p_popt; /* 'printoptions' */ -EXTERN char_u *p_header; /* 'printheader' */ -EXTERN int p_prompt; /* 'prompt' */ -#ifdef CURSOR_SHAPE -EXTERN char_u *p_guicursor; /* 'guicursor' */ -#endif -EXTERN char_u *p_hf; /* 'helpfile' */ -EXTERN long p_hh; /* 'helpheight' */ -EXTERN char_u *p_hlg; /* 'helplang' */ -EXTERN int p_hid; /* 'hidden' */ -/* Use P_HID to check if a buffer is to be hidden when it is no longer - * visible in a window. */ -# define P_HID(buf) (buf_hide(buf)) -EXTERN char_u *p_hl; /* 'highlight' */ -EXTERN int p_hls; /* 'hlsearch' */ -EXTERN long p_hi; /* 'history' */ -EXTERN int p_hkmap; /* 'hkmap' */ -EXTERN int p_hkmapp; /* 'hkmapp' */ -EXTERN int p_fkmap; /* 'fkmap' */ -EXTERN int p_altkeymap; /* 'altkeymap' */ -EXTERN int p_arshape; /* 'arabicshape' */ -EXTERN int p_icon; /* 'icon' */ -EXTERN char_u *p_iconstring; /* 'iconstring' */ -EXTERN int p_ic; /* 'ignorecase' */ -#ifdef USE_IM_CONTROL -EXTERN int p_imcmdline; /* 'imcmdline' */ -EXTERN int p_imdisable; /* 'imdisable' */ -#endif -EXTERN int p_is; /* 'incsearch' */ -EXTERN int p_im; /* 'insertmode' */ -EXTERN char_u *p_isf; /* 'isfname' */ -EXTERN char_u *p_isi; /* 'isident' */ -EXTERN char_u *p_isp; /* 'isprint' */ -EXTERN int p_js; /* 'joinspaces' */ -EXTERN char_u *p_kp; /* 'keywordprg' */ -EXTERN char_u *p_km; /* 'keymodel' */ -EXTERN char_u *p_langmap; /* 'langmap'*/ -EXTERN char_u *p_lm; /* 'langmenu' */ -EXTERN char_u *p_lispwords; /* 'lispwords' */ -EXTERN long p_ls; /* 'laststatus' */ -EXTERN long p_stal; /* 'showtabline' */ -EXTERN char_u *p_lcs; /* 'listchars' */ - -EXTERN int p_lz; /* 'lazyredraw' */ -EXTERN int p_lpl; /* 'loadplugins' */ -EXTERN int p_magic; /* 'magic' */ -EXTERN char_u *p_mef; /* 'makeef' */ -EXTERN char_u *p_mp; /* 'makeprg' */ -EXTERN char_u *p_cc; /* 'colorcolumn' */ -EXTERN int p_cc_cols[256]; /* array for 'colorcolumn' columns */ -EXTERN long p_mat; /* 'matchtime' */ -EXTERN long p_mco; /* 'maxcombine' */ -EXTERN long p_mfd; /* 'maxfuncdepth' */ -EXTERN long p_mmd; /* 'maxmapdepth' */ -EXTERN long p_mm; /* 'maxmem' */ -EXTERN long p_mmp; /* 'maxmempattern' */ -EXTERN long p_mmt; /* 'maxmemtot' */ -EXTERN long p_mis; /* 'menuitems' */ -EXTERN char_u *p_msm; /* 'mkspellmem' */ -EXTERN long p_mls; /* 'modelines' */ -EXTERN char_u *p_mouse; /* 'mouse' */ -EXTERN char_u *p_mousem; /* 'mousemodel' */ -EXTERN long p_mouset; /* 'mousetime' */ -EXTERN int p_more; /* 'more' */ -EXTERN char_u *p_opfunc; /* 'operatorfunc' */ -EXTERN char_u *p_para; /* 'paragraphs' */ -EXTERN int p_paste; /* 'paste' */ -EXTERN char_u *p_pt; /* 'pastetoggle' */ -EXTERN char_u *p_pex; /* 'patchexpr' */ -EXTERN char_u *p_pm; /* 'patchmode' */ -EXTERN char_u *p_path; /* 'path' */ -EXTERN char_u *p_cdpath; /* 'cdpath' */ -EXTERN long p_rdt; /* 'redrawtime' */ -EXTERN int p_remap; /* 'remap' */ -EXTERN long p_re; /* 'regexpengine' */ -EXTERN long p_report; /* 'report' */ -EXTERN long p_pvh; /* 'previewheight' */ -EXTERN int p_ari; /* 'allowrevins' */ -EXTERN int p_ri; /* 'revins' */ -EXTERN int p_ru; /* 'ruler' */ -EXTERN char_u *p_ruf; /* 'rulerformat' */ -EXTERN char_u *p_rtp; /* 'runtimepath' */ -EXTERN long p_sj; /* 'scrolljump' */ -EXTERN long p_so; /* 'scrolloff' */ -EXTERN char_u *p_sbo; /* 'scrollopt' */ -EXTERN char_u *p_sections; /* 'sections' */ -EXTERN int p_secure; /* 'secure' */ -EXTERN char_u *p_sel; /* 'selection' */ -EXTERN char_u *p_slm; /* 'selectmode' */ -EXTERN char_u *p_ssop; /* 'sessionoptions' */ -EXTERN unsigned ssop_flags; -# ifdef IN_OPTION_C -/* Also used for 'viewoptions'! */ -static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize", - "localoptions", "options", "help", "blank", - "globals", "slash", "unix", - "sesdir", "curdir", "folds", "cursor", - "tabpages", NULL}; -# endif -# define SSOP_BUFFERS 0x001 -# define SSOP_WINPOS 0x002 -# define SSOP_RESIZE 0x004 -# define SSOP_WINSIZE 0x008 -# define SSOP_LOCALOPTIONS 0x010 -# define SSOP_OPTIONS 0x020 -# define SSOP_HELP 0x040 -# define SSOP_BLANK 0x080 -# define SSOP_GLOBALS 0x100 -# define SSOP_SLASH 0x200 -# define SSOP_UNIX 0x400 -# define SSOP_SESDIR 0x800 -# define SSOP_CURDIR 0x1000 -# define SSOP_FOLDS 0x2000 -# define SSOP_CURSOR 0x4000 -# define SSOP_TABPAGES 0x8000 -EXTERN char_u *p_sh; /* 'shell' */ -EXTERN char_u *p_shcf; /* 'shellcmdflag' */ -EXTERN char_u *p_sp; /* 'shellpipe' */ -EXTERN char_u *p_shq; /* 'shellquote' */ -EXTERN char_u *p_sxq; /* 'shellxquote' */ -EXTERN char_u *p_sxe; /* 'shellxescape' */ -EXTERN char_u *p_srr; /* 'shellredir' */ -EXTERN int p_stmp; /* 'shelltemp' */ -#ifdef BACKSLASH_IN_FILENAME -EXTERN int p_ssl; /* 'shellslash' */ -#endif -EXTERN char_u *p_stl; /* 'statusline' */ -EXTERN int p_sr; /* 'shiftround' */ -EXTERN char_u *p_shm; /* 'shortmess' */ -EXTERN char_u *p_sbr; /* 'showbreak' */ -EXTERN int p_sc; /* 'showcmd' */ -EXTERN int p_sft; /* 'showfulltag' */ -EXTERN int p_sm; /* 'showmatch' */ -EXTERN int p_smd; /* 'showmode' */ -EXTERN long p_ss; /* 'sidescroll' */ -EXTERN long p_siso; /* 'sidescrolloff' */ -EXTERN int p_scs; /* 'smartcase' */ -EXTERN int p_sta; /* 'smarttab' */ -EXTERN int p_sb; /* 'splitbelow' */ -EXTERN long p_tpm; /* 'tabpagemax' */ -EXTERN char_u *p_tal; /* 'tabline' */ -EXTERN char_u *p_sps; /* 'spellsuggest' */ -EXTERN int p_spr; /* 'splitright' */ -EXTERN int p_sol; /* 'startofline' */ -EXTERN char_u *p_su; /* 'suffixes' */ -EXTERN char_u *p_sws; /* 'swapsync' */ -EXTERN char_u *p_swb; /* 'switchbuf' */ -EXTERN unsigned swb_flags; -#ifdef IN_OPTION_C -static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", NULL}; -#endif -#define SWB_USEOPEN 0x001 -#define SWB_USETAB 0x002 -#define SWB_SPLIT 0x004 -#define SWB_NEWTAB 0x008 -EXTERN int p_tbs; /* 'tagbsearch' */ -EXTERN long p_tl; /* 'taglength' */ -EXTERN int p_tr; /* 'tagrelative' */ -EXTERN char_u *p_tags; /* 'tags' */ -EXTERN int p_tgst; /* 'tagstack' */ -EXTERN int p_tbidi; /* 'termbidi' */ -EXTERN char_u *p_tenc; /* 'termencoding' */ -EXTERN int p_terse; /* 'terse' */ -EXTERN int p_ta; /* 'textauto' */ -EXTERN int p_to; /* 'tildeop' */ -EXTERN int p_timeout; /* 'timeout' */ -EXTERN long p_tm; /* 'timeoutlen' */ -EXTERN int p_title; /* 'title' */ -EXTERN long p_titlelen; /* 'titlelen' */ -EXTERN char_u *p_titleold; /* 'titleold' */ -EXTERN char_u *p_titlestring; /* 'titlestring' */ -EXTERN char_u *p_tsr; /* 'thesaurus' */ -EXTERN int p_ttimeout; /* 'ttimeout' */ -EXTERN long p_ttm; /* 'ttimeoutlen' */ -EXTERN int p_tbi; /* 'ttybuiltin' */ -EXTERN int p_tf; /* 'ttyfast' */ -EXTERN long p_ttyscroll; /* 'ttyscroll' */ -#if defined(FEAT_MOUSE) && (defined(UNIX) || defined(VMS)) -EXTERN char_u *p_ttym; /* 'ttymouse' */ -EXTERN unsigned ttym_flags; -# ifdef IN_OPTION_C -static char *(p_ttym_values[]) = -{"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL}; -# endif -# define TTYM_XTERM 0x01 -# define TTYM_XTERM2 0x02 -# define TTYM_DEC 0x04 -# define TTYM_NETTERM 0x08 -# define TTYM_JSBTERM 0x10 -# define TTYM_PTERM 0x20 -# define TTYM_URXVT 0x40 -# define TTYM_SGR 0x80 -#endif -EXTERN char_u *p_udir; /* 'undodir' */ -EXTERN long p_ul; /* 'undolevels' */ -EXTERN long p_ur; /* 'undoreload' */ -EXTERN long p_uc; /* 'updatecount' */ -EXTERN long p_ut; /* 'updatetime' */ -EXTERN char_u *p_fcs; /* 'fillchar' */ -EXTERN char_u *p_viminfo; /* 'viminfo' */ -EXTERN char_u *p_vdir; /* 'viewdir' */ -EXTERN char_u *p_vop; /* 'viewoptions' */ -EXTERN unsigned vop_flags; /* uses SSOP_ flags */ -EXTERN int p_vb; /* 'visualbell' */ -EXTERN char_u *p_ve; /* 'virtualedit' */ -EXTERN unsigned ve_flags; -# ifdef IN_OPTION_C -static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", NULL}; -# endif -# define VE_BLOCK 5 /* includes "all" */ -# define VE_INSERT 6 /* includes "all" */ -# define VE_ALL 4 -# define VE_ONEMORE 8 -EXTERN long p_verbose; /* 'verbose' */ -#ifdef IN_OPTION_C -char_u *p_vfile = (char_u *)""; /* used before options are initialized */ -#else -extern char_u *p_vfile; /* 'verbosefile' */ -#endif -EXTERN int p_warn; /* 'warn' */ -EXTERN char_u *p_wop; /* 'wildoptions' */ -EXTERN long p_window; /* 'window' */ -#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(LINT) \ - || defined (FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) -#define FEAT_WAK -EXTERN char_u *p_wak; /* 'winaltkeys' */ -#endif -EXTERN char_u *p_wak; -EXTERN char_u *p_wig; /* 'wildignore' */ -EXTERN int p_wiv; /* 'weirdinvert' */ -EXTERN char_u *p_ww; /* 'whichwrap' */ -EXTERN long p_wc; /* 'wildchar' */ -EXTERN long p_wcm; /* 'wildcharm' */ -EXTERN long p_wic; /* 'wildignorecase' */ -EXTERN char_u *p_wim; /* 'wildmode' */ -EXTERN int p_wmnu; /* 'wildmenu' */ -EXTERN long p_wh; /* 'winheight' */ -EXTERN long p_wmh; /* 'winminheight' */ -EXTERN long p_wmw; /* 'winminwidth' */ -EXTERN long p_wiw; /* 'winwidth' */ -EXTERN int p_ws; /* 'wrapscan' */ -EXTERN int p_write; /* 'write' */ -EXTERN int p_wa; /* 'writeany' */ -EXTERN int p_wb; /* 'writebackup' */ -EXTERN long p_wd; /* 'writedelay' */ - -/* - * "indir" values for buffer-local opions. - * These need to be defined globally, so that the BV_COUNT can be used with - * b_p_scriptID[]. - */ -enum { - BV_AI = 0 - , BV_AR - , BV_BH - , BV_BT - , BV_EFM - , BV_GP - , BV_MP - , BV_BIN - , BV_BL - , BV_BOMB - , BV_CI - , BV_CIN - , BV_CINK - , BV_CINO - , BV_CINW - , BV_CM - , BV_CMS - , BV_COM - , BV_CPT - , BV_DICT - , BV_TSR - , BV_CFU - , BV_DEF - , BV_INC - , BV_EOL - , BV_EP - , BV_ET - , BV_FENC - , BV_BEXPR - , BV_FEX - , BV_FF - , BV_FLP - , BV_FO - , BV_FT - , BV_IMI - , BV_IMS - , BV_INDE - , BV_INDK - , BV_INEX - , BV_INF - , BV_ISK - , BV_KEY - , BV_KMAP - , BV_KP - , BV_LISP - , BV_MA - , BV_ML - , BV_MOD - , BV_MPS - , BV_NF - , BV_OFU - , BV_PATH - , BV_PI - , BV_QE - , BV_RO - , BV_SI -#ifndef SHORT_FNAME - , BV_SN -#endif - , BV_SMC - , BV_SYN - , BV_SPC - , BV_SPF - , BV_SPL - , BV_STS - , BV_SUA - , BV_SW - , BV_SWF - , BV_TAGS - , BV_TS - , BV_TW - , BV_TX - , BV_UDF - , BV_UL - , BV_WM - , BV_COUNT /* must be the last one */ -}; - -/* - * "indir" values for window-local options. - * These need to be defined globally, so that the WV_COUNT can be used in the - * window structure. - */ -enum { - WV_LIST = 0 - , WV_ARAB - , WV_COCU - , WV_COLE - , WV_CRBIND - , WV_DIFF - , WV_FDC - , WV_FEN - , WV_FDI - , WV_FDL - , WV_FDM - , WV_FML - , WV_FDN - , WV_FDE - , WV_FDT - , WV_FMR - , WV_LBR - , WV_NU - , WV_RNU - , WV_NUW - , WV_PVW - , WV_RL - , WV_RLC - , WV_SCBIND - , WV_SCROLL - , WV_SPELL - , WV_CUC - , WV_CUL - , WV_CC - , WV_STL - , WV_WFH - , WV_WFW - , WV_WRAP - , WV_COUNT /* must be the last one */ -}; - -/* Value for b_p_ul indicating the global value must be used. */ -#define NO_LOCAL_UNDOLEVEL -123456 +#ifndef NEOVIM_OPTION_H +#define NEOVIM_OPTION_H +/* option.c */ +void set_init_1 __ARGS((void)); +void set_string_default __ARGS((char *name, char_u *val)); +void set_number_default __ARGS((char *name, long val)); +void free_all_options __ARGS((void)); +void set_init_2 __ARGS((void)); +void set_init_3 __ARGS((void)); +void set_helplang_default __ARGS((char_u *lang)); +void init_gui_options __ARGS((void)); +void set_title_defaults __ARGS((void)); +int do_set __ARGS((char_u *arg, int opt_flags)); +void set_options_bin __ARGS((int oldval, int newval, int opt_flags)); +int get_viminfo_parameter __ARGS((int type)); +char_u *find_viminfo_parameter __ARGS((int type)); +void check_options __ARGS((void)); +void check_buf_options __ARGS((buf_T *buf)); +void free_string_option __ARGS((char_u *p)); +void clear_string_option __ARGS((char_u **pp)); +void set_term_option_alloced __ARGS((char_u **p)); +int was_set_insecurely __ARGS((char_u *opt, int opt_flags)); +void set_string_option_direct __ARGS((char_u *name, int opt_idx, char_u *val, + int opt_flags, + int set_sid)); +char_u *check_colorcolumn __ARGS((win_T *wp)); +char_u *check_stl_option __ARGS((char_u *s)); +int get_option_value __ARGS((char_u *name, long *numval, char_u **stringval, + int opt_flags)); +int get_option_value_strict __ARGS((char_u *name, long *numval, char_u * + *stringval, int opt_type, + void *from)); +char_u *option_iter_next __ARGS((void **option, int opt_type)); +char_u *set_option_value __ARGS((char_u *name, long number, char_u *string, + int opt_flags)); +char_u *get_term_code __ARGS((char_u *tname)); +char_u *get_highlight_default __ARGS((void)); +char_u *get_encoding_default __ARGS((void)); +int makeset __ARGS((FILE *fd, int opt_flags, int local_only)); +int makefoldset __ARGS((FILE *fd)); +void clear_termoptions __ARGS((void)); +void free_termoptions __ARGS((void)); +void free_one_termoption __ARGS((char_u *var)); +void set_term_defaults __ARGS((void)); +void comp_col __ARGS((void)); +void unset_global_local_option __ARGS((char_u *name, void *from)); +char_u *get_equalprg __ARGS((void)); +void win_copy_options __ARGS((win_T *wp_from, win_T *wp_to)); +void copy_winopt __ARGS((winopt_T *from, winopt_T *to)); +void check_win_options __ARGS((win_T *win)); +void check_winopt __ARGS((winopt_T *wop)); +void clear_winopt __ARGS((winopt_T *wop)); +void buf_copy_options __ARGS((buf_T *buf, int flags)); +void reset_modifiable __ARGS((void)); +void set_iminsert_global __ARGS((void)); +void set_imsearch_global __ARGS((void)); +void set_context_in_set_cmd __ARGS((expand_T *xp, char_u *arg, int opt_flags)); +int ExpandSettings __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, + char_u ***file)); +int ExpandOldSetting __ARGS((int *num_file, char_u ***file)); +int langmap_adjust_mb __ARGS((int c)); +int has_format_option __ARGS((int x)); +int shortmess __ARGS((int x)); +void vimrc_found __ARGS((char_u *fname, char_u *envname)); +void change_compatible __ARGS((int on)); +int option_was_set __ARGS((char_u *name)); +void reset_option_was_set __ARGS((char_u *name)); +int can_bs __ARGS((int what)); +void save_file_ff __ARGS((buf_T *buf)); +int file_ff_differs __ARGS((buf_T *buf, int ignore_empty)); +int check_ff_value __ARGS((char_u *p)); +long get_sw_value __ARGS((buf_T *buf)); +long get_sts_value __ARGS((void)); +void find_mps_values __ARGS((int *initc, int *findc, int *backwards, + int switchit)); +/* vim: set ft=c : */ +#endif /* NEOVIM_OPTION_H */ diff --git a/src/option_defs.h b/src/option_defs.h new file mode 100644 index 0000000000..6dc232d03d --- /dev/null +++ b/src/option_defs.h @@ -0,0 +1,768 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * option_defs.h: definition of global variables for settable options + */ + +/* + * Default values for 'errorformat'. + * The "%f|%l| %m" one is used for when the contents of the quickfix window is + * written to a file. + */ +#define DFLT_EFM \ + "%*[^\"]\"%f\"%*\\D%l: %m,\"%f\"%*\\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l: for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\\,,%-GIn file included from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\\,,%-G%*[ ]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,\"%f\"\\, line %l%*\\D%c%*[^ ] %m,%D%*\\a[%*\\d]: Entering directory %*[`']%f',%X%*\\a[%*\\d]: Leaving directory %*[`']%f',%D%*\\a: Entering directory %*[`']%f',%X%*\\a: Leaving directory %*[`']%f',%DMaking %*\\a in %f,%f|%l| %m" + +#define DFLT_GREPFORMAT "%f:%l:%m,%f:%l%m,%f %l%m" + +/* default values for b_p_ff 'fileformat' and p_ffs 'fileformats' */ +#define FF_DOS "dos" +#define FF_MAC "mac" +#define FF_UNIX "unix" + +#ifdef USE_CRNL +# define DFLT_FF "dos" +# define DFLT_FFS_VIM "dos,unix" +# define DFLT_FFS_VI "dos,unix" /* also autodetect in compatible mode */ +# define DFLT_TEXTAUTO TRUE +#else +# ifdef USE_CR +# define DFLT_FF "mac" +# define DFLT_FFS_VIM "mac,unix,dos" +# define DFLT_FFS_VI "mac,unix,dos" +# define DFLT_TEXTAUTO TRUE +# else +# define DFLT_FF "unix" +# define DFLT_FFS_VIM "unix,dos" +# define DFLT_FFS_VI "" +# define DFLT_TEXTAUTO FALSE +# endif +#endif + + +/* Possible values for 'encoding' */ +# define ENC_UCSBOM "ucs-bom" /* check for BOM at start of file */ + +/* default value for 'encoding' */ +# define ENC_DFLT "latin1" + +/* end-of-line style */ +#define EOL_UNKNOWN -1 /* not defined yet */ +#define EOL_UNIX 0 /* NL */ +#define EOL_DOS 1 /* CR NL */ +#define EOL_MAC 2 /* CR */ + +/* Formatting options for p_fo 'formatoptions' */ +#define FO_WRAP 't' +#define FO_WRAP_COMS 'c' +#define FO_RET_COMS 'r' +#define FO_OPEN_COMS 'o' +#define FO_Q_COMS 'q' +#define FO_Q_NUMBER 'n' +#define FO_Q_SECOND '2' +#define FO_INS_VI 'v' +#define FO_INS_LONG 'l' +#define FO_INS_BLANK 'b' +#define FO_MBYTE_BREAK 'm' /* break before/after multi-byte char */ +#define FO_MBYTE_JOIN 'M' /* no space before/after multi-byte char */ +#define FO_MBYTE_JOIN2 'B' /* no space between multi-byte chars */ +#define FO_ONE_LETTER '1' +#define FO_WHITE_PAR 'w' /* trailing white space continues paragr. */ +#define FO_AUTO 'a' /* automatic formatting */ +#define FO_REMOVE_COMS 'j' /* remove comment leaders when joining lines */ + +#define DFLT_FO_VI "vt" +#define DFLT_FO_VIM "tcq" +#define FO_ALL "tcroq2vlb1mMBn,awj" /* for do_set() */ + +/* characters for the p_cpo option: */ +#define CPO_ALTREAD 'a' /* ":read" sets alternate file name */ +#define CPO_ALTWRITE 'A' /* ":write" sets alternate file name */ +#define CPO_BAR 'b' /* "\|" ends a mapping */ +#define CPO_BSLASH 'B' /* backslash in mapping is not special */ +#define CPO_SEARCH 'c' +#define CPO_CONCAT 'C' /* Don't concatenate sourced lines */ +#define CPO_DOTTAG 'd' /* "./tags" in 'tags' is in current dir */ +#define CPO_DIGRAPH 'D' /* No digraph after "r", "f", etc. */ +#define CPO_EXECBUF 'e' +#define CPO_EMPTYREGION 'E' /* operating on empty region is an error */ +#define CPO_FNAMER 'f' /* set file name for ":r file" */ +#define CPO_FNAMEW 'F' /* set file name for ":w file" */ +#define CPO_GOTO1 'g' /* goto line 1 for ":edit" */ +#define CPO_INSEND 'H' /* "I" inserts before last blank in line */ +#define CPO_INTMOD 'i' /* interrupt a read makes buffer modified */ +#define CPO_INDENT 'I' /* remove auto-indent more often */ +#define CPO_JOINSP 'j' /* only use two spaces for join after '.' */ +#define CPO_ENDOFSENT 'J' /* need two spaces to detect end of sentence */ +#define CPO_KEYCODE 'k' /* don't recognize raw key code in mappings */ +#define CPO_KOFFSET 'K' /* don't wait for key code in mappings */ +#define CPO_LITERAL 'l' /* take char after backslash in [] literal */ +#define CPO_LISTWM 'L' /* 'list' changes wrapmargin */ +#define CPO_SHOWMATCH 'm' +#define CPO_MATCHBSL 'M' /* "%" ignores use of backslashes */ +#define CPO_NUMCOL 'n' /* 'number' column also used for text */ +#define CPO_LINEOFF 'o' +#define CPO_OVERNEW 'O' /* silently overwrite new file */ +#define CPO_LISP 'p' /* 'lisp' indenting */ +#define CPO_FNAMEAPP 'P' /* set file name for ":w >>file" */ +#define CPO_JOINCOL 'q' /* with "3J" use column after first join */ +#define CPO_REDO 'r' +#define CPO_REMMARK 'R' /* remove marks when filtering */ +#define CPO_BUFOPT 's' +#define CPO_BUFOPTGLOB 'S' +#define CPO_TAGPAT 't' +#define CPO_UNDO 'u' /* "u" undoes itself */ +#define CPO_BACKSPACE 'v' /* "v" keep deleted text */ +#define CPO_CW 'w' /* "cw" only changes one blank */ +#define CPO_FWRITE 'W' /* "w!" doesn't overwrite readonly files */ +#define CPO_ESC 'x' +#define CPO_REPLCNT 'X' /* "R" with a count only deletes chars once */ +#define CPO_YANK 'y' +#define CPO_KEEPRO 'Z' /* don't reset 'readonly' on ":w!" */ +#define CPO_DOLLAR '$' +#define CPO_FILTER '!' +#define CPO_MATCH '%' +#define CPO_STAR '*' /* ":*" means ":@" */ +#define CPO_PLUS '+' /* ":write file" resets 'modified' */ +#define CPO_MINUS '-' /* "9-" fails at and before line 9 */ +#define CPO_SPECI '<' /* don't recognize <> in mappings */ +#define CPO_REGAPPEND '>' /* insert NL when appending to a register */ +/* POSIX flags */ +#define CPO_HASH '#' /* "D", "o" and "O" do not use a count */ +#define CPO_PARA '{' /* "{" is also a paragraph boundary */ +#define CPO_TSIZE '|' /* $LINES and $COLUMNS overrule term size */ +#define CPO_PRESERVE '&' /* keep swap file after :preserve */ +#define CPO_SUBPERCENT '/' /* % in :s string uses previous one */ +#define CPO_BACKSL '\\' /* \ is not special in [] */ +#define CPO_CHDIR '.' /* don't chdir if buffer is modified */ +#define CPO_SCOLON ';' /* using "," and ";" will skip over char if + * cursor would not move */ +/* default values for Vim, Vi and POSIX */ +#define CPO_VIM "aABceFs" +#define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;" +#define CPO_ALL \ + "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\\.;" + +/* characters for p_ww option: */ +#define WW_ALL "bshl<>[],~" + +/* characters for p_mouse option: */ +#define MOUSE_NORMAL 'n' /* use mouse in Normal mode */ +#define MOUSE_VISUAL 'v' /* use mouse in Visual/Select mode */ +#define MOUSE_INSERT 'i' /* use mouse in Insert mode */ +#define MOUSE_COMMAND 'c' /* use mouse in Command-line mode */ +#define MOUSE_HELP 'h' /* use mouse in help buffers */ +#define MOUSE_RETURN 'r' /* use mouse for hit-return message */ +#define MOUSE_A "nvich" /* used for 'a' flag */ +#define MOUSE_ALL "anvichr" /* all possible characters */ +#define MOUSE_NONE ' ' /* don't use Visual selection */ +#define MOUSE_NONEF 'x' /* forced modeless selection */ + +#define COCU_ALL "nvic" /* flags for 'concealcursor' */ + +/* characters for p_shm option: */ +#define SHM_RO 'r' /* readonly */ +#define SHM_MOD 'm' /* modified */ +#define SHM_FILE 'f' /* (file 1 of 2) */ +#define SHM_LAST 'i' /* last line incomplete */ +#define SHM_TEXT 'x' /* tx instead of textmode */ +#define SHM_LINES 'l' /* "L" instead of "lines" */ +#define SHM_NEW 'n' /* "[New]" instead of "[New file]" */ +#define SHM_WRI 'w' /* "[w]" instead of "written" */ +#define SHM_A "rmfixlnw" /* represented by 'a' flag */ +#define SHM_WRITE 'W' /* don't use "written" at all */ +#define SHM_TRUNC 't' /* trunctate file messages */ +#define SHM_TRUNCALL 'T' /* trunctate all messages */ +#define SHM_OVER 'o' /* overwrite file messages */ +#define SHM_OVERALL 'O' /* overwrite more messages */ +#define SHM_SEARCH 's' /* no search hit bottom messages */ +#define SHM_ATTENTION 'A' /* no ATTENTION messages */ +#define SHM_INTRO 'I' /* intro messages */ +#define SHM_ALL "rmfixlnwaWtToOsAI" /* all possible flags for 'shm' */ + +/* characters for p_go: */ +#define GO_ASEL 'a' /* autoselect */ +#define GO_ASELML 'A' /* autoselect modeless selection */ +#define GO_BOT 'b' /* use bottom scrollbar */ +#define GO_CONDIALOG 'c' /* use console dialog */ +#define GO_TABLINE 'e' /* may show tabline */ +#define GO_FORG 'f' /* start GUI in foreground */ +#define GO_GREY 'g' /* use grey menu items */ +#define GO_HORSCROLL 'h' /* flexible horizontal scrolling */ +#define GO_ICON 'i' /* use Vim icon */ +#define GO_LEFT 'l' /* use left scrollbar */ +#define GO_VLEFT 'L' /* left scrollbar with vert split */ +#define GO_MENUS 'm' /* use menu bar */ +#define GO_NOSYSMENU 'M' /* don't source system menu */ +#define GO_POINTER 'p' /* pointer enter/leave callbacks */ +#define GO_ASELPLUS 'P' /* autoselectPlus */ +#define GO_RIGHT 'r' /* use right scrollbar */ +#define GO_VRIGHT 'R' /* right scrollbar with vert split */ +#define GO_TEAROFF 't' /* add tear-off menu items */ +#define GO_TOOLBAR 'T' /* add toolbar */ +#define GO_FOOTER 'F' /* add footer */ +#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */ +#define GO_ALL "aAbcefFghilmMprtTv" /* all possible flags for 'go' */ + +/* flags for 'comments' option */ +#define COM_NEST 'n' /* comments strings nest */ +#define COM_BLANK 'b' /* needs blank after string */ +#define COM_START 's' /* start of comment */ +#define COM_MIDDLE 'm' /* middle of comment */ +#define COM_END 'e' /* end of comment */ +#define COM_AUTO_END 'x' /* last char of end closes comment */ +#define COM_FIRST 'f' /* first line comment only */ +#define COM_LEFT 'l' /* left adjusted */ +#define COM_RIGHT 'r' /* right adjusted */ +#define COM_NOBACK 'O' /* don't use for "O" command */ +#define COM_ALL "nbsmexflrO" /* all flags for 'comments' option */ +#define COM_MAX_LEN 50 /* maximum length of a part */ + +/* flags for 'statusline' option */ +#define STL_FILEPATH 'f' /* path of file in buffer */ +#define STL_FULLPATH 'F' /* full path of file in buffer */ +#define STL_FILENAME 't' /* last part (tail) of file path */ +#define STL_COLUMN 'c' /* column og cursor*/ +#define STL_VIRTCOL 'v' /* virtual column */ +#define STL_VIRTCOL_ALT 'V' /* - with 'if different' display */ +#define STL_LINE 'l' /* line number of cursor */ +#define STL_NUMLINES 'L' /* number of lines in buffer */ +#define STL_BUFNO 'n' /* current buffer number */ +#define STL_KEYMAP 'k' /* 'keymap' when active */ +#define STL_OFFSET 'o' /* offset of character under cursor*/ +#define STL_OFFSET_X 'O' /* - in hexadecimal */ +#define STL_BYTEVAL 'b' /* byte value of character */ +#define STL_BYTEVAL_X 'B' /* - in hexadecimal */ +#define STL_ROFLAG 'r' /* readonly flag */ +#define STL_ROFLAG_ALT 'R' /* - other display */ +#define STL_HELPFLAG 'h' /* window is showing a help file */ +#define STL_HELPFLAG_ALT 'H' /* - other display */ +#define STL_FILETYPE 'y' /* 'filetype' */ +#define STL_FILETYPE_ALT 'Y' /* - other display */ +#define STL_PREVIEWFLAG 'w' /* window is showing the preview buf */ +#define STL_PREVIEWFLAG_ALT 'W' /* - other display */ +#define STL_MODIFIED 'm' /* modified flag */ +#define STL_MODIFIED_ALT 'M' /* - other display */ +#define STL_QUICKFIX 'q' /* quickfix window description */ +#define STL_PERCENTAGE 'p' /* percentage through file */ +#define STL_ALTPERCENT 'P' /* percentage as TOP BOT ALL or NN% */ +#define STL_ARGLISTSTAT 'a' /* argument list status as (x of y) */ +#define STL_PAGENUM 'N' /* page number (when printing)*/ +#define STL_VIM_EXPR '{' /* start of expression to substitute */ +#define STL_MIDDLEMARK '=' /* separation between left and right */ +#define STL_TRUNCMARK '<' /* truncation mark if line is too long*/ +#define STL_USER_HL '*' /* highlight from (User)1..9 or 0 */ +#define STL_HIGHLIGHT '#' /* highlight name */ +#define STL_TABPAGENR 'T' /* tab page label nr */ +#define STL_TABCLOSENR 'X' /* tab page close nr */ +#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#") + +/* flags used for parsed 'wildmode' */ +#define WIM_FULL 1 +#define WIM_LONGEST 2 +#define WIM_LIST 4 + +/* arguments for can_bs() */ +#define BS_INDENT 'i' /* "Indent" */ +#define BS_EOL 'o' /* "eOl" */ +#define BS_START 's' /* "Start" */ + +#define LISPWORD_VALUE \ + "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object" + +/* + * The following are actual variables for the options + */ + +EXTERN long p_aleph; /* 'aleph' */ +EXTERN int p_acd; /* 'autochdir' */ +EXTERN char_u *p_ambw; /* 'ambiwidth' */ +EXTERN int p_ar; /* 'autoread' */ +EXTERN int p_aw; /* 'autowrite' */ +EXTERN int p_awa; /* 'autowriteall' */ +EXTERN char_u *p_bs; /* 'backspace' */ +EXTERN char_u *p_bg; /* 'background' */ +EXTERN int p_bk; /* 'backup' */ +EXTERN char_u *p_bkc; /* 'backupcopy' */ +EXTERN unsigned bkc_flags; +#ifdef IN_OPTION_C +static char *(p_bkc_values[]) = +{"yes", "auto", "no", "breaksymlink", "breakhardlink", NULL}; +#endif +# define BKC_YES 0x001 +# define BKC_AUTO 0x002 +# define BKC_NO 0x004 +# define BKC_BREAKSYMLINK 0x008 +# define BKC_BREAKHARDLINK 0x010 +EXTERN char_u *p_bdir; /* 'backupdir' */ +EXTERN char_u *p_bex; /* 'backupext' */ +EXTERN char_u *p_bsk; /* 'backupskip' */ +EXTERN char_u *p_cm; /* 'cryptmethod' */ +EXTERN char_u *p_breakat; /* 'breakat' */ +EXTERN char_u *p_cmp; /* 'casemap' */ +EXTERN unsigned cmp_flags; +# ifdef IN_OPTION_C +static char *(p_cmp_values[]) = {"internal", "keepascii", NULL}; +# endif +# define CMP_INTERNAL 0x001 +# define CMP_KEEPASCII 0x002 +EXTERN char_u *p_enc; /* 'encoding' */ +EXTERN int p_deco; /* 'delcombine' */ +EXTERN char_u *p_ccv; /* 'charconvert' */ +EXTERN char_u *p_cedit; /* 'cedit' */ +EXTERN long p_cwh; /* 'cmdwinheight' */ +EXTERN long p_ch; /* 'cmdheight' */ +EXTERN int p_confirm; /* 'confirm' */ +EXTERN int p_cp; /* 'compatible' */ +EXTERN char_u *p_cot; /* 'completeopt' */ +EXTERN long p_ph; /* 'pumheight' */ +EXTERN char_u *p_cpo; /* 'cpoptions' */ +EXTERN char_u *p_csprg; /* 'cscopeprg' */ +EXTERN int p_csre; /* 'cscoperelative' */ +EXTERN char_u *p_csqf; /* 'cscopequickfix' */ +# define CSQF_CMDS "sgdctefi" +# define CSQF_FLAGS "+-0" +EXTERN int p_cst; /* 'cscopetag' */ +EXTERN long p_csto; /* 'cscopetagorder' */ +EXTERN long p_cspc; /* 'cscopepathcomp' */ +EXTERN int p_csverbose; /* 'cscopeverbose' */ +EXTERN char_u *p_debug; /* 'debug' */ +EXTERN char_u *p_def; /* 'define' */ +EXTERN char_u *p_inc; +EXTERN char_u *p_dip; /* 'diffopt' */ +EXTERN char_u *p_dex; /* 'diffexpr' */ +EXTERN char_u *p_dict; /* 'dictionary' */ +EXTERN int p_dg; /* 'digraph' */ +EXTERN char_u *p_dir; /* 'directory' */ +EXTERN char_u *p_dy; /* 'display' */ +EXTERN unsigned dy_flags; +#ifdef IN_OPTION_C +static char *(p_dy_values[]) = {"lastline", "uhex", NULL}; +#endif +#define DY_LASTLINE 0x001 +#define DY_UHEX 0x002 +EXTERN int p_ed; /* 'edcompatible' */ +EXTERN char_u *p_ead; /* 'eadirection' */ +EXTERN int p_ea; /* 'equalalways' */ +EXTERN char_u *p_ep; /* 'equalprg' */ +EXTERN int p_eb; /* 'errorbells' */ +EXTERN char_u *p_ef; /* 'errorfile' */ +EXTERN char_u *p_efm; /* 'errorformat' */ +EXTERN char_u *p_gefm; /* 'grepformat' */ +EXTERN char_u *p_gp; /* 'grepprg' */ +EXTERN char_u *p_ei; /* 'eventignore' */ +EXTERN int p_ek; /* 'esckeys' */ +EXTERN int p_exrc; /* 'exrc' */ +EXTERN char_u *p_fencs; /* 'fileencodings' */ +EXTERN char_u *p_ffs; /* 'fileformats' */ +EXTERN long p_fic; /* 'fileignorecase' */ +EXTERN char_u *p_fcl; /* 'foldclose' */ +EXTERN long p_fdls; /* 'foldlevelstart' */ +EXTERN char_u *p_fdo; /* 'foldopen' */ +EXTERN unsigned fdo_flags; +# ifdef IN_OPTION_C +static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent", + "quickfix", "search", "tag", "insert", + "undo", "jump", NULL}; +# endif +# define FDO_ALL 0x001 +# define FDO_BLOCK 0x002 +# define FDO_HOR 0x004 +# define FDO_MARK 0x008 +# define FDO_PERCENT 0x010 +# define FDO_QUICKFIX 0x020 +# define FDO_SEARCH 0x040 +# define FDO_TAG 0x080 +# define FDO_INSERT 0x100 +# define FDO_UNDO 0x200 +# define FDO_JUMP 0x400 +EXTERN char_u *p_fp; /* 'formatprg' */ +#ifdef HAVE_FSYNC +EXTERN int p_fs; /* 'fsync' */ +#endif +EXTERN int p_gd; /* 'gdefault' */ +EXTERN char_u *p_pdev; /* 'printdevice' */ +EXTERN char_u *p_penc; /* 'printencoding' */ +EXTERN char_u *p_pexpr; /* 'printexpr' */ +EXTERN char_u *p_pmfn; /* 'printmbfont' */ +EXTERN char_u *p_pmcs; /* 'printmbcharset' */ +EXTERN char_u *p_pfn; /* 'printfont' */ +EXTERN char_u *p_popt; /* 'printoptions' */ +EXTERN char_u *p_header; /* 'printheader' */ +EXTERN int p_prompt; /* 'prompt' */ +#ifdef CURSOR_SHAPE +EXTERN char_u *p_guicursor; /* 'guicursor' */ +#endif +EXTERN char_u *p_hf; /* 'helpfile' */ +EXTERN long p_hh; /* 'helpheight' */ +EXTERN char_u *p_hlg; /* 'helplang' */ +EXTERN int p_hid; /* 'hidden' */ +/* Use P_HID to check if a buffer is to be hidden when it is no longer + * visible in a window. */ +# define P_HID(buf) (buf_hide(buf)) +EXTERN char_u *p_hl; /* 'highlight' */ +EXTERN int p_hls; /* 'hlsearch' */ +EXTERN long p_hi; /* 'history' */ +EXTERN int p_hkmap; /* 'hkmap' */ +EXTERN int p_hkmapp; /* 'hkmapp' */ +EXTERN int p_fkmap; /* 'fkmap' */ +EXTERN int p_altkeymap; /* 'altkeymap' */ +EXTERN int p_arshape; /* 'arabicshape' */ +EXTERN int p_icon; /* 'icon' */ +EXTERN char_u *p_iconstring; /* 'iconstring' */ +EXTERN int p_ic; /* 'ignorecase' */ +#ifdef USE_IM_CONTROL +EXTERN int p_imcmdline; /* 'imcmdline' */ +EXTERN int p_imdisable; /* 'imdisable' */ +#endif +EXTERN int p_is; /* 'incsearch' */ +EXTERN int p_im; /* 'insertmode' */ +EXTERN char_u *p_isf; /* 'isfname' */ +EXTERN char_u *p_isi; /* 'isident' */ +EXTERN char_u *p_isp; /* 'isprint' */ +EXTERN int p_js; /* 'joinspaces' */ +EXTERN char_u *p_kp; /* 'keywordprg' */ +EXTERN char_u *p_km; /* 'keymodel' */ +EXTERN char_u *p_langmap; /* 'langmap'*/ +EXTERN char_u *p_lm; /* 'langmenu' */ +EXTERN char_u *p_lispwords; /* 'lispwords' */ +EXTERN long p_ls; /* 'laststatus' */ +EXTERN long p_stal; /* 'showtabline' */ +EXTERN char_u *p_lcs; /* 'listchars' */ + +EXTERN int p_lz; /* 'lazyredraw' */ +EXTERN int p_lpl; /* 'loadplugins' */ +EXTERN int p_magic; /* 'magic' */ +EXTERN char_u *p_mef; /* 'makeef' */ +EXTERN char_u *p_mp; /* 'makeprg' */ +EXTERN char_u *p_cc; /* 'colorcolumn' */ +EXTERN int p_cc_cols[256]; /* array for 'colorcolumn' columns */ +EXTERN long p_mat; /* 'matchtime' */ +EXTERN long p_mco; /* 'maxcombine' */ +EXTERN long p_mfd; /* 'maxfuncdepth' */ +EXTERN long p_mmd; /* 'maxmapdepth' */ +EXTERN long p_mm; /* 'maxmem' */ +EXTERN long p_mmp; /* 'maxmempattern' */ +EXTERN long p_mmt; /* 'maxmemtot' */ +EXTERN long p_mis; /* 'menuitems' */ +EXTERN char_u *p_msm; /* 'mkspellmem' */ +EXTERN long p_mls; /* 'modelines' */ +EXTERN char_u *p_mouse; /* 'mouse' */ +EXTERN char_u *p_mousem; /* 'mousemodel' */ +EXTERN long p_mouset; /* 'mousetime' */ +EXTERN int p_more; /* 'more' */ +EXTERN char_u *p_opfunc; /* 'operatorfunc' */ +EXTERN char_u *p_para; /* 'paragraphs' */ +EXTERN int p_paste; /* 'paste' */ +EXTERN char_u *p_pt; /* 'pastetoggle' */ +EXTERN char_u *p_pex; /* 'patchexpr' */ +EXTERN char_u *p_pm; /* 'patchmode' */ +EXTERN char_u *p_path; /* 'path' */ +EXTERN char_u *p_cdpath; /* 'cdpath' */ +EXTERN long p_rdt; /* 'redrawtime' */ +EXTERN int p_remap; /* 'remap' */ +EXTERN long p_re; /* 'regexpengine' */ +EXTERN long p_report; /* 'report' */ +EXTERN long p_pvh; /* 'previewheight' */ +EXTERN int p_ari; /* 'allowrevins' */ +EXTERN int p_ri; /* 'revins' */ +EXTERN int p_ru; /* 'ruler' */ +EXTERN char_u *p_ruf; /* 'rulerformat' */ +EXTERN char_u *p_rtp; /* 'runtimepath' */ +EXTERN long p_sj; /* 'scrolljump' */ +EXTERN long p_so; /* 'scrolloff' */ +EXTERN char_u *p_sbo; /* 'scrollopt' */ +EXTERN char_u *p_sections; /* 'sections' */ +EXTERN int p_secure; /* 'secure' */ +EXTERN char_u *p_sel; /* 'selection' */ +EXTERN char_u *p_slm; /* 'selectmode' */ +EXTERN char_u *p_ssop; /* 'sessionoptions' */ +EXTERN unsigned ssop_flags; +# ifdef IN_OPTION_C +/* Also used for 'viewoptions'! */ +static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize", + "localoptions", "options", "help", "blank", + "globals", "slash", "unix", + "sesdir", "curdir", "folds", "cursor", + "tabpages", NULL}; +# endif +# define SSOP_BUFFERS 0x001 +# define SSOP_WINPOS 0x002 +# define SSOP_RESIZE 0x004 +# define SSOP_WINSIZE 0x008 +# define SSOP_LOCALOPTIONS 0x010 +# define SSOP_OPTIONS 0x020 +# define SSOP_HELP 0x040 +# define SSOP_BLANK 0x080 +# define SSOP_GLOBALS 0x100 +# define SSOP_SLASH 0x200 +# define SSOP_UNIX 0x400 +# define SSOP_SESDIR 0x800 +# define SSOP_CURDIR 0x1000 +# define SSOP_FOLDS 0x2000 +# define SSOP_CURSOR 0x4000 +# define SSOP_TABPAGES 0x8000 +EXTERN char_u *p_sh; /* 'shell' */ +EXTERN char_u *p_shcf; /* 'shellcmdflag' */ +EXTERN char_u *p_sp; /* 'shellpipe' */ +EXTERN char_u *p_shq; /* 'shellquote' */ +EXTERN char_u *p_sxq; /* 'shellxquote' */ +EXTERN char_u *p_sxe; /* 'shellxescape' */ +EXTERN char_u *p_srr; /* 'shellredir' */ +EXTERN int p_stmp; /* 'shelltemp' */ +#ifdef BACKSLASH_IN_FILENAME +EXTERN int p_ssl; /* 'shellslash' */ +#endif +EXTERN char_u *p_stl; /* 'statusline' */ +EXTERN int p_sr; /* 'shiftround' */ +EXTERN char_u *p_shm; /* 'shortmess' */ +EXTERN char_u *p_sbr; /* 'showbreak' */ +EXTERN int p_sc; /* 'showcmd' */ +EXTERN int p_sft; /* 'showfulltag' */ +EXTERN int p_sm; /* 'showmatch' */ +EXTERN int p_smd; /* 'showmode' */ +EXTERN long p_ss; /* 'sidescroll' */ +EXTERN long p_siso; /* 'sidescrolloff' */ +EXTERN int p_scs; /* 'smartcase' */ +EXTERN int p_sta; /* 'smarttab' */ +EXTERN int p_sb; /* 'splitbelow' */ +EXTERN long p_tpm; /* 'tabpagemax' */ +EXTERN char_u *p_tal; /* 'tabline' */ +EXTERN char_u *p_sps; /* 'spellsuggest' */ +EXTERN int p_spr; /* 'splitright' */ +EXTERN int p_sol; /* 'startofline' */ +EXTERN char_u *p_su; /* 'suffixes' */ +EXTERN char_u *p_sws; /* 'swapsync' */ +EXTERN char_u *p_swb; /* 'switchbuf' */ +EXTERN unsigned swb_flags; +#ifdef IN_OPTION_C +static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", NULL}; +#endif +#define SWB_USEOPEN 0x001 +#define SWB_USETAB 0x002 +#define SWB_SPLIT 0x004 +#define SWB_NEWTAB 0x008 +EXTERN int p_tbs; /* 'tagbsearch' */ +EXTERN long p_tl; /* 'taglength' */ +EXTERN int p_tr; /* 'tagrelative' */ +EXTERN char_u *p_tags; /* 'tags' */ +EXTERN int p_tgst; /* 'tagstack' */ +EXTERN int p_tbidi; /* 'termbidi' */ +EXTERN char_u *p_tenc; /* 'termencoding' */ +EXTERN int p_terse; /* 'terse' */ +EXTERN int p_ta; /* 'textauto' */ +EXTERN int p_to; /* 'tildeop' */ +EXTERN int p_timeout; /* 'timeout' */ +EXTERN long p_tm; /* 'timeoutlen' */ +EXTERN int p_title; /* 'title' */ +EXTERN long p_titlelen; /* 'titlelen' */ +EXTERN char_u *p_titleold; /* 'titleold' */ +EXTERN char_u *p_titlestring; /* 'titlestring' */ +EXTERN char_u *p_tsr; /* 'thesaurus' */ +EXTERN int p_ttimeout; /* 'ttimeout' */ +EXTERN long p_ttm; /* 'ttimeoutlen' */ +EXTERN int p_tbi; /* 'ttybuiltin' */ +EXTERN int p_tf; /* 'ttyfast' */ +EXTERN long p_ttyscroll; /* 'ttyscroll' */ +#if defined(FEAT_MOUSE) && (defined(UNIX) || defined(VMS)) +EXTERN char_u *p_ttym; /* 'ttymouse' */ +EXTERN unsigned ttym_flags; +# ifdef IN_OPTION_C +static char *(p_ttym_values[]) = +{"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL}; +# endif +# define TTYM_XTERM 0x01 +# define TTYM_XTERM2 0x02 +# define TTYM_DEC 0x04 +# define TTYM_NETTERM 0x08 +# define TTYM_JSBTERM 0x10 +# define TTYM_PTERM 0x20 +# define TTYM_URXVT 0x40 +# define TTYM_SGR 0x80 +#endif +EXTERN char_u *p_udir; /* 'undodir' */ +EXTERN long p_ul; /* 'undolevels' */ +EXTERN long p_ur; /* 'undoreload' */ +EXTERN long p_uc; /* 'updatecount' */ +EXTERN long p_ut; /* 'updatetime' */ +EXTERN char_u *p_fcs; /* 'fillchar' */ +EXTERN char_u *p_viminfo; /* 'viminfo' */ +EXTERN char_u *p_vdir; /* 'viewdir' */ +EXTERN char_u *p_vop; /* 'viewoptions' */ +EXTERN unsigned vop_flags; /* uses SSOP_ flags */ +EXTERN int p_vb; /* 'visualbell' */ +EXTERN char_u *p_ve; /* 'virtualedit' */ +EXTERN unsigned ve_flags; +# ifdef IN_OPTION_C +static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", NULL}; +# endif +# define VE_BLOCK 5 /* includes "all" */ +# define VE_INSERT 6 /* includes "all" */ +# define VE_ALL 4 +# define VE_ONEMORE 8 +EXTERN long p_verbose; /* 'verbose' */ +#ifdef IN_OPTION_C +char_u *p_vfile = (char_u *)""; /* used before options are initialized */ +#else +extern char_u *p_vfile; /* 'verbosefile' */ +#endif +EXTERN int p_warn; /* 'warn' */ +EXTERN char_u *p_wop; /* 'wildoptions' */ +EXTERN long p_window; /* 'window' */ +#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(LINT) \ + || defined (FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) +#define FEAT_WAK +EXTERN char_u *p_wak; /* 'winaltkeys' */ +#endif +EXTERN char_u *p_wak; +EXTERN char_u *p_wig; /* 'wildignore' */ +EXTERN int p_wiv; /* 'weirdinvert' */ +EXTERN char_u *p_ww; /* 'whichwrap' */ +EXTERN long p_wc; /* 'wildchar' */ +EXTERN long p_wcm; /* 'wildcharm' */ +EXTERN long p_wic; /* 'wildignorecase' */ +EXTERN char_u *p_wim; /* 'wildmode' */ +EXTERN int p_wmnu; /* 'wildmenu' */ +EXTERN long p_wh; /* 'winheight' */ +EXTERN long p_wmh; /* 'winminheight' */ +EXTERN long p_wmw; /* 'winminwidth' */ +EXTERN long p_wiw; /* 'winwidth' */ +EXTERN int p_ws; /* 'wrapscan' */ +EXTERN int p_write; /* 'write' */ +EXTERN int p_wa; /* 'writeany' */ +EXTERN int p_wb; /* 'writebackup' */ +EXTERN long p_wd; /* 'writedelay' */ + +/* + * "indir" values for buffer-local opions. + * These need to be defined globally, so that the BV_COUNT can be used with + * b_p_scriptID[]. + */ +enum { + BV_AI = 0 + , BV_AR + , BV_BH + , BV_BT + , BV_EFM + , BV_GP + , BV_MP + , BV_BIN + , BV_BL + , BV_BOMB + , BV_CI + , BV_CIN + , BV_CINK + , BV_CINO + , BV_CINW + , BV_CM + , BV_CMS + , BV_COM + , BV_CPT + , BV_DICT + , BV_TSR + , BV_CFU + , BV_DEF + , BV_INC + , BV_EOL + , BV_EP + , BV_ET + , BV_FENC + , BV_BEXPR + , BV_FEX + , BV_FF + , BV_FLP + , BV_FO + , BV_FT + , BV_IMI + , BV_IMS + , BV_INDE + , BV_INDK + , BV_INEX + , BV_INF + , BV_ISK + , BV_KEY + , BV_KMAP + , BV_KP + , BV_LISP + , BV_MA + , BV_ML + , BV_MOD + , BV_MPS + , BV_NF + , BV_OFU + , BV_PATH + , BV_PI + , BV_QE + , BV_RO + , BV_SI +#ifndef SHORT_FNAME + , BV_SN +#endif + , BV_SMC + , BV_SYN + , BV_SPC + , BV_SPF + , BV_SPL + , BV_STS + , BV_SUA + , BV_SW + , BV_SWF + , BV_TAGS + , BV_TS + , BV_TW + , BV_TX + , BV_UDF + , BV_UL + , BV_WM + , BV_COUNT /* must be the last one */ +}; + +/* + * "indir" values for window-local options. + * These need to be defined globally, so that the WV_COUNT can be used in the + * window structure. + */ +enum { + WV_LIST = 0 + , WV_ARAB + , WV_COCU + , WV_COLE + , WV_CRBIND + , WV_DIFF + , WV_FDC + , WV_FEN + , WV_FDI + , WV_FDL + , WV_FDM + , WV_FML + , WV_FDN + , WV_FDE + , WV_FDT + , WV_FMR + , WV_LBR + , WV_NU + , WV_RNU + , WV_NUW + , WV_PVW + , WV_RL + , WV_RLC + , WV_SCBIND + , WV_SCROLL + , WV_SPELL + , WV_CUC + , WV_CUL + , WV_CC + , WV_STL + , WV_WFH + , WV_WFW + , WV_WRAP + , WV_COUNT /* must be the last one */ +}; + +/* Value for b_p_ul indicating the global value must be used. */ +#define NO_LOCAL_UNDOLEVEL -123456 diff --git a/src/os/fs.c b/src/os/fs.c index e9fe651b6b..3529ab4f46 100644 --- a/src/os/fs.c +++ b/src/os/fs.c @@ -14,6 +14,7 @@ #include #include "os.h" +#include "../message.h" int mch_chdir(char *path) { if (p_verbose >= 5) { diff --git a/src/os_unix.c b/src/os_unix.c index c3353d3724..856191ea95 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -28,9 +28,25 @@ # define select select_declared_wrong #include "vim.h" +#include "os_unix.h" +#include "buffer.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds.h" +#include "fileio.h" +#include "getchar.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "screen.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" #include "os/os.h" - #include "os_unixx.h" /* unix includes for os_unix.c only */ #ifdef HAVE_SELINUX diff --git a/src/os_unix.h b/src/os_unix.h index 3eb79e9a25..3a20c49252 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -1,351 +1,78 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * NextStep has a problem with configure, undefine a few things: - */ - -#include -#include - -# include -# include - -#ifdef HAVE_STDLIB_H -# include -#endif - - - -/* On AIX 4.2 there is a conflicting prototype for ioctl() in stropts.h and - * unistd.h. This hack should fix that (suggested by Jeff George). - * But on AIX 4.3 it's alright (suggested by Jake Hamby). */ - -#ifdef HAVE_UNISTD_H -# include -#endif - -#ifdef HAVE_LIBC_H -# include /* for NeXT */ -#endif - -#ifdef HAVE_SYS_PARAM_H -# include /* defines BSD, if it's a BSD system */ -#endif - -/* - * Sun defines FILE on SunOS 4.x.x, Solaris has a typedef for FILE - */ - -#ifndef __ARGS -/* The AIX VisualAge cc compiler defines __EXTENDED__ instead of __STDC__ - * because it includes pre-ansi features. */ -# if defined(__STDC__) || defined(__GNUC__) || defined(__EXTENDED__) -# define __ARGS(x) x -# else -# define __ARGS(x) () -# endif -#endif - -/* always use unlink() to remove files */ -# define vim_mkdir(x, y) mkdir((char *)(x), y) -# define mch_rmdir(x) rmdir((char *)(x)) -# define mch_remove(x) unlink((char *)(x)) - -/* The number of arguments to a signal handler is configured here. */ -/* It used to be a long list of almost all systems. Any system that doesn't - * have an argument??? */ -#define SIGHASARG - -/* List 3 arg systems here. I guess __sgi, please test and correct me. jw. */ - -#ifdef SIGHASARG -# ifdef SIGHAS3ARGS -# define SIGPROTOARG (int, int, struct sigcontext *) -# define SIGDEFARG(s) (s, sig2, scont) int s, sig2; struct sigcontext *scont; -# define SIGDUMMYARG 0, 0, (struct sigcontext *)0 -# else -# define SIGPROTOARG (int) -# define SIGDEFARG(s) (s) int s; -# define SIGDUMMYARG 0 -# endif -#else -# define SIGPROTOARG (void) -# define SIGDEFARG(s) () -# define SIGDUMMYARG -#endif - -#ifdef HAVE_DIRENT_H -# include -# ifndef NAMLEN -# define NAMLEN(dirent) strlen((dirent)->d_name) -# endif -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME) -# include /* on some systems time.h should not be - included together with sys/time.h */ -#endif -#ifdef HAVE_SYS_TIME_H -# include -#endif - -#include - -#if defined(DIRSIZ) && !defined(MAXNAMLEN) -# define MAXNAMLEN DIRSIZ -#endif - -#if defined(UFS_MAXNAMLEN) && !defined(MAXNAMLEN) -# define MAXNAMLEN UFS_MAXNAMLEN /* for dynix/ptx */ -#endif - -#if defined(NAME_MAX) && !defined(MAXNAMLEN) -# define MAXNAMLEN NAME_MAX /* for Linux before .99p3 */ -#endif - -/* - * Note: if MAXNAMLEN has the wrong value, you will get error messages - * for not being able to open the swap file. - */ -#if !defined(MAXNAMLEN) -# define MAXNAMLEN 512 /* for all other Unix */ -#endif - -#define BASENAMELEN (MAXNAMLEN - 5) - -#ifdef HAVE_PWD_H -# include -#endif - -#ifdef __COHERENT__ -# undef __ARGS -#endif - -/* - * Unix system-dependent file names - */ -#ifndef SYS_VIMRC_FILE -# define SYS_VIMRC_FILE "$VIM/vimrc" -#endif -#ifndef SYS_GVIMRC_FILE -# define SYS_GVIMRC_FILE "$VIM/gvimrc" -#endif -#ifndef DFLT_HELPFILE -# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt" -#endif -#ifndef FILETYPE_FILE -# define FILETYPE_FILE "filetype.vim" -#endif -#ifndef FTPLUGIN_FILE -# define FTPLUGIN_FILE "ftplugin.vim" -#endif -#ifndef INDENT_FILE -# define INDENT_FILE "indent.vim" -#endif -#ifndef FTOFF_FILE -# define FTOFF_FILE "ftoff.vim" -#endif -#ifndef FTPLUGOF_FILE -# define FTPLUGOF_FILE "ftplugof.vim" -#endif -#ifndef INDOFF_FILE -# define INDOFF_FILE "indoff.vim" -#endif -#ifndef SYS_MENU_FILE -# define SYS_MENU_FILE "$VIMRUNTIME/menu.vim" -#endif - -#ifndef USR_EXRC_FILE -# define USR_EXRC_FILE "$HOME/.exrc" -#endif - - -#ifndef USR_VIMRC_FILE -# define USR_VIMRC_FILE "$HOME/.neovimrc" -#endif - - -#if !defined(USR_EXRC_FILE2) -# define USR_VIMRC_FILE2 "~/.neovim/vimrc" -#endif - - -#ifndef USR_GVIMRC_FILE -# define USR_GVIMRC_FILE "$HOME/.neogvimrc" -#endif - -#ifndef USR_GVIMRC_FILE2 -# define USR_GVIMRC_FILE2 "~/.neovim/gvimrc" -#endif - - -#ifndef EVIM_FILE -# define EVIM_FILE "$VIMRUNTIME/evim.vim" -#endif - -# ifndef VIMINFO_FILE -# define VIMINFO_FILE "$HOME/.neoviminfo" -# endif - -#ifndef EXRC_FILE -# define EXRC_FILE ".exrc" -#endif - -#ifndef VIMRC_FILE -# define VIMRC_FILE ".neovimrc" -#endif - - -#ifndef SYNTAX_FNAME -# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim" -#endif - -#ifndef DFLT_BDIR -# define DFLT_BDIR ".,~/tmp,~/" /* default for 'backupdir' */ -#endif - -#ifndef DFLT_DIR -# define DFLT_DIR ".,~/tmp,/var/tmp,/tmp" /* default for 'directory' */ -#endif - -#ifndef DFLT_VDIR -# define DFLT_VDIR "$HOME/.neovim/view" /* default for 'viewdir' */ -#endif - -#define DFLT_ERRORFILE "errors.err" - -# ifdef RUNTIME_GLOBAL -# define DFLT_RUNTIMEPATH "~/.neovim," RUNTIME_GLOBAL ",$VIMRUNTIME," \ - RUNTIME_GLOBAL "/after,~/.neovim/after" -# else -# define DFLT_RUNTIMEPATH \ - "~/.neovim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.neovim/after" -# endif - -# define TEMPDIRNAMES "$TMPDIR", "/tmp", ".", "$HOME" -# define TEMPNAMELEN 256 - -/* Special wildcards that need to be handled by the shell */ -#define SPECIAL_WILDCHAR "`'{" - -#ifndef HAVE_OPENDIR -# define NO_EXPANDPATH -#endif - -/* - * Unix has plenty of memory, use large buffers - */ -#define CMDBUFFSIZE 1024 /* size of the command processing buffer */ - -/* Use the system path length if it makes sense. */ -#if defined(PATH_MAX) && (PATH_MAX > 1000) -# define MAXPATHL PATH_MAX -#else -# define MAXPATHL 1024 -#endif - -#define CHECK_INODE /* used when checking if a swap file already - exists for a file */ -# ifndef DFLT_MAXMEM -# define DFLT_MAXMEM (5*1024) /* use up to 5 Mbyte for a buffer */ -# endif -# ifndef DFLT_MAXMEMTOT -# define DFLT_MAXMEMTOT (10*1024) /* use up to 10 Mbyte for Vim */ -# endif - -/* memmove is not present on all systems, use memmove, bcopy, memcpy or our - * own version */ -/* Some systems have (void *) arguments, some (char *). If we use (char *) it - * works for all */ -#ifdef USEMEMMOVE -# define mch_memmove(to, from, len) memmove((char *)(to), (char *)(from), len) -#else -# ifdef USEBCOPY -# define mch_memmove(to, from, len) bcopy((char *)(from), (char *)(to), len) -# else -# ifdef USEMEMCPY -# define mch_memmove(to, from, len) memcpy((char *)(to), (char *)(from), len) -# else -# define VIM_MEMMOVE /* found in misc2.c */ -# endif -# endif -#endif - -# ifdef HAVE_RENAME -# define mch_rename(src, dst) rename(src, dst) -# else -int mch_rename __ARGS((const char *src, const char *dest)); -# endif -# ifdef __MVS__ -/* on OS390 Unix getenv() doesn't return a pointer to persistent - * storage -> use __getenv() */ -# define mch_getenv(x) (char_u *)__getenv((char *)(x)) -# else -# define mch_getenv(x) (char_u *)getenv((char *)(x)) -# endif -# define mch_setenv(name, val, x) setenv(name, val, x) - -#if !defined(S_ISDIR) && defined(S_IFDIR) -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#if !defined(S_ISREG) && defined(S_IFREG) -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#if !defined(S_ISBLK) && defined(S_IFBLK) -# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif -#if !defined(S_ISSOCK) && defined(S_IFSOCK) -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -#endif -#if !defined(S_ISFIFO) && defined(S_IFIFO) -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#endif -#if !defined(S_ISCHR) && defined(S_IFCHR) -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif - -/* Note: Some systems need both string.h and strings.h (Savage). However, - * some systems can't handle both, only use string.h in that case. */ -#ifdef HAVE_STRING_H -# include -#endif -#if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H) -# include -#endif - -#if defined(HAVE_SETJMP_H) -# include -# ifdef HAVE_SIGSETJMP -# define JMP_BUF sigjmp_buf -# define SETJMP(x) sigsetjmp((x), 1) -# define LONGJMP siglongjmp -# else -# define JMP_BUF jmp_buf -# define SETJMP(x) setjmp(x) -# define LONGJMP longjmp -# endif -#endif - -#define HAVE_DUP /* have dup() */ -#define HAVE_ST_MODE /* have stat.st_mode */ - -/* We have three kinds of ACL support. */ -#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL) +#ifndef NEOVIM_OS_UNIX_H +#define NEOVIM_OS_UNIX_H +/* os_unix.c */ +void mch_write __ARGS((char_u *s, int len)); +int mch_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); +int mch_char_avail __ARGS((void)); +void mch_delay __ARGS((long msec, int ignoreinput)); +int mch_stackcheck __ARGS((char *p)); +void mch_startjmp __ARGS((void)); +void mch_endjmp __ARGS((void)); +void mch_didjmp __ARGS((void)); +void mch_suspend __ARGS((void)); +void mch_init __ARGS((void)); +void reset_signals __ARGS((void)); +int vim_handle_signal __ARGS((int sig)); +int mch_check_win __ARGS((int argc, char **argv)); +int mch_input_isatty __ARGS((void)); +int mch_can_restore_title __ARGS((void)); +int mch_can_restore_icon __ARGS((void)); +void mch_settitle __ARGS((char_u *title, char_u *icon)); +void mch_restore_title __ARGS((int which)); +int vim_is_xterm __ARGS((char_u *name)); +int use_xterm_like_mouse __ARGS((char_u *name)); +int use_xterm_mouse __ARGS((void)); +int vim_is_iris __ARGS((char_u *name)); +int vim_is_vt300 __ARGS((char_u *name)); +int vim_is_fastterm __ARGS((char_u *name)); +int mch_get_user_name __ARGS((char_u *s, int len)); +int mch_get_uname __ARGS((uid_t uid, char_u *s, int len)); +void mch_get_host_name __ARGS((char_u *s, int len)); +long mch_get_pid __ARGS((void)); +void slash_adjust __ARGS((char_u *p)); +void fname_case __ARGS((char_u *name, int len)); +long mch_getperm __ARGS((char_u *name)); +int mch_setperm __ARGS((char_u *name, long perm)); +void mch_copy_sec __ARGS((char_u *from_file, char_u *to_file)); +vim_acl_T mch_get_acl __ARGS((char_u *fname)); +void mch_set_acl __ARGS((char_u *fname, vim_acl_T aclent)); +void mch_free_acl __ARGS((vim_acl_T aclent)); +void mch_hide __ARGS((char_u *name)); +int mch_isdir __ARGS((char_u *name)); +int mch_can_exe __ARGS((char_u *name)); +int mch_nodetype __ARGS((char_u *name)); +void mch_early_init __ARGS((void)); +void mch_free_mem __ARGS((void)); +void mch_exit __ARGS((int r)); +void mch_settmode __ARGS((int tmode)); +void get_stty __ARGS((void)); +void mch_setmouse __ARGS((int on)); +void check_mouse_termcode __ARGS((void)); +int mch_screenmode __ARGS((char_u *arg)); +int mch_get_shellsize __ARGS((void)); +void mch_set_shellsize __ARGS((void)); +void mch_new_shellsize __ARGS((void)); +int mch_call_shell __ARGS((char_u *cmd, int options)); +void mch_breakcheck __ARGS((void)); +int mch_expandpath __ARGS((garray_T *gap, char_u *path, int flags)); +int mch_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, + char_u ***file, + int flags)); +int mch_has_exp_wildcard __ARGS((char_u *p)); +int mch_has_wildcard __ARGS((char_u *p)); +int mch_libcall __ARGS((char_u *libname, char_u *funcname, char_u *argstring, + int argint, char_u **string_result, + int *number_result)); +void setup_term_clip __ARGS((void)); +void start_xterm_trace __ARGS((int button)); +void stop_xterm_trace __ARGS((void)); +void clear_xterm_clip __ARGS((void)); +int clip_xterm_own_selection __ARGS((VimClipboard *cbd)); +void clip_xterm_lose_selection __ARGS((VimClipboard *cbd)); +void clip_xterm_request_selection __ARGS((VimClipboard *cbd)); +void clip_xterm_set_selection __ARGS((VimClipboard *cbd)); +int xsmp_handle_requests __ARGS((void)); +void xsmp_init __ARGS((void)); +void xsmp_close __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_OS_UNIX_H */ diff --git a/src/os_unix_defs.h b/src/os_unix_defs.h new file mode 100644 index 0000000000..3eb79e9a25 --- /dev/null +++ b/src/os_unix_defs.h @@ -0,0 +1,351 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * NextStep has a problem with configure, undefine a few things: + */ + +#include +#include + +# include +# include + +#ifdef HAVE_STDLIB_H +# include +#endif + + + +/* On AIX 4.2 there is a conflicting prototype for ioctl() in stropts.h and + * unistd.h. This hack should fix that (suggested by Jeff George). + * But on AIX 4.3 it's alright (suggested by Jake Hamby). */ + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_LIBC_H +# include /* for NeXT */ +#endif + +#ifdef HAVE_SYS_PARAM_H +# include /* defines BSD, if it's a BSD system */ +#endif + +/* + * Sun defines FILE on SunOS 4.x.x, Solaris has a typedef for FILE + */ + +#ifndef __ARGS +/* The AIX VisualAge cc compiler defines __EXTENDED__ instead of __STDC__ + * because it includes pre-ansi features. */ +# if defined(__STDC__) || defined(__GNUC__) || defined(__EXTENDED__) +# define __ARGS(x) x +# else +# define __ARGS(x) () +# endif +#endif + +/* always use unlink() to remove files */ +# define vim_mkdir(x, y) mkdir((char *)(x), y) +# define mch_rmdir(x) rmdir((char *)(x)) +# define mch_remove(x) unlink((char *)(x)) + +/* The number of arguments to a signal handler is configured here. */ +/* It used to be a long list of almost all systems. Any system that doesn't + * have an argument??? */ +#define SIGHASARG + +/* List 3 arg systems here. I guess __sgi, please test and correct me. jw. */ + +#ifdef SIGHASARG +# ifdef SIGHAS3ARGS +# define SIGPROTOARG (int, int, struct sigcontext *) +# define SIGDEFARG(s) (s, sig2, scont) int s, sig2; struct sigcontext *scont; +# define SIGDUMMYARG 0, 0, (struct sigcontext *)0 +# else +# define SIGPROTOARG (int) +# define SIGDEFARG(s) (s) int s; +# define SIGDUMMYARG 0 +# endif +#else +# define SIGPROTOARG (void) +# define SIGDEFARG(s) () +# define SIGDUMMYARG +#endif + +#ifdef HAVE_DIRENT_H +# include +# ifndef NAMLEN +# define NAMLEN(dirent) strlen((dirent)->d_name) +# endif +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME) +# include /* on some systems time.h should not be + included together with sys/time.h */ +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include + +#if defined(DIRSIZ) && !defined(MAXNAMLEN) +# define MAXNAMLEN DIRSIZ +#endif + +#if defined(UFS_MAXNAMLEN) && !defined(MAXNAMLEN) +# define MAXNAMLEN UFS_MAXNAMLEN /* for dynix/ptx */ +#endif + +#if defined(NAME_MAX) && !defined(MAXNAMLEN) +# define MAXNAMLEN NAME_MAX /* for Linux before .99p3 */ +#endif + +/* + * Note: if MAXNAMLEN has the wrong value, you will get error messages + * for not being able to open the swap file. + */ +#if !defined(MAXNAMLEN) +# define MAXNAMLEN 512 /* for all other Unix */ +#endif + +#define BASENAMELEN (MAXNAMLEN - 5) + +#ifdef HAVE_PWD_H +# include +#endif + +#ifdef __COHERENT__ +# undef __ARGS +#endif + +/* + * Unix system-dependent file names + */ +#ifndef SYS_VIMRC_FILE +# define SYS_VIMRC_FILE "$VIM/vimrc" +#endif +#ifndef SYS_GVIMRC_FILE +# define SYS_GVIMRC_FILE "$VIM/gvimrc" +#endif +#ifndef DFLT_HELPFILE +# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt" +#endif +#ifndef FILETYPE_FILE +# define FILETYPE_FILE "filetype.vim" +#endif +#ifndef FTPLUGIN_FILE +# define FTPLUGIN_FILE "ftplugin.vim" +#endif +#ifndef INDENT_FILE +# define INDENT_FILE "indent.vim" +#endif +#ifndef FTOFF_FILE +# define FTOFF_FILE "ftoff.vim" +#endif +#ifndef FTPLUGOF_FILE +# define FTPLUGOF_FILE "ftplugof.vim" +#endif +#ifndef INDOFF_FILE +# define INDOFF_FILE "indoff.vim" +#endif +#ifndef SYS_MENU_FILE +# define SYS_MENU_FILE "$VIMRUNTIME/menu.vim" +#endif + +#ifndef USR_EXRC_FILE +# define USR_EXRC_FILE "$HOME/.exrc" +#endif + + +#ifndef USR_VIMRC_FILE +# define USR_VIMRC_FILE "$HOME/.neovimrc" +#endif + + +#if !defined(USR_EXRC_FILE2) +# define USR_VIMRC_FILE2 "~/.neovim/vimrc" +#endif + + +#ifndef USR_GVIMRC_FILE +# define USR_GVIMRC_FILE "$HOME/.neogvimrc" +#endif + +#ifndef USR_GVIMRC_FILE2 +# define USR_GVIMRC_FILE2 "~/.neovim/gvimrc" +#endif + + +#ifndef EVIM_FILE +# define EVIM_FILE "$VIMRUNTIME/evim.vim" +#endif + +# ifndef VIMINFO_FILE +# define VIMINFO_FILE "$HOME/.neoviminfo" +# endif + +#ifndef EXRC_FILE +# define EXRC_FILE ".exrc" +#endif + +#ifndef VIMRC_FILE +# define VIMRC_FILE ".neovimrc" +#endif + + +#ifndef SYNTAX_FNAME +# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim" +#endif + +#ifndef DFLT_BDIR +# define DFLT_BDIR ".,~/tmp,~/" /* default for 'backupdir' */ +#endif + +#ifndef DFLT_DIR +# define DFLT_DIR ".,~/tmp,/var/tmp,/tmp" /* default for 'directory' */ +#endif + +#ifndef DFLT_VDIR +# define DFLT_VDIR "$HOME/.neovim/view" /* default for 'viewdir' */ +#endif + +#define DFLT_ERRORFILE "errors.err" + +# ifdef RUNTIME_GLOBAL +# define DFLT_RUNTIMEPATH "~/.neovim," RUNTIME_GLOBAL ",$VIMRUNTIME," \ + RUNTIME_GLOBAL "/after,~/.neovim/after" +# else +# define DFLT_RUNTIMEPATH \ + "~/.neovim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.neovim/after" +# endif + +# define TEMPDIRNAMES "$TMPDIR", "/tmp", ".", "$HOME" +# define TEMPNAMELEN 256 + +/* Special wildcards that need to be handled by the shell */ +#define SPECIAL_WILDCHAR "`'{" + +#ifndef HAVE_OPENDIR +# define NO_EXPANDPATH +#endif + +/* + * Unix has plenty of memory, use large buffers + */ +#define CMDBUFFSIZE 1024 /* size of the command processing buffer */ + +/* Use the system path length if it makes sense. */ +#if defined(PATH_MAX) && (PATH_MAX > 1000) +# define MAXPATHL PATH_MAX +#else +# define MAXPATHL 1024 +#endif + +#define CHECK_INODE /* used when checking if a swap file already + exists for a file */ +# ifndef DFLT_MAXMEM +# define DFLT_MAXMEM (5*1024) /* use up to 5 Mbyte for a buffer */ +# endif +# ifndef DFLT_MAXMEMTOT +# define DFLT_MAXMEMTOT (10*1024) /* use up to 10 Mbyte for Vim */ +# endif + +/* memmove is not present on all systems, use memmove, bcopy, memcpy or our + * own version */ +/* Some systems have (void *) arguments, some (char *). If we use (char *) it + * works for all */ +#ifdef USEMEMMOVE +# define mch_memmove(to, from, len) memmove((char *)(to), (char *)(from), len) +#else +# ifdef USEBCOPY +# define mch_memmove(to, from, len) bcopy((char *)(from), (char *)(to), len) +# else +# ifdef USEMEMCPY +# define mch_memmove(to, from, len) memcpy((char *)(to), (char *)(from), len) +# else +# define VIM_MEMMOVE /* found in misc2.c */ +# endif +# endif +#endif + +# ifdef HAVE_RENAME +# define mch_rename(src, dst) rename(src, dst) +# else +int mch_rename __ARGS((const char *src, const char *dest)); +# endif +# ifdef __MVS__ +/* on OS390 Unix getenv() doesn't return a pointer to persistent + * storage -> use __getenv() */ +# define mch_getenv(x) (char_u *)__getenv((char *)(x)) +# else +# define mch_getenv(x) (char_u *)getenv((char *)(x)) +# endif +# define mch_setenv(name, val, x) setenv(name, val, x) + +#if !defined(S_ISDIR) && defined(S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISBLK) && defined(S_IFBLK) +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif + +/* Note: Some systems need both string.h and strings.h (Savage). However, + * some systems can't handle both, only use string.h in that case. */ +#ifdef HAVE_STRING_H +# include +#endif +#if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H) +# include +#endif + +#if defined(HAVE_SETJMP_H) +# include +# ifdef HAVE_SIGSETJMP +# define JMP_BUF sigjmp_buf +# define SETJMP(x) sigsetjmp((x), 1) +# define LONGJMP siglongjmp +# else +# define JMP_BUF jmp_buf +# define SETJMP(x) setjmp(x) +# define LONGJMP longjmp +# endif +#endif + +#define HAVE_DUP /* have dup() */ +#define HAVE_ST_MODE /* have stat.st_mode */ + +/* We have three kinds of ACL support. */ +#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL || HAVE_AIX_ACL) diff --git a/src/popupmnu.c b/src/popupmnu.c index be8c3ec0e0..293e1f0bb2 100644 --- a/src/popupmnu.c +++ b/src/popupmnu.c @@ -11,7 +11,16 @@ * popupmnu.c: Popup menu (PUM) */ #include "vim.h" - +#include "popupmnu.h" +#include "charset.h" +#include "ex_cmds.h" +#include "memline.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "screen.h" +#include "search.h" +#include "window.h" static pumitem_T *pum_array = NULL; /* items of displayed pum */ static int pum_size; /* nr of items in "pum_array" */ diff --git a/src/popupmnu.h b/src/popupmnu.h new file mode 100644 index 0000000000..8a619fdb36 --- /dev/null +++ b/src/popupmnu.h @@ -0,0 +1,11 @@ +#ifndef NEOVIM_POPUPMNU_H +#define NEOVIM_POPUPMNU_H +/* popupmnu.c */ +void pum_display __ARGS((pumitem_T *array, int size, int selected)); +void pum_redraw __ARGS((void)); +void pum_undisplay __ARGS((void)); +void pum_clear __ARGS((void)); +int pum_visible __ARGS((void)); +int pum_get_height __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_POPUPMNU_H */ diff --git a/src/proto.h b/src/proto.h index b040ff70cc..5037dfa26f 100644 --- a/src/proto.h +++ b/src/proto.h @@ -26,35 +26,6 @@ # define GdkEventKey int # define XImage int -# if defined(UNIX) || defined(__EMX__) || defined(VMS) -# include "os_unix.pro" -# endif - -# include "blowfish.pro" -# include "buffer.pro" -# include "charset.pro" -# include "if_cscope.pro" -# include "diff.pro" -# include "digraph.pro" -# include "edit.pro" -# include "eval.pro" -# include "ex_cmds.pro" -# include "ex_cmds2.pro" -# include "ex_docmd.pro" -# include "ex_eval.pro" -# include "ex_getln.pro" -# include "fileio.pro" -# include "fold.pro" -# include "getchar.pro" -# include "hangulin.pro" -# include "hardcopy.pro" -# include "hashtab.pro" -# include "main.pro" -# include "mark.pro" -# include "memfile.pro" -# include "memline.pro" -# include "menu.pro" - # if !defined MESSAGE_FILE || defined(HAVE_STDARG_H) /* These prototypes cannot be produced automatically and conflict with * the old-style prototypes in message.c. */ @@ -75,9 +46,6 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs) # endif # endif -# include "message.pro" -# include "misc1.pro" -# include "misc2.pro" #ifndef HAVE_STRPBRK /* not generated automatically from misc2.c */ char_u *vim_strpbrk __ARGS((char_u *s, char_u *charset)); #endif @@ -86,52 +54,9 @@ char_u *vim_strpbrk __ARGS((char_u *s, char_u *charset)); void qsort __ARGS((void *base, size_t elm_count, size_t elm_size, int (*cmp)( const void *, const void *))); #endif -# include "move.pro" -# if defined(FEAT_MBYTE) || defined(FEAT_XIM) || defined(FEAT_KEYMAP) \ - || defined(FEAT_POSTSCRIPT) -# include "mbyte.pro" -# endif -# include "normal.pro" -# include "ops.pro" -# include "option.pro" -# include "popupmnu.pro" -# include "quickfix.pro" -# include "regexp.pro" -# include "screen.pro" -# include "sha256.pro" -# include "search.pro" -# include "spell.pro" -# include "syntax.pro" -# include "tag.pro" -# include "term.pro" -# include "ui.pro" -# include "undo.pro" -# include "version.pro" -# include "window.pro" - - - - - - /* Ugly solution for "BalloonEval" not being defined while it's used in some * .pro files. */ # define BalloonEval int - - -# ifdef FEAT_OLE -# endif - -/* - * The perl include files pollute the namespace, therefore proto.h must be - * included before the perl include files. But then CV is not defined, which - * not included here for the perl files. Use a dummy define for CV for the - * other files. - */ - -#ifdef MACOS_CONVERT -#endif - #endif /* !PROTO && !NOPROTO */ diff --git a/src/proto/blowfish.pro b/src/proto/blowfish.pro deleted file mode 100644 index 51e4fa9ec5..0000000000 --- a/src/proto/blowfish.pro +++ /dev/null @@ -1,10 +0,0 @@ -/* blowfish.c */ -void bf_key_init __ARGS((char_u *password, char_u *salt, int salt_len)); -void bf_ofb_init __ARGS((char_u *iv, int iv_len)); -void bf_crypt_encode __ARGS((char_u *from, size_t len, char_u *to)); -void bf_crypt_decode __ARGS((char_u *ptr, long len)); -void bf_crypt_init_keys __ARGS((char_u *passwd)); -void bf_crypt_save __ARGS((void)); -void bf_crypt_restore __ARGS((void)); -int blowfish_self_test __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro deleted file mode 100644 index 060008db77..0000000000 --- a/src/proto/buffer.pro +++ /dev/null @@ -1,81 +0,0 @@ -/* buffer.c */ -int open_buffer __ARGS((int read_stdin, exarg_T *eap, int flags)); -int buf_valid __ARGS((buf_T *buf)); -void close_buffer __ARGS((win_T *win, buf_T *buf, int action, int abort_if_last)); -void buf_clear_file __ARGS((buf_T *buf)); -void buf_freeall __ARGS((buf_T *buf, int flags)); -void goto_buffer __ARGS((exarg_T *eap, int start, int dir, int count)); -void handle_swap_exists __ARGS((buf_T *old_curbuf)); -char_u *do_bufdel __ARGS((int command, char_u *arg, int addr_count, - int start_bnr, int end_bnr, - int forceit)); -int do_buffer __ARGS((int action, int start, int dir, int count, int forceit)); -void set_curbuf __ARGS((buf_T *buf, int action)); -void enter_buffer __ARGS((buf_T *buf)); -void do_autochdir __ARGS((void)); -buf_T *buflist_new __ARGS((char_u *ffname, char_u *sfname, linenr_T lnum, - int flags)); -void free_buf_options __ARGS((buf_T *buf, int free_p_ff)); -int buflist_getfile __ARGS((int n, linenr_T lnum, int options, int forceit)); -void buflist_getfpos __ARGS((void)); -buf_T *buflist_findname_exp __ARGS((char_u *fname)); -buf_T *buflist_findname __ARGS((char_u *ffname)); -int buflist_findpat __ARGS((char_u *pattern, char_u *pattern_end, int unlisted, - int diffmode, - int curtab_only)); -int ExpandBufnames __ARGS((char_u *pat, int *num_file, char_u ***file, - int options)); -buf_T *buflist_findnr __ARGS((int nr)); -char_u *buflist_nr2name __ARGS((int n, int fullname, int helptail)); -void get_winopts __ARGS((buf_T *buf)); -pos_T *buflist_findfpos __ARGS((buf_T *buf)); -linenr_T buflist_findlnum __ARGS((buf_T *buf)); -void buflist_list __ARGS((exarg_T *eap)); -int buflist_name_nr __ARGS((int fnum, char_u **fname, linenr_T *lnum)); -int setfname __ARGS((buf_T *buf, char_u *ffname, char_u *sfname, int message)); -void buf_set_name __ARGS((int fnum, char_u *name)); -void buf_name_changed __ARGS((buf_T *buf)); -buf_T *setaltfname __ARGS((char_u *ffname, char_u *sfname, linenr_T lnum)); -char_u *getaltfname __ARGS((int errmsg)); -int buflist_add __ARGS((char_u *fname, int flags)); -void buflist_slash_adjust __ARGS((void)); -void buflist_altfpos __ARGS((win_T *win)); -int otherfile __ARGS((char_u *ffname)); -void buf_setino __ARGS((buf_T *buf)); -void fileinfo __ARGS((int fullname, int shorthelp, int dont_truncate)); -void col_print __ARGS((char_u *buf, size_t buflen, int col, int vcol)); -void maketitle __ARGS((void)); -void resettitle __ARGS((void)); -void free_titles __ARGS((void)); -int build_stl_str_hl __ARGS((win_T *wp, char_u *out, size_t outlen, char_u *fmt, - int use_sandbox, int fillchar, int maxwidth, - struct stl_hlrec *hltab, - struct stl_hlrec *tabtab)); -void get_rel_pos __ARGS((win_T *wp, char_u *buf, int buflen)); -char_u *fix_fname __ARGS((char_u *fname)); -void fname_expand __ARGS((buf_T *buf, char_u **ffname, char_u **sfname)); -char_u *alist_name __ARGS((aentry_T *aep)); -void do_arg_all __ARGS((int count, int forceit, int keep_tabs)); -void ex_buffer_all __ARGS((exarg_T *eap)); -void do_modelines __ARGS((int flags)); -int read_viminfo_bufferlist __ARGS((vir_T *virp, int writing)); -void write_viminfo_bufferlist __ARGS((FILE *fp)); -char_u *buf_spname __ARGS((buf_T *buf)); -int find_win_for_buf __ARGS((buf_T *buf, win_T **wp, tabpage_T **tp)); -void buf_addsign __ARGS((buf_T *buf, int id, linenr_T lnum, int typenr)); -linenr_T buf_change_sign_type __ARGS((buf_T *buf, int markId, int typenr)); -int buf_getsigntype __ARGS((buf_T *buf, linenr_T lnum, int type)); -linenr_T buf_delsign __ARGS((buf_T *buf, int id)); -int buf_findsign __ARGS((buf_T *buf, int id)); -int buf_findsign_id __ARGS((buf_T *buf, linenr_T lnum)); -int buf_findsigntype_id __ARGS((buf_T *buf, linenr_T lnum, int typenr)); -int buf_signcount __ARGS((buf_T *buf, linenr_T lnum)); -void buf_delete_signs __ARGS((buf_T *buf)); -void buf_delete_all_signs __ARGS((void)); -void sign_list_placed __ARGS((buf_T *rbuf)); -void sign_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, - long amount_after)); -void set_buflisted __ARGS((int on)); -int buf_contents_changed __ARGS((buf_T *buf)); -void wipe_buffer __ARGS((buf_T *buf, int aucmd)); -/* vim: set ft=c : */ diff --git a/src/proto/charset.pro b/src/proto/charset.pro deleted file mode 100644 index d0223f1e9c..0000000000 --- a/src/proto/charset.pro +++ /dev/null @@ -1,64 +0,0 @@ -/* charset.c */ -int init_chartab __ARGS((void)); -int buf_init_chartab __ARGS((buf_T *buf, int global)); -void trans_characters __ARGS((char_u *buf, int bufsize)); -char_u *transstr __ARGS((char_u *s)); -char_u *str_foldcase __ARGS((char_u *str, int orglen, char_u *buf, int buflen)); -char_u *transchar __ARGS((int c)); -char_u *transchar_byte __ARGS((int c)); -void transchar_nonprint __ARGS((char_u *buf, int c)); -void transchar_hex __ARGS((char_u *buf, int c)); -int byte2cells __ARGS((int b)); -int char2cells __ARGS((int c)); -int ptr2cells __ARGS((char_u *p)); -int vim_strsize __ARGS((char_u *s)); -int vim_strnsize __ARGS((char_u *s, int len)); -int chartabsize __ARGS((char_u *p, colnr_T col)); -int linetabsize __ARGS((char_u *s)); -int linetabsize_col __ARGS((int startcol, char_u *s)); -int win_linetabsize __ARGS((win_T *wp, char_u *p, colnr_T len)); -int vim_isIDc __ARGS((int c)); -int vim_iswordc __ARGS((int c)); -int vim_iswordc_buf __ARGS((int c, buf_T *buf)); -int vim_iswordp __ARGS((char_u *p)); -int vim_iswordp_buf __ARGS((char_u *p, buf_T *buf)); -int vim_isfilec __ARGS((int c)); -int vim_isfilec_or_wc __ARGS((int c)); -int vim_isprintc __ARGS((int c)); -int vim_isprintc_strict __ARGS((int c)); -int lbr_chartabsize __ARGS((unsigned char *s, colnr_T col)); -int lbr_chartabsize_adv __ARGS((char_u **s, colnr_T col)); -int win_lbr_chartabsize __ARGS((win_T *wp, char_u *s, colnr_T col, int *headp)); -int in_win_border __ARGS((win_T *wp, colnr_T vcol)); -void getvcol __ARGS((win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, - colnr_T *end)); -colnr_T getvcol_nolist __ARGS((pos_T *posp)); -void getvvcol __ARGS((win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, - colnr_T *end)); -void getvcols __ARGS((win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, - colnr_T *right)); -char_u *skipwhite __ARGS((char_u *q)); -char_u *skipdigits __ARGS((char_u *q)); -char_u *skiphex __ARGS((char_u *q)); -char_u *skiptodigit __ARGS((char_u *q)); -char_u *skiptohex __ARGS((char_u *q)); -int vim_isdigit __ARGS((int c)); -int vim_isxdigit __ARGS((int c)); -int vim_islower __ARGS((int c)); -int vim_isupper __ARGS((int c)); -int vim_toupper __ARGS((int c)); -int vim_tolower __ARGS((int c)); -char_u *skiptowhite __ARGS((char_u *p)); -char_u *skiptowhite_esc __ARGS((char_u *p)); -long getdigits __ARGS((char_u **pp)); -int vim_isblankline __ARGS((char_u *lbuf)); -void vim_str2nr __ARGS((char_u *start, int *hexp, int *len, int dooct, - int dohex, long *nptr, - unsigned long *unptr)); -int hex2nr __ARGS((int c)); -int hexhex2nr __ARGS((char_u *p)); -int rem_backslash __ARGS((char_u *str)); -void backslash_halve __ARGS((char_u *p)); -char_u *backslash_halve_save __ARGS((char_u *p)); -void ebcdic2ascii __ARGS((char_u *buffer, int len)); -/* vim: set ft=c : */ diff --git a/src/proto/diff.pro b/src/proto/diff.pro deleted file mode 100644 index 0093629033..0000000000 --- a/src/proto/diff.pro +++ /dev/null @@ -1,30 +0,0 @@ -/* diff.c */ -void diff_buf_delete __ARGS((buf_T *buf)); -void diff_buf_adjust __ARGS((win_T *win)); -void diff_buf_add __ARGS((buf_T *buf)); -void diff_invalidate __ARGS((buf_T *buf)); -void diff_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, - long amount_after)); -void ex_diffupdate __ARGS((exarg_T *eap)); -void ex_diffpatch __ARGS((exarg_T *eap)); -void ex_diffsplit __ARGS((exarg_T *eap)); -void ex_diffthis __ARGS((exarg_T *eap)); -void diff_win_options __ARGS((win_T *wp, int addbuf)); -void ex_diffoff __ARGS((exarg_T *eap)); -void diff_clear __ARGS((tabpage_T *tp)); -int diff_check __ARGS((win_T *wp, linenr_T lnum)); -int diff_check_fill __ARGS((win_T *wp, linenr_T lnum)); -void diff_set_topline __ARGS((win_T *fromwin, win_T *towin)); -int diffopt_changed __ARGS((void)); -int diffopt_horizontal __ARGS((void)); -int diff_find_change __ARGS((win_T *wp, linenr_T lnum, int *startp, int *endp)); -int diff_infold __ARGS((win_T *wp, linenr_T lnum)); -void nv_diffgetput __ARGS((int put)); -void ex_diffgetput __ARGS((exarg_T *eap)); -int diff_mode_buf __ARGS((buf_T *buf)); -int diff_move_to __ARGS((int dir, long count)); -linenr_T diff_get_corresponding_line __ARGS((buf_T *buf1, linenr_T lnum1, - buf_T *buf2, - linenr_T lnum3)); -linenr_T diff_lnum_win __ARGS((linenr_T lnum, win_T *wp)); -/* vim: set ft=c : */ diff --git a/src/proto/digraph.pro b/src/proto/digraph.pro deleted file mode 100644 index 5573b8c36d..0000000000 --- a/src/proto/digraph.pro +++ /dev/null @@ -1,9 +0,0 @@ -/* digraph.c */ -int do_digraph __ARGS((int c)); -int get_digraph __ARGS((int cmdline)); -int getdigraph __ARGS((int char1, int char2, int meta_char)); -void putdigraph __ARGS((char_u *str)); -void listdigraphs __ARGS((void)); -char_u *keymap_init __ARGS((void)); -void ex_loadkeymap __ARGS((exarg_T *eap)); -/* vim: set ft=c : */ diff --git a/src/proto/edit.pro b/src/proto/edit.pro deleted file mode 100644 index 0284101df4..0000000000 --- a/src/proto/edit.pro +++ /dev/null @@ -1,46 +0,0 @@ -/* edit.c */ -int edit __ARGS((int cmdchar, int startln, long count)); -void edit_putchar __ARGS((int c, int highlight)); -void edit_unputchar __ARGS((void)); -void display_dollar __ARGS((colnr_T col)); -void change_indent __ARGS((int type, int amount, int round, int replaced, - int call_changed_bytes)); -void truncate_spaces __ARGS((char_u *line)); -void backspace_until_column __ARGS((int col)); -int vim_is_ctrl_x_key __ARGS((int c)); -int ins_compl_add_infercase __ARGS((char_u *str, int len, int icase, char_u * - fname, int dir, - int flags)); -void set_completion __ARGS((colnr_T startcol, list_T *list)); -void ins_compl_show_pum __ARGS((void)); -char_u *find_word_start __ARGS((char_u *ptr)); -char_u *find_word_end __ARGS((char_u *ptr)); -int ins_compl_active __ARGS((void)); -int ins_compl_add_tv __ARGS((typval_T *tv, int dir)); -void ins_compl_check_keys __ARGS((int frequency)); -int get_literal __ARGS((void)); -void insertchar __ARGS((int c, int flags, int second_indent)); -void auto_format __ARGS((int trailblank, int prev_line)); -int comp_textwidth __ARGS((int ff)); -int stop_arrow __ARGS((void)); -void set_last_insert __ARGS((int c)); -void free_last_insert __ARGS((void)); -char_u *add_char2buf __ARGS((int c, char_u *s)); -void beginline __ARGS((int flags)); -int oneright __ARGS((void)); -int oneleft __ARGS((void)); -int cursor_up __ARGS((long n, int upd_topline)); -int cursor_down __ARGS((long n, int upd_topline)); -int stuff_inserted __ARGS((int c, long count, int no_esc)); -char_u *get_last_insert __ARGS((void)); -char_u *get_last_insert_save __ARGS((void)); -void replace_push __ARGS((int c)); -int replace_push_mb __ARGS((char_u *p)); -void fixthisline __ARGS((int (*get_the_indent)(void))); -void fix_indent __ARGS((void)); -int in_cinkeys __ARGS((int keytyped, int when, int line_is_empty)); -int hkmap __ARGS((int c)); -void ins_scroll __ARGS((void)); -void ins_horscroll __ARGS((void)); -int ins_copychar __ARGS((linenr_T lnum)); -/* vim: set ft=c : */ diff --git a/src/proto/eval.pro b/src/proto/eval.pro deleted file mode 100644 index c0f707cab2..0000000000 --- a/src/proto/eval.pro +++ /dev/null @@ -1,150 +0,0 @@ -/* eval.c */ -void eval_init __ARGS((void)); -void eval_clear __ARGS((void)); -char_u *func_name __ARGS((void *cookie)); -linenr_T *func_breakpoint __ARGS((void *cookie)); -int *func_dbg_tick __ARGS((void *cookie)); -int func_level __ARGS((void *cookie)); -int current_func_returned __ARGS((void)); -void set_internal_string_var __ARGS((char_u *name, char_u *value)); -int var_redir_start __ARGS((char_u *name, int append)); -void var_redir_str __ARGS((char_u *value, int value_len)); -void var_redir_stop __ARGS((void)); -int eval_charconvert __ARGS((char_u *enc_from, char_u *enc_to, char_u * - fname_from, - char_u *fname_to)); -int eval_printexpr __ARGS((char_u *fname, char_u *args)); -void eval_diff __ARGS((char_u *origfile, char_u *newfile, char_u *outfile)); -void eval_patch __ARGS((char_u *origfile, char_u *difffile, char_u *outfile)); -int eval_to_bool __ARGS((char_u *arg, int *error, char_u **nextcmd, int skip)); -char_u *eval_to_string_skip __ARGS((char_u *arg, char_u **nextcmd, int skip)); -int skip_expr __ARGS((char_u **pp)); -char_u *eval_to_string __ARGS((char_u *arg, char_u **nextcmd, int convert)); -char_u *eval_to_string_safe __ARGS((char_u *arg, char_u **nextcmd, - int use_sandbox)); -int eval_to_number __ARGS((char_u *expr)); -list_T *eval_spell_expr __ARGS((char_u *badword, char_u *expr)); -int get_spellword __ARGS((list_T *list, char_u **pp)); -typval_T *eval_expr __ARGS((char_u *arg, char_u **nextcmd)); -int call_vim_function __ARGS((char_u *func, int argc, char_u **argv, int safe, - int str_arg_only, - typval_T *rettv)); -long call_func_retnr __ARGS((char_u *func, int argc, char_u **argv, int safe)); -void *call_func_retstr __ARGS((char_u *func, int argc, char_u **argv, int safe)); -void *call_func_retlist __ARGS((char_u *func, int argc, char_u **argv, int safe)); -void *save_funccal __ARGS((void)); -void restore_funccal __ARGS((void *vfc)); -void prof_child_enter __ARGS((proftime_T *tm)); -void prof_child_exit __ARGS((proftime_T *tm)); -int eval_foldexpr __ARGS((char_u *arg, int *cp)); -void ex_let __ARGS((exarg_T *eap)); -void list_add_watch __ARGS((list_T *l, listwatch_T *lw)); -void list_rem_watch __ARGS((list_T *l, listwatch_T *lwrem)); -void *eval_for_line __ARGS((char_u *arg, int *errp, char_u **nextcmdp, int skip)); -int next_for_item __ARGS((void *fi_void, char_u *arg)); -void free_for_info __ARGS((void *fi_void)); -void set_context_for_expression __ARGS((expand_T *xp, char_u *arg, - cmdidx_T cmdidx)); -void ex_call __ARGS((exarg_T *eap)); -void ex_unlet __ARGS((exarg_T *eap)); -void ex_lockvar __ARGS((exarg_T *eap)); -int do_unlet __ARGS((char_u *name, int forceit)); -void del_menutrans_vars __ARGS((void)); -char_u *get_user_var_name __ARGS((expand_T *xp, int idx)); -list_T *list_alloc __ARGS((void)); -void list_unref __ARGS((list_T *l)); -void list_free __ARGS((list_T *l, int recurse)); -listitem_T *listitem_alloc __ARGS((void)); -void listitem_free __ARGS((listitem_T *item)); -void listitem_remove __ARGS((list_T *l, listitem_T *item)); -dictitem_T *dict_lookup __ARGS((hashitem_T *hi)); -listitem_T *list_find __ARGS((list_T *l, long n)); -char_u *list_find_str __ARGS((list_T *l, long idx)); -void list_append __ARGS((list_T *l, listitem_T *item)); -int list_append_tv __ARGS((list_T *l, typval_T *tv)); -int list_append_dict __ARGS((list_T *list, dict_T *dict)); -int list_append_string __ARGS((list_T *l, char_u *str, int len)); -int list_insert_tv __ARGS((list_T *l, typval_T *tv, listitem_T *item)); -void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); -void list_insert __ARGS((list_T *l, listitem_T *ni, listitem_T *item)); -int garbage_collect __ARGS((void)); -void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); -void set_ref_in_list __ARGS((list_T *l, int copyID)); -void set_ref_in_item __ARGS((typval_T *tv, int copyID)); -dict_T *dict_alloc __ARGS((void)); -void dict_unref __ARGS((dict_T *d)); -void dict_free __ARGS((dict_T *d, int recurse)); -dictitem_T *dictitem_alloc __ARGS((char_u *key)); -void dictitem_free __ARGS((dictitem_T *item)); -int dict_add __ARGS((dict_T *d, dictitem_T *item)); -int dict_add_nr_str __ARGS((dict_T *d, char *key, long nr, char_u *str)); -int dict_add_list __ARGS((dict_T *d, char *key, list_T *list)); -dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len)); -char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save)); -long get_dict_number __ARGS((dict_T *d, char_u *key)); -char_u *get_function_name __ARGS((expand_T *xp, int idx)); -char_u *get_expr_name __ARGS((expand_T *xp, int idx)); -int func_call __ARGS((char_u *name, typval_T *args, dict_T *selfdict, - typval_T *rettv)); -void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action)); -void mzscheme_call_vim __ARGS((char_u *name, typval_T *args, typval_T *rettv)); -float_T vim_round __ARGS((float_T f)); -long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir, - char_u *skip, int flags, pos_T *match_pos, - linenr_T lnum_stop, - long time_limit)); -void set_vim_var_nr __ARGS((int idx, long val)); -long get_vim_var_nr __ARGS((int idx)); -char_u *get_vim_var_str __ARGS((int idx)); -list_T *get_vim_var_list __ARGS((int idx)); -void set_vim_var_char __ARGS((int c)); -void set_vcount __ARGS((long count, long count1, int set_prevcount)); -void set_vim_var_string __ARGS((int idx, char_u *val, int len)); -void set_vim_var_list __ARGS((int idx, list_T *val)); -void set_reg_var __ARGS((int c)); -char_u *v_exception __ARGS((char_u *oldval)); -char_u *v_throwpoint __ARGS((char_u *oldval)); -char_u *set_cmdarg __ARGS((exarg_T *eap, char_u *oldarg)); -void free_tv __ARGS((typval_T *varp)); -void clear_tv __ARGS((typval_T *varp)); -long get_tv_number_chk __ARGS((typval_T *varp, int *denote)); -char_u *get_tv_string_chk __ARGS((typval_T *varp)); -char_u *get_var_value __ARGS((char_u *name)); -void new_script_vars __ARGS((scid_T id)); -void init_var_dict __ARGS((dict_T *dict, dictitem_T *dict_var, int scope)); -void unref_var_dict __ARGS((dict_T *dict)); -void vars_clear __ARGS((hashtab_T *ht)); -void copy_tv __ARGS((typval_T *from, typval_T *to)); -void ex_echo __ARGS((exarg_T *eap)); -void ex_echohl __ARGS((exarg_T *eap)); -void ex_execute __ARGS((exarg_T *eap)); -void ex_function __ARGS((exarg_T *eap)); -void free_all_functions __ARGS((void)); -int translated_function_exists __ARGS((char_u *name)); -char_u *get_expanded_name __ARGS((char_u *name, int check)); -void func_dump_profile __ARGS((FILE *fd)); -char_u *get_user_func_name __ARGS((expand_T *xp, int idx)); -void ex_delfunction __ARGS((exarg_T *eap)); -void func_unref __ARGS((char_u *name)); -void func_ref __ARGS((char_u *name)); -void ex_return __ARGS((exarg_T *eap)); -int do_return __ARGS((exarg_T *eap, int reanimate, int is_cmd, void *rettv)); -void discard_pending_return __ARGS((void *rettv)); -char_u *get_return_cmd __ARGS((void *rettv)); -char_u *get_func_line __ARGS((int c, void *cookie, int indent)); -void func_line_start __ARGS((void *cookie)); -void func_line_exec __ARGS((void *cookie)); -void func_line_end __ARGS((void *cookie)); -int func_has_ended __ARGS((void *cookie)); -int func_has_abort __ARGS((void *cookie)); -int read_viminfo_varlist __ARGS((vir_T *virp, int writing)); -void write_viminfo_varlist __ARGS((FILE *fp)); -int store_session_globals __ARGS((FILE *fd)); -void last_set_msg __ARGS((scid_T scriptID)); -void ex_oldfiles __ARGS((exarg_T *eap)); -int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u * - *bufp, - int *fnamelen)); -char_u *do_string_sub __ARGS((char_u *str, char_u *pat, char_u *sub, - char_u *flags)); -/* vim: set ft=c : */ diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro deleted file mode 100644 index 6d566e7f05..0000000000 --- a/src/proto/ex_cmds.pro +++ /dev/null @@ -1,72 +0,0 @@ -/* ex_cmds.c */ -void do_ascii __ARGS((exarg_T *eap)); -void ex_align __ARGS((exarg_T *eap)); -void ex_sort __ARGS((exarg_T *eap)); -void ex_retab __ARGS((exarg_T *eap)); -int do_move __ARGS((linenr_T line1, linenr_T line2, linenr_T dest)); -void ex_copy __ARGS((linenr_T line1, linenr_T line2, linenr_T n)); -void free_prev_shellcmd __ARGS((void)); -void do_bang __ARGS((int addr_count, exarg_T *eap, int forceit, int do_in, - int do_out)); -void do_shell __ARGS((char_u *cmd, int flags)); -char_u *make_filter_cmd __ARGS((char_u *cmd, char_u *itmp, char_u *otmp)); -void append_redir __ARGS((char_u *buf, int buflen, char_u *opt, char_u *fname)); -int viminfo_error __ARGS((char *errnum, char *message, char_u *line)); -int read_viminfo __ARGS((char_u *file, int flags)); -void write_viminfo __ARGS((char_u *file, int forceit)); -int viminfo_readline __ARGS((vir_T *virp)); -char_u *viminfo_readstring __ARGS((vir_T *virp, int off, int convert)); -void viminfo_writestring __ARGS((FILE *fd, char_u *p)); -void do_fixdel __ARGS((exarg_T *eap)); -void print_line_no_prefix __ARGS((linenr_T lnum, int use_number, int list)); -void print_line __ARGS((linenr_T lnum, int use_number, int list)); -int rename_buffer __ARGS((char_u *new_fname)); -void ex_file __ARGS((exarg_T *eap)); -void ex_update __ARGS((exarg_T *eap)); -void ex_write __ARGS((exarg_T *eap)); -int do_write __ARGS((exarg_T *eap)); -int check_overwrite __ARGS((exarg_T *eap, buf_T *buf, char_u *fname, char_u * - ffname, - int other)); -void ex_wnext __ARGS((exarg_T *eap)); -void do_wqall __ARGS((exarg_T *eap)); -int not_writing __ARGS((void)); -int getfile __ARGS((int fnum, char_u *ffname, char_u *sfname, int setpm, - linenr_T lnum, - int forceit)); -int do_ecmd __ARGS((int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, - linenr_T newlnum, int flags, - win_T *oldwin)); -void ex_append __ARGS((exarg_T *eap)); -void ex_change __ARGS((exarg_T *eap)); -void ex_z __ARGS((exarg_T *eap)); -int check_restricted __ARGS((void)); -int check_secure __ARGS((void)); -void do_sub __ARGS((exarg_T *eap)); -int do_sub_msg __ARGS((int count_only)); -void ex_global __ARGS((exarg_T *eap)); -void global_exe __ARGS((char_u *cmd)); -int read_viminfo_sub_string __ARGS((vir_T *virp, int force)); -void write_viminfo_sub_string __ARGS((FILE *fp)); -void free_old_sub __ARGS((void)); -int prepare_tagpreview __ARGS((int undo_sync)); -void ex_help __ARGS((exarg_T *eap)); -char_u *check_help_lang __ARGS((char_u *arg)); -int help_heuristic __ARGS((char_u *matched_string, int offset, int wrong_case)); -int find_help_tags __ARGS((char_u *arg, int *num_matches, char_u ***matches, - int keep_lang)); -void fix_help_buffer __ARGS((void)); -void ex_exusage __ARGS((exarg_T *eap)); -void ex_viusage __ARGS((exarg_T *eap)); -void ex_helptags __ARGS((exarg_T *eap)); -void ex_sign __ARGS((exarg_T *eap)); -void sign_gui_started __ARGS((void)); -int sign_get_attr __ARGS((int typenr, int line)); -char_u *sign_get_text __ARGS((int typenr)); -void *sign_get_image __ARGS((int typenr)); -char_u *sign_typenr2name __ARGS((int typenr)); -void free_signs __ARGS((void)); -char_u *get_sign_name __ARGS((expand_T *xp, int idx)); -void set_context_in_sign_cmd __ARGS((expand_T *xp, char_u *arg)); -void ex_drop __ARGS((exarg_T *eap)); -/* vim: set ft=c : */ diff --git a/src/proto/ex_cmds2.pro b/src/proto/ex_cmds2.pro deleted file mode 100644 index 51efb73455..0000000000 --- a/src/proto/ex_cmds2.pro +++ /dev/null @@ -1,93 +0,0 @@ -/* ex_cmds2.c */ -void do_debug __ARGS((char_u *cmd)); -void ex_debug __ARGS((exarg_T *eap)); -void dbg_check_breakpoint __ARGS((exarg_T *eap)); -int dbg_check_skipped __ARGS((exarg_T *eap)); -void ex_breakadd __ARGS((exarg_T *eap)); -void ex_debuggreedy __ARGS((exarg_T *eap)); -void ex_breakdel __ARGS((exarg_T *eap)); -void ex_breaklist __ARGS((exarg_T *eap)); -linenr_T dbg_find_breakpoint __ARGS((int file, char_u *fname, linenr_T after)); -int has_profiling __ARGS((int file, char_u *fname, int *fp)); -void dbg_breakpoint __ARGS((char_u *name, linenr_T lnum)); -void profile_start __ARGS((proftime_T *tm)); -void profile_end __ARGS((proftime_T *tm)); -void profile_sub __ARGS((proftime_T *tm, proftime_T *tm2)); -char *profile_msg __ARGS((proftime_T *tm)); -void profile_setlimit __ARGS((long msec, proftime_T *tm)); -int profile_passed_limit __ARGS((proftime_T *tm)); -void profile_zero __ARGS((proftime_T *tm)); -void profile_divide __ARGS((proftime_T *tm, int count, proftime_T *tm2)); -void profile_add __ARGS((proftime_T *tm, proftime_T *tm2)); -void profile_self __ARGS((proftime_T *self, proftime_T *total, - proftime_T *children)); -void profile_get_wait __ARGS((proftime_T *tm)); -void profile_sub_wait __ARGS((proftime_T *tm, proftime_T *tma)); -int profile_equal __ARGS((proftime_T *tm1, proftime_T *tm2)); -int profile_cmp __ARGS((const proftime_T *tm1, const proftime_T *tm2)); -void ex_profile __ARGS((exarg_T *eap)); -char_u *get_profile_name __ARGS((expand_T *xp, int idx)); -void set_context_in_profile_cmd __ARGS((expand_T *xp, char_u *arg)); -void profile_dump __ARGS((void)); -void script_prof_save __ARGS((proftime_T *tm)); -void script_prof_restore __ARGS((proftime_T *tm)); -void prof_inchar_enter __ARGS((void)); -void prof_inchar_exit __ARGS((void)); -int prof_def_func __ARGS((void)); -int autowrite __ARGS((buf_T *buf, int forceit)); -void autowrite_all __ARGS((void)); -int check_changed __ARGS((buf_T *buf, int flags)); -void browse_save_fname __ARGS((buf_T *buf)); -void dialog_changed __ARGS((buf_T *buf, int checkall)); -int can_abandon __ARGS((buf_T *buf, int forceit)); -int check_changed_any __ARGS((int hidden)); -int check_fname __ARGS((void)); -int buf_write_all __ARGS((buf_T *buf, int forceit)); -int get_arglist __ARGS((garray_T *gap, char_u *str)); -int get_arglist_exp __ARGS((char_u *str, int *fcountp, char_u ***fnamesp, - int wig)); -void set_arglist __ARGS((char_u *str)); -void check_arg_idx __ARGS((win_T *win)); -void ex_args __ARGS((exarg_T *eap)); -void ex_previous __ARGS((exarg_T *eap)); -void ex_rewind __ARGS((exarg_T *eap)); -void ex_last __ARGS((exarg_T *eap)); -void ex_argument __ARGS((exarg_T *eap)); -void do_argfile __ARGS((exarg_T *eap, int argn)); -void ex_next __ARGS((exarg_T *eap)); -void ex_argedit __ARGS((exarg_T *eap)); -void ex_argadd __ARGS((exarg_T *eap)); -void ex_argdelete __ARGS((exarg_T *eap)); -void ex_listdo __ARGS((exarg_T *eap)); -void ex_compiler __ARGS((exarg_T *eap)); -void ex_runtime __ARGS((exarg_T *eap)); -int source_runtime __ARGS((char_u *name, int all)); -int do_in_runtimepath __ARGS((char_u *name, int all, void (*callback)( - char_u *fname, void *ck), void *cookie)); -void ex_options __ARGS((exarg_T *eap)); -void ex_source __ARGS((exarg_T *eap)); -linenr_T *source_breakpoint __ARGS((void *cookie)); -int *source_dbg_tick __ARGS((void *cookie)); -int source_level __ARGS((void *cookie)); -int do_source __ARGS((char_u *fname, int check_other, int is_vimrc)); -void ex_scriptnames __ARGS((exarg_T *eap)); -void scriptnames_slash_adjust __ARGS((void)); -char_u *get_scriptname __ARGS((scid_T id)); -void free_scriptnames __ARGS((void)); -char *fgets_cr __ARGS((char *s, int n, FILE *stream)); -char_u *getsourceline __ARGS((int c, void *cookie, int indent)); -void script_line_start __ARGS((void)); -void script_line_exec __ARGS((void)); -void script_line_end __ARGS((void)); -void ex_scriptencoding __ARGS((exarg_T *eap)); -void ex_finish __ARGS((exarg_T *eap)); -void do_finish __ARGS((exarg_T *eap, int reanimate)); -int source_finished __ARGS((char_u *(*fgetline)(int, void *, int), void *cookie)); -void ex_checktime __ARGS((exarg_T *eap)); -char_u *get_mess_lang __ARGS((void)); -void set_lang_var __ARGS((void)); -void ex_language __ARGS((exarg_T *eap)); -void free_locales __ARGS((void)); -char_u *get_lang_arg __ARGS((expand_T *xp, int idx)); -char_u *get_locales __ARGS((expand_T *xp, int idx)); -/* vim: set ft=c : */ diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro deleted file mode 100644 index ff83cad83f..0000000000 --- a/src/proto/ex_docmd.pro +++ /dev/null @@ -1,69 +0,0 @@ -/* ex_docmd.c */ -void do_exmode __ARGS((int improved)); -int do_cmdline_cmd __ARGS((char_u *cmd)); -int do_cmdline __ARGS((char_u *cmdline, char_u * - (*fgetline)(int, void *, int), void *cookie, - int flags)); -int getline_equal __ARGS((char_u * - (*fgetline)(int, void *, - int), void *cookie, char_u * - (*func)(int, void *, - int))); -void *getline_cookie __ARGS((char_u *(*fgetline)(int, void *, int), - void *cookie)); -int checkforcmd __ARGS((char_u **pp, char *cmd, int len)); -int modifier_len __ARGS((char_u *cmd)); -int cmd_exists __ARGS((char_u *name)); -char_u *set_one_cmd_context __ARGS((expand_T *xp, char_u *buff)); -char_u *skip_range __ARGS((char_u *cmd, int *ctx)); -void ex_ni __ARGS((exarg_T *eap)); -int expand_filename __ARGS((exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)); -void separate_nextcmd __ARGS((exarg_T *eap)); -int ends_excmd __ARGS((int c)); -char_u *find_nextcmd __ARGS((char_u *p)); -char_u *check_nextcmd __ARGS((char_u *p)); -char_u *get_command_name __ARGS((expand_T *xp, int idx)); -void ex_comclear __ARGS((exarg_T *eap)); -void uc_clear __ARGS((garray_T *gap)); -char_u *get_user_commands __ARGS((expand_T *xp, int idx)); -char_u *get_user_cmd_flags __ARGS((expand_T *xp, int idx)); -char_u *get_user_cmd_nargs __ARGS((expand_T *xp, int idx)); -char_u *get_user_cmd_complete __ARGS((expand_T *xp, int idx)); -int parse_compl_arg __ARGS((char_u *value, int vallen, int *complp, long *argt, - char_u **compl_arg)); -void not_exiting __ARGS((void)); -void tabpage_close __ARGS((int forceit)); -void tabpage_close_other __ARGS((tabpage_T *tp, int forceit)); -void ex_all __ARGS((exarg_T *eap)); -void handle_drop __ARGS((int filec, char_u **filev, int split)); -void alist_clear __ARGS((alist_T *al)); -void alist_init __ARGS((alist_T *al)); -void alist_unlink __ARGS((alist_T *al)); -void alist_new __ARGS((void)); -void alist_expand __ARGS((int *fnum_list, int fnum_len)); -void alist_set __ARGS((alist_T *al, int count, char_u **files, int use_curbuf, - int *fnum_list, - int fnum_len)); -void alist_add __ARGS((alist_T *al, char_u *fname, int set_fnum)); -void alist_slash_adjust __ARGS((void)); -void ex_splitview __ARGS((exarg_T *eap)); -void tabpage_new __ARGS((void)); -void do_exedit __ARGS((exarg_T *eap, win_T *old_curwin)); -void free_cd_dir __ARGS((void)); -void post_chdir __ARGS((int local)); -void ex_cd __ARGS((exarg_T *eap)); -void do_sleep __ARGS((long msec)); -int vim_mkdir_emsg __ARGS((char_u *name, int prot)); -FILE *open_exfile __ARGS((char_u *fname, int forceit, char *mode)); -void update_topline_cursor __ARGS((void)); -void exec_normal_cmd __ARGS((char_u *cmd, int remap, int silent)); -int find_cmdline_var __ARGS((char_u *src, int *usedlen)); -char_u *eval_vars __ARGS((char_u *src, char_u *srcstart, int *usedlen, - linenr_T *lnump, char_u **errormsg, - int *escaped)); -char_u *expand_sfile __ARGS((char_u *arg)); -int put_eol __ARGS((FILE *fd)); -int put_line __ARGS((FILE *fd, char *s)); -void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname)); -char_u *get_behave_arg __ARGS((expand_T *xp, int idx)); -/* vim: set ft=c : */ diff --git a/src/proto/ex_eval.pro b/src/proto/ex_eval.pro deleted file mode 100644 index 7fc87410e0..0000000000 --- a/src/proto/ex_eval.pro +++ /dev/null @@ -1,38 +0,0 @@ -/* ex_eval.c */ -int aborting __ARGS((void)); -void update_force_abort __ARGS((void)); -int should_abort __ARGS((int retcode)); -int aborted_in_try __ARGS((void)); -int cause_errthrow __ARGS((char_u *mesg, int severe, int *ignore)); -void free_global_msglist __ARGS((void)); -void do_errthrow __ARGS((struct condstack *cstack, char_u *cmdname)); -int do_intthrow __ARGS((struct condstack *cstack)); -char_u *get_exception_string __ARGS((void *value, int type, char_u *cmdname, - int *should_free)); -void discard_current_exception __ARGS((void)); -void report_make_pending __ARGS((int pending, void *value)); -void report_resume_pending __ARGS((int pending, void *value)); -void report_discard_pending __ARGS((int pending, void *value)); -void ex_if __ARGS((exarg_T *eap)); -void ex_endif __ARGS((exarg_T *eap)); -void ex_else __ARGS((exarg_T *eap)); -void ex_while __ARGS((exarg_T *eap)); -void ex_continue __ARGS((exarg_T *eap)); -void ex_break __ARGS((exarg_T *eap)); -void ex_endwhile __ARGS((exarg_T *eap)); -void ex_throw __ARGS((exarg_T *eap)); -void do_throw __ARGS((struct condstack *cstack)); -void ex_try __ARGS((exarg_T *eap)); -void ex_catch __ARGS((exarg_T *eap)); -void ex_finally __ARGS((exarg_T *eap)); -void ex_endtry __ARGS((exarg_T *eap)); -void enter_cleanup __ARGS((cleanup_T *csp)); -void leave_cleanup __ARGS((cleanup_T *csp)); -int cleanup_conditionals __ARGS((struct condstack *cstack, int searched_cond, - int inclusive)); -void rewind_conditionals __ARGS((struct condstack *cstack, int idx, - int cond_type, - int *cond_level)); -void ex_endfunction __ARGS((exarg_T *eap)); -int has_loop_cmd __ARGS((char_u *p)); -/* vim: set ft=c : */ diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro deleted file mode 100644 index e3a642283f..0000000000 --- a/src/proto/ex_getln.pro +++ /dev/null @@ -1,66 +0,0 @@ -/* ex_getln.c */ -char_u *getcmdline __ARGS((int firstc, long count, int indent)); -char_u *getcmdline_prompt __ARGS((int firstc, char_u *prompt, int attr, - int xp_context, - char_u *xp_arg)); -int text_locked __ARGS((void)); -void text_locked_msg __ARGS((void)); -int curbuf_locked __ARGS((void)); -int allbuf_locked __ARGS((void)); -char_u *getexline __ARGS((int c, void *cookie, int indent)); -char_u *getexmodeline __ARGS((int promptc, void *cookie, int indent)); -int cmdline_overstrike __ARGS((void)); -int cmdline_at_end __ARGS((void)); -colnr_T cmdline_getvcol_cursor __ARGS((void)); -void free_cmdline_buf __ARGS((void)); -void putcmdline __ARGS((int c, int shift)); -void unputcmdline __ARGS((void)); -int put_on_cmdline __ARGS((char_u *str, int len, int redraw)); -char_u *save_cmdline_alloc __ARGS((void)); -void restore_cmdline_alloc __ARGS((char_u *p)); -void cmdline_paste_str __ARGS((char_u *s, int literally)); -void redrawcmdline __ARGS((void)); -void redrawcmd __ARGS((void)); -void compute_cmdrow __ARGS((void)); -void gotocmdline __ARGS((int clr)); -char_u *ExpandOne __ARGS((expand_T *xp, char_u *str, char_u *orig, int options, - int mode)); -void ExpandInit __ARGS((expand_T *xp)); -void ExpandCleanup __ARGS((expand_T *xp)); -void ExpandEscape __ARGS((expand_T *xp, char_u *str, int numfiles, char_u * - *files, - int options)); -char_u *vim_strsave_fnameescape __ARGS((char_u *fname, int shell)); -void tilde_replace __ARGS((char_u *orig_pat, int num_files, char_u **files)); -char_u *sm_gettail __ARGS((char_u *s)); -char_u *addstar __ARGS((char_u *fname, int len, int context)); -void set_cmd_context __ARGS((expand_T *xp, char_u *str, int len, int col)); -int expand_cmdline __ARGS((expand_T *xp, char_u *str, int col, int *matchcount, - char_u ***matches)); -int ExpandGeneric __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, - char_u ***file, char_u *((*func)(expand_T *, int)), - int escaped)); -char_u *globpath __ARGS((char_u *path, char_u *file, int expand_options)); -void init_history __ARGS((void)); -int get_histtype __ARGS((char_u *name)); -void add_to_history __ARGS((int histype, char_u *new_entry, int in_map, int sep)); -int get_history_idx __ARGS((int histype)); -char_u *get_cmdline_str __ARGS((void)); -int get_cmdline_pos __ARGS((void)); -int set_cmdline_pos __ARGS((int pos)); -int get_cmdline_type __ARGS((void)); -char_u *get_history_entry __ARGS((int histype, int idx)); -int clr_history __ARGS((int histype)); -int del_history_entry __ARGS((int histype, char_u *str)); -int del_history_idx __ARGS((int histype, int idx)); -void remove_key_from_history __ARGS((void)); -int get_list_range __ARGS((char_u **str, int *num1, int *num2)); -void ex_history __ARGS((exarg_T *eap)); -void prepare_viminfo_history __ARGS((int asklen, int writing)); -int read_viminfo_history __ARGS((vir_T *virp, int writing)); -void finish_viminfo_history __ARGS((void)); -void write_viminfo_history __ARGS((FILE *fp, int merge)); -void cmd_pchar __ARGS((int c, int offset)); -int cmd_gchar __ARGS((int offset)); -char_u *script_get __ARGS((exarg_T *eap, char_u *cmd)); -/* vim: set ft=c : */ diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro deleted file mode 100644 index ec83342e4d..0000000000 --- a/src/proto/fileio.pro +++ /dev/null @@ -1,82 +0,0 @@ -/* fileio.c */ -void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr)); -int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, - linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T * - eap, - int flags)); -int prep_exarg __ARGS((exarg_T *eap, buf_T *buf)); -void set_file_options __ARGS((int set_options, exarg_T *eap)); -void set_forced_fenc __ARGS((exarg_T *eap)); -int prepare_crypt_read __ARGS((FILE *fp)); -char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp)); -int check_file_readonly __ARGS((char_u *fname, int perm)); -int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, - linenr_T end, exarg_T *eap, int append, int forceit, - int reset_changed, - int filtering)); -void msg_add_fname __ARGS((buf_T *buf, char_u *fname)); -void msg_add_lines __ARGS((int insert_space, long lnum, off_t nchars)); -char_u *shorten_fname1 __ARGS((char_u *full_path)); -char_u *shorten_fname __ARGS((char_u *full_path, char_u *dir_name)); -void shorten_fnames __ARGS((int force)); -void shorten_filenames __ARGS((char_u **fnames, int count)); -char_u *modname __ARGS((char_u *fname, char_u *ext, int prepend_dot)); -char_u *buf_modname __ARGS((int shortname, char_u *fname, char_u *ext, - int prepend_dot)); -int vim_fgets __ARGS((char_u *buf, int size, FILE *fp)); -int tag_fgets __ARGS((char_u *buf, int size, FILE *fp)); -int vim_rename __ARGS((char_u *from, char_u *to)); -int check_timestamps __ARGS((int focus)); -int buf_check_timestamp __ARGS((buf_T *buf, int focus)); -void buf_reload __ARGS((buf_T *buf, int orig_mode)); -void buf_store_time __ARGS((buf_T *buf, struct stat *st, char_u *fname)); -void write_lnum_adjust __ARGS((linenr_T offset)); -void vim_deltempdir __ARGS((void)); -char_u *vim_tempname __ARGS((int extra_char)); -void forward_slash __ARGS((char_u *fname)); -void aubuflocal_remove __ARGS((buf_T *buf)); -int au_has_group __ARGS((char_u *name)); -void do_augroup __ARGS((char_u *arg, int del_group)); -void free_all_autocmds __ARGS((void)); -int check_ei __ARGS((void)); -char_u *au_event_disable __ARGS((char *what)); -void au_event_restore __ARGS((char_u *old_ei)); -void do_autocmd __ARGS((char_u *arg, int forceit)); -int do_doautocmd __ARGS((char_u *arg, int do_msg)); -void ex_doautoall __ARGS((exarg_T *eap)); -int check_nomodeline __ARGS((char_u **argp)); -void aucmd_prepbuf __ARGS((aco_save_T *aco, buf_T *buf)); -void aucmd_restbuf __ARGS((aco_save_T *aco)); -int apply_autocmds __ARGS((event_T event, char_u *fname, char_u *fname_io, - int force, - buf_T *buf)); -int apply_autocmds_retval __ARGS((event_T event, char_u *fname, char_u * - fname_io, int force, buf_T *buf, - int *retval)); -int has_cursorhold __ARGS((void)); -int trigger_cursorhold __ARGS((void)); -int has_cursormoved __ARGS((void)); -int has_cursormovedI __ARGS((void)); -int has_textchanged __ARGS((void)); -int has_textchangedI __ARGS((void)); -int has_insertcharpre __ARGS((void)); -void block_autocmds __ARGS((void)); -void unblock_autocmds __ARGS((void)); -int is_autocmd_blocked __ARGS((void)); -char_u *getnextac __ARGS((int c, void *cookie, int indent)); -int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf)); -char_u *get_augroup_name __ARGS((expand_T *xp, int idx)); -char_u *set_context_in_autocmd __ARGS((expand_T *xp, char_u *arg, int doautocmd)); -char_u *get_event_name __ARGS((expand_T *xp, int idx)); -int autocmd_supported __ARGS((char_u *name)); -int au_exists __ARGS((char_u *arg)); -int match_file_pat __ARGS((char_u *pattern, regprog_T *prog, char_u *fname, - char_u *sfname, char_u *tail, - int allow_dirs)); -int match_file_list __ARGS((char_u *list, char_u *sfname, char_u *ffname)); -char_u *file_pat_to_reg_pat __ARGS((char_u *pat, char_u *pat_end, - char *allow_dirs, - int no_bslash)); -long read_eintr __ARGS((int fd, void *buf, size_t bufsize)); -long write_eintr __ARGS((int fd, void *buf, size_t bufsize)); -/* vim: set ft=c : */ diff --git a/src/proto/fold.pro b/src/proto/fold.pro deleted file mode 100644 index 6f498872e7..0000000000 --- a/src/proto/fold.pro +++ /dev/null @@ -1,50 +0,0 @@ -/* fold.c */ -void copyFoldingState __ARGS((win_T *wp_from, win_T *wp_to)); -int hasAnyFolding __ARGS((win_T *win)); -int hasFolding __ARGS((linenr_T lnum, linenr_T *firstp, linenr_T *lastp)); -int hasFoldingWin __ARGS((win_T *win, linenr_T lnum, linenr_T *firstp, - linenr_T *lastp, int cache, - foldinfo_T *infop)); -int foldLevel __ARGS((linenr_T lnum)); -int lineFolded __ARGS((win_T *win, linenr_T lnum)); -long foldedCount __ARGS((win_T *win, linenr_T lnum, foldinfo_T *infop)); -int foldmethodIsManual __ARGS((win_T *wp)); -int foldmethodIsIndent __ARGS((win_T *wp)); -int foldmethodIsExpr __ARGS((win_T *wp)); -int foldmethodIsMarker __ARGS((win_T *wp)); -int foldmethodIsSyntax __ARGS((win_T *wp)); -int foldmethodIsDiff __ARGS((win_T *wp)); -void closeFold __ARGS((linenr_T lnum, long count)); -void closeFoldRecurse __ARGS((linenr_T lnum)); -void opFoldRange __ARGS((linenr_T first, linenr_T last, int opening, - int recurse, - int had_visual)); -void openFold __ARGS((linenr_T lnum, long count)); -void openFoldRecurse __ARGS((linenr_T lnum)); -void foldOpenCursor __ARGS((void)); -void newFoldLevel __ARGS((void)); -void foldCheckClose __ARGS((void)); -int foldManualAllowed __ARGS((int create)); -void foldCreate __ARGS((linenr_T start, linenr_T end)); -void deleteFold __ARGS((linenr_T start, linenr_T end, int recursive, - int had_visual)); -void clearFolding __ARGS((win_T *win)); -void foldUpdate __ARGS((win_T *wp, linenr_T top, linenr_T bot)); -void foldUpdateAll __ARGS((win_T *win)); -int foldMoveTo __ARGS((int updown, int dir, long count)); -void foldInitWin __ARGS((win_T *new_win)); -int find_wl_entry __ARGS((win_T *win, linenr_T lnum)); -void foldAdjustVisual __ARGS((void)); -void foldAdjustCursor __ARGS((void)); -void cloneFoldGrowArray __ARGS((garray_T *from, garray_T *to)); -void deleteFoldRecurse __ARGS((garray_T *gap)); -void foldMarkAdjust __ARGS((win_T *wp, linenr_T line1, linenr_T line2, - long amount, - long amount_after)); -int getDeepestNesting __ARGS((void)); -char_u *get_foldtext __ARGS((win_T *wp, linenr_T lnum, linenr_T lnume, - foldinfo_T *foldinfo, - char_u *buf)); -void foldtext_cleanup __ARGS((char_u *str)); -int put_folds __ARGS((FILE *fd, win_T *wp)); -/* vim: set ft=c : */ diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro deleted file mode 100644 index df3c9836cd..0000000000 --- a/src/proto/getchar.pro +++ /dev/null @@ -1,74 +0,0 @@ -/* getchar.c */ -void free_buff __ARGS((struct buffheader *buf)); -char_u *get_recorded __ARGS((void)); -char_u *get_inserted __ARGS((void)); -int stuff_empty __ARGS((void)); -void typeahead_noflush __ARGS((int c)); -void flush_buffers __ARGS((int flush_typeahead)); -void ResetRedobuff __ARGS((void)); -void CancelRedo __ARGS((void)); -void saveRedobuff __ARGS((void)); -void restoreRedobuff __ARGS((void)); -void AppendToRedobuff __ARGS((char_u *s)); -void AppendToRedobuffLit __ARGS((char_u *str, int len)); -void AppendCharToRedobuff __ARGS((int c)); -void AppendNumberToRedobuff __ARGS((long n)); -void stuffReadbuff __ARGS((char_u *s)); -void stuffReadbuffLen __ARGS((char_u *s, long len)); -void stuffReadbuffSpec __ARGS((char_u *s)); -void stuffcharReadbuff __ARGS((int c)); -void stuffnumReadbuff __ARGS((long n)); -int start_redo __ARGS((long count, int old_redo)); -int start_redo_ins __ARGS((void)); -void stop_redo_ins __ARGS((void)); -int ins_typebuf __ARGS((char_u *str, int noremap, int offset, int nottyped, - int silent)); -void ins_char_typebuf __ARGS((int c)); -int typebuf_changed __ARGS((int tb_change_cnt)); -int typebuf_typed __ARGS((void)); -int typebuf_maplen __ARGS((void)); -void del_typebuf __ARGS((int len, int offset)); -int alloc_typebuf __ARGS((void)); -void free_typebuf __ARGS((void)); -int save_typebuf __ARGS((void)); -void save_typeahead __ARGS((tasave_T *tp)); -void restore_typeahead __ARGS((tasave_T *tp)); -void openscript __ARGS((char_u *name, int directly)); -void close_all_scripts __ARGS((void)); -int using_script __ARGS((void)); -void before_blocking __ARGS((void)); -void updatescript __ARGS((int c)); -int vgetc __ARGS((void)); -int safe_vgetc __ARGS((void)); -int plain_vgetc __ARGS((void)); -int vpeekc __ARGS((void)); -int vpeekc_nomap __ARGS((void)); -int vpeekc_any __ARGS((void)); -int char_avail __ARGS((void)); -void vungetc __ARGS((int c)); -int inchar __ARGS((char_u *buf, int maxlen, long wait_time, int tb_change_cnt)); -int fix_input_buffer __ARGS((char_u *buf, int len, int script)); -int input_available __ARGS((void)); -int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev)); -int get_map_mode __ARGS((char_u **cmdp, int forceit)); -void map_clear __ARGS((char_u *cmdp, char_u *arg, int forceit, int abbr)); -void map_clear_int __ARGS((buf_T *buf, int mode, int local, int abbr)); -char_u *map_mode_to_chars __ARGS((int mode)); -int map_to_exists __ARGS((char_u *str, char_u *modechars, int abbr)); -int map_to_exists_mode __ARGS((char_u *rhs, int mode, int abbr)); -char_u *set_context_in_map_cmd __ARGS((expand_T *xp, char_u *cmd, char_u *arg, - int forceit, int isabbrev, int isunmap, - cmdidx_T cmdidx)); -int ExpandMappings __ARGS((regmatch_T *regmatch, int *num_file, char_u ***file)); -int check_abbr __ARGS((int c, char_u *ptr, int col, int mincol)); -char_u *vim_strsave_escape_csi __ARGS((char_u *p)); -void vim_unescape_csi __ARGS((char_u *p)); -int makemap __ARGS((FILE *fd, buf_T *buf)); -int put_escstr __ARGS((FILE *fd, char_u *strstart, int what)); -void check_map_keycodes __ARGS((void)); -char_u *check_map __ARGS((char_u *keys, int mode, int exact, int ign_mod, - int abbr, mapblock_T **mp_ptr, - int *local_ptr)); -void init_mappings __ARGS((void)); -void add_map __ARGS((char_u *map, int mode)); -/* vim: set ft=c : */ diff --git a/src/proto/hangulin.pro b/src/proto/hangulin.pro deleted file mode 100644 index adfde142ff..0000000000 --- a/src/proto/hangulin.pro +++ /dev/null @@ -1,9 +0,0 @@ -/* hangulin.c */ -int hangul_input_state_get __ARGS((void)); -void hangul_input_state_set __ARGS((int state)); -int im_get_status __ARGS((void)); -void hangul_input_state_toggle __ARGS((void)); -void hangul_keyboard_set __ARGS((void)); -int hangul_input_process __ARGS((char_u *s, int len)); -void hangul_input_clear __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/hardcopy.pro b/src/proto/hardcopy.pro deleted file mode 100644 index 3744181371..0000000000 --- a/src/proto/hardcopy.pro +++ /dev/null @@ -1,21 +0,0 @@ -/* hardcopy.c */ -char_u *parse_printoptions __ARGS((void)); -char_u *parse_printmbfont __ARGS((void)); -int prt_header_height __ARGS((void)); -int prt_use_number __ARGS((void)); -int prt_get_unit __ARGS((int idx)); -void ex_hardcopy __ARGS((exarg_T *eap)); -void mch_print_cleanup __ARGS((void)); -int mch_print_init __ARGS((prt_settings_T *psettings, char_u *jobname, - int forceit)); -int mch_print_begin __ARGS((prt_settings_T *psettings)); -void mch_print_end __ARGS((prt_settings_T *psettings)); -int mch_print_end_page __ARGS((void)); -int mch_print_begin_page __ARGS((char_u *str)); -int mch_print_blank_page __ARGS((void)); -void mch_print_start_line __ARGS((int margin, int page_line)); -int mch_print_text_out __ARGS((char_u *p, int len)); -void mch_print_set_font __ARGS((int iBold, int iItalic, int iUnderline)); -void mch_print_set_bg __ARGS((long_u bgcol)); -void mch_print_set_fg __ARGS((long_u fgcol)); -/* vim: set ft=c : */ diff --git a/src/proto/hashtab.pro b/src/proto/hashtab.pro deleted file mode 100644 index c90f44898e..0000000000 --- a/src/proto/hashtab.pro +++ /dev/null @@ -1,15 +0,0 @@ -/* hashtab.c */ -void hash_init __ARGS((hashtab_T *ht)); -void hash_clear __ARGS((hashtab_T *ht)); -void hash_clear_all __ARGS((hashtab_T *ht, int off)); -hashitem_T *hash_find __ARGS((hashtab_T *ht, char_u *key)); -hashitem_T *hash_lookup __ARGS((hashtab_T *ht, char_u *key, hash_T hash)); -void hash_debug_results __ARGS((void)); -int hash_add __ARGS((hashtab_T *ht, char_u *key)); -int hash_add_item __ARGS((hashtab_T *ht, hashitem_T *hi, char_u *key, - hash_T hash)); -void hash_remove __ARGS((hashtab_T *ht, hashitem_T *hi)); -void hash_lock __ARGS((hashtab_T *ht)); -void hash_unlock __ARGS((hashtab_T *ht)); -hash_T hash_hash __ARGS((char_u *key)); -/* vim: set ft=c : */ diff --git a/src/proto/if_cscope.pro b/src/proto/if_cscope.pro deleted file mode 100644 index 1239835d79..0000000000 --- a/src/proto/if_cscope.pro +++ /dev/null @@ -1,13 +0,0 @@ -/* if_cscope.c */ -char_u *get_cscope_name __ARGS((expand_T *xp, int idx)); -void set_context_in_cscope_cmd __ARGS((expand_T *xp, char_u *arg, - cmdidx_T cmdidx)); -void do_cscope __ARGS((exarg_T *eap)); -void do_scscope __ARGS((exarg_T *eap)); -void do_cstag __ARGS((exarg_T *eap)); -int cs_fgets __ARGS((char_u *buf, int size)); -void cs_free_tags __ARGS((void)); -void cs_print_tags __ARGS((void)); -int cs_connection __ARGS((int num, char_u *dbpath, char_u *ppath)); -void cs_end __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/main.pro b/src/proto/main.pro deleted file mode 100644 index a93b8de2ae..0000000000 --- a/src/proto/main.pro +++ /dev/null @@ -1,27 +0,0 @@ -/* main.c */ -void main_loop __ARGS((int cmdwin, int noexmode)); -void getout_preserve_modified __ARGS((int exitval)); -void getout __ARGS((int exitval)); -int process_env __ARGS((char_u *env, int is_viminit)); -void mainerr_arg_missing __ARGS((char_u *str)); -void time_push __ARGS((void *tv_rel, void *tv_start)); -void time_pop __ARGS((void *tp)); -void time_msg __ARGS((char *mesg, void *tv_start)); -void server_to_input_buf __ARGS((char_u *str)); -char_u *eval_client_expr_to_string __ARGS((char_u *expr)); -char_u *serverConvert __ARGS((char_u *client_enc, char_u *data, char_u **tofree)); -int toF_TyA __ARGS((int c)); -int fkmap __ARGS((int c)); -void conv_to_pvim __ARGS((void)); -void conv_to_pstd __ARGS((void)); -char_u *lrswap __ARGS((char_u *ibuf)); -char_u *lrFswap __ARGS((char_u *cmdbuf, int len)); -char_u *lrF_sub __ARGS((char_u *ibuf)); -int cmdl_fkmap __ARGS((int c)); -int F_isalpha __ARGS((int c)); -int F_isdigit __ARGS((int c)); -int F_ischar __ARGS((int c)); -void farsi_fkey __ARGS((cmdarg_T *cap)); -int arabic_shape __ARGS((int c, int *ccp, int *c1p, int prev_c, int prev_c1, - int next_c)); -/* vim: set ft=c : */ diff --git a/src/proto/mark.pro b/src/proto/mark.pro deleted file mode 100644 index 47623f4847..0000000000 --- a/src/proto/mark.pro +++ /dev/null @@ -1,34 +0,0 @@ -/* mark.c */ -int setmark __ARGS((int c)); -int setmark_pos __ARGS((int c, pos_T *pos, int fnum)); -void setpcmark __ARGS((void)); -void checkpcmark __ARGS((void)); -pos_T *movemark __ARGS((int count)); -pos_T *movechangelist __ARGS((int count)); -pos_T *getmark_buf __ARGS((buf_T *buf, int c, int changefile)); -pos_T *getmark __ARGS((int c, int changefile)); -pos_T *getmark_buf_fnum __ARGS((buf_T *buf, int c, int changefile, int *fnum)); -pos_T *getnextmark __ARGS((pos_T *startpos, int dir, int begin_line)); -void fmarks_check_names __ARGS((buf_T *buf)); -int check_mark __ARGS((pos_T *pos)); -void clrallmarks __ARGS((buf_T *buf)); -char_u *fm_getname __ARGS((fmark_T *fmark, int lead_len)); -void do_marks __ARGS((exarg_T *eap)); -void ex_delmarks __ARGS((exarg_T *eap)); -void ex_jumps __ARGS((exarg_T *eap)); -void ex_changes __ARGS((exarg_T *eap)); -void mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, - long amount_after)); -void mark_col_adjust __ARGS((linenr_T lnum, colnr_T mincol, long lnum_amount, - long col_amount)); -void copy_jumplist __ARGS((win_T *from, win_T *to)); -void free_jumplist __ARGS((win_T *wp)); -void set_last_cursor __ARGS((win_T *win)); -void free_all_marks __ARGS((void)); -int read_viminfo_filemark __ARGS((vir_T *virp, int force)); -void write_viminfo_filemarks __ARGS((FILE *fp)); -int removable __ARGS((char_u *name)); -int write_viminfo_marks __ARGS((FILE *fp_out)); -void copy_viminfo_marks __ARGS((vir_T *virp, FILE *fp_out, int count, int eof, - int flags)); -/* vim: set ft=c : */ diff --git a/src/proto/mbyte.pro b/src/proto/mbyte.pro deleted file mode 100644 index c440d62a4e..0000000000 --- a/src/proto/mbyte.pro +++ /dev/null @@ -1,100 +0,0 @@ -/* mbyte.c */ -int enc_canon_props __ARGS((char_u *name)); -char_u *mb_init __ARGS((void)); -int bomb_size __ARGS((void)); -void remove_bom __ARGS((char_u *s)); -int mb_get_class __ARGS((char_u *p)); -int mb_get_class_buf __ARGS((char_u *p, buf_T *buf)); -int dbcs_class __ARGS((unsigned lead, unsigned trail)); -int latin_char2len __ARGS((int c)); -int latin_char2bytes __ARGS((int c, char_u *buf)); -int latin_ptr2len __ARGS((char_u *p)); -int latin_ptr2len_len __ARGS((char_u *p, int size)); -int utf_char2cells __ARGS((int c)); -int latin_ptr2cells __ARGS((char_u *p)); -int utf_ptr2cells __ARGS((char_u *p)); -int dbcs_ptr2cells __ARGS((char_u *p)); -int latin_ptr2cells_len __ARGS((char_u *p, int size)); -int latin_char2cells __ARGS((int c)); -int mb_string2cells __ARGS((char_u *p, int len)); -int latin_off2cells __ARGS((unsigned off, unsigned max_off)); -int dbcs_off2cells __ARGS((unsigned off, unsigned max_off)); -int utf_off2cells __ARGS((unsigned off, unsigned max_off)); -int latin_ptr2char __ARGS((char_u *p)); -int utf_ptr2char __ARGS((char_u *p)); -int mb_ptr2char_adv __ARGS((char_u **pp)); -int mb_cptr2char_adv __ARGS((char_u **pp)); -int arabic_combine __ARGS((int one, int two)); -int arabic_maycombine __ARGS((int two)); -int utf_composinglike __ARGS((char_u *p1, char_u *p2)); -int utfc_ptr2char __ARGS((char_u *p, int *pcc)); -int utfc_ptr2char_len __ARGS((char_u *p, int *pcc, int maxlen)); -int utfc_char2bytes __ARGS((int off, char_u *buf)); -int utf_ptr2len __ARGS((char_u *p)); -int utf_byte2len __ARGS((int b)); -int utf_ptr2len_len __ARGS((char_u *p, int size)); -int utfc_ptr2len __ARGS((char_u *p)); -int utfc_ptr2len_len __ARGS((char_u *p, int size)); -int utf_char2len __ARGS((int c)); -int utf_char2bytes __ARGS((int c, char_u *buf)); -int utf_iscomposing __ARGS((int c)); -int utf_printable __ARGS((int c)); -int utf_class __ARGS((int c)); -int utf_fold __ARGS((int a)); -int utf_toupper __ARGS((int a)); -int utf_islower __ARGS((int a)); -int utf_tolower __ARGS((int a)); -int utf_isupper __ARGS((int a)); -int mb_strnicmp __ARGS((char_u *s1, char_u *s2, size_t nn)); -void show_utf8 __ARGS((void)); -int latin_head_off __ARGS((char_u *base, char_u *p)); -int dbcs_head_off __ARGS((char_u *base, char_u *p)); -int dbcs_screen_head_off __ARGS((char_u *base, char_u *p)); -int utf_head_off __ARGS((char_u *base, char_u *p)); -void mb_copy_char __ARGS((char_u **fp, char_u **tp)); -int mb_off_next __ARGS((char_u *base, char_u *p)); -int mb_tail_off __ARGS((char_u *base, char_u *p)); -void utf_find_illegal __ARGS((void)); -int utf_valid_string __ARGS((char_u *s, char_u *end)); -int dbcs_screen_tail_off __ARGS((char_u *base, char_u *p)); -void mb_adjust_cursor __ARGS((void)); -void mb_adjustpos __ARGS((buf_T *buf, pos_T *lp)); -char_u *mb_prevptr __ARGS((char_u *line, char_u *p)); -int mb_charlen __ARGS((char_u *str)); -int mb_charlen_len __ARGS((char_u *str, int len)); -char_u *mb_unescape __ARGS((char_u **pp)); -int mb_lefthalve __ARGS((int row, int col)); -int mb_fix_col __ARGS((int col, int row)); -char_u *enc_skip __ARGS((char_u *p)); -char_u *enc_canonize __ARGS((char_u *enc)); -char_u *enc_locale __ARGS((void)); -int encname2codepage __ARGS((char_u *name)); -void *my_iconv_open __ARGS((char_u *to, char_u *from)); -int iconv_enabled __ARGS((int verbose)); -void iconv_end __ARGS((void)); -void im_set_active __ARGS((int active)); -void xim_set_focus __ARGS((int focus)); -void im_set_position __ARGS((int row, int col)); -void xim_set_preedit __ARGS((void)); -int im_get_feedback_attr __ARGS((int col)); -void xim_init __ARGS((void)); -void im_shutdown __ARGS((void)); -int im_xim_isvalid_imactivate __ARGS((void)); -void xim_reset __ARGS((void)); -int xim_queue_key_press_event __ARGS((GdkEventKey *event, int down)); -int im_get_status __ARGS((void)); -int preedit_get_status __ARGS((void)); -int im_is_preediting __ARGS((void)); -void xim_set_status_area __ARGS((void)); -int xim_get_status_area_height __ARGS((void)); -int convert_setup __ARGS((vimconv_T *vcp, char_u *from, char_u *to)); -int convert_setup_ext __ARGS((vimconv_T *vcp, char_u *from, - int from_unicode_is_utf8, char_u *to, - int to_unicode_is_utf8)); -int convert_input __ARGS((char_u *ptr, int len, int maxlen)); -int convert_input_safe __ARGS((char_u *ptr, int len, int maxlen, char_u **restp, - int *restlenp)); -char_u *string_convert __ARGS((vimconv_T *vcp, char_u *ptr, int *lenp)); -char_u *string_convert_ext __ARGS((vimconv_T *vcp, char_u *ptr, int *lenp, - int *unconvlenp)); -/* vim: set ft=c : */ diff --git a/src/proto/memfile.pro b/src/proto/memfile.pro deleted file mode 100644 index 3983b4799c..0000000000 --- a/src/proto/memfile.pro +++ /dev/null @@ -1,18 +0,0 @@ -/* memfile.c */ -memfile_T *mf_open __ARGS((char_u *fname, int flags)); -int mf_open_file __ARGS((memfile_T *mfp, char_u *fname)); -void mf_close __ARGS((memfile_T *mfp, int del_file)); -void mf_close_file __ARGS((buf_T *buf, int getlines)); -void mf_new_page_size __ARGS((memfile_T *mfp, unsigned new_size)); -bhdr_T *mf_new __ARGS((memfile_T *mfp, int negative, int page_count)); -bhdr_T *mf_get __ARGS((memfile_T *mfp, blocknr_T nr, int page_count)); -void mf_put __ARGS((memfile_T *mfp, bhdr_T *hp, int dirty, int infile)); -void mf_free __ARGS((memfile_T *mfp, bhdr_T *hp)); -int mf_sync __ARGS((memfile_T *mfp, int flags)); -void mf_set_dirty __ARGS((memfile_T *mfp)); -int mf_release_all __ARGS((void)); -blocknr_T mf_trans_del __ARGS((memfile_T *mfp, blocknr_T old_nr)); -void mf_set_ffname __ARGS((memfile_T *mfp)); -void mf_fullname __ARGS((memfile_T *mfp)); -int mf_need_trans __ARGS((memfile_T *mfp)); -/* vim: set ft=c : */ diff --git a/src/proto/memline.pro b/src/proto/memline.pro deleted file mode 100644 index 97806d38a2..0000000000 --- a/src/proto/memline.pro +++ /dev/null @@ -1,41 +0,0 @@ -/* memline.c */ -int ml_open __ARGS((buf_T *buf)); -void ml_set_crypt_key __ARGS((buf_T *buf, char_u *old_key, int old_cm)); -void ml_setname __ARGS((buf_T *buf)); -void ml_open_files __ARGS((void)); -void ml_open_file __ARGS((buf_T *buf)); -void check_need_swap __ARGS((int newfile)); -void ml_close __ARGS((buf_T *buf, int del_file)); -void ml_close_all __ARGS((int del_file)); -void ml_close_notmod __ARGS((void)); -void ml_timestamp __ARGS((buf_T *buf)); -void ml_recover __ARGS((void)); -int recover_names __ARGS((char_u *fname, int list, int nr, char_u **fname_out)); -void ml_sync_all __ARGS((int check_file, int check_char)); -void ml_preserve __ARGS((buf_T *buf, int message)); -char_u *ml_get __ARGS((linenr_T lnum)); -char_u *ml_get_pos __ARGS((pos_T *pos)); -char_u *ml_get_curline __ARGS((void)); -char_u *ml_get_cursor __ARGS((void)); -char_u *ml_get_buf __ARGS((buf_T *buf, linenr_T lnum, int will_change)); -int ml_line_alloced __ARGS((void)); -int ml_append __ARGS((linenr_T lnum, char_u *line, colnr_T len, int newfile)); -int ml_append_buf __ARGS((buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, - int newfile)); -int ml_replace __ARGS((linenr_T lnum, char_u *line, int copy)); -int ml_delete __ARGS((linenr_T lnum, int message)); -void ml_setmarked __ARGS((linenr_T lnum)); -linenr_T ml_firstmarked __ARGS((void)); -void ml_clearmarked __ARGS((void)); -int resolve_symlink __ARGS((char_u *fname, char_u *buf)); -char_u *makeswapname __ARGS((char_u *fname, char_u *ffname, buf_T *buf, - char_u *dir_name)); -char_u *get_file_in_dir __ARGS((char_u *fname, char_u *dname)); -void ml_setflags __ARGS((buf_T *buf)); -char_u *ml_encrypt_data __ARGS((memfile_T *mfp, char_u *data, off_t offset, - unsigned size)); -void ml_decrypt_data __ARGS((memfile_T *mfp, char_u *data, off_t offset, - unsigned size)); -long ml_find_line_or_offset __ARGS((buf_T *buf, linenr_T lnum, long *offp)); -void goto_byte __ARGS((long cnt)); -/* vim: set ft=c : */ diff --git a/src/proto/menu.pro b/src/proto/menu.pro deleted file mode 100644 index 80460d2de2..0000000000 --- a/src/proto/menu.pro +++ /dev/null @@ -1,23 +0,0 @@ -/* menu.c */ -void ex_menu __ARGS((exarg_T *eap)); -char_u *set_context_in_menu_cmd __ARGS((expand_T *xp, char_u *cmd, char_u *arg, - int forceit)); -char_u *get_menu_name __ARGS((expand_T *xp, int idx)); -char_u *get_menu_names __ARGS((expand_T *xp, int idx)); -char_u *menu_name_skip __ARGS((char_u *name)); -int get_menu_index __ARGS((vimmenu_T *menu, int state)); -int menu_is_menubar __ARGS((char_u *name)); -int menu_is_popup __ARGS((char_u *name)); -int menu_is_child_of_popup __ARGS((vimmenu_T *menu)); -int menu_is_toolbar __ARGS((char_u *name)); -int menu_is_separator __ARGS((char_u *name)); -int check_menu_pointer __ARGS((vimmenu_T *root, vimmenu_T *menu_to_check)); -void gui_create_initial_menus __ARGS((vimmenu_T *menu)); -void gui_update_menus __ARGS((int modes)); -int gui_is_menu_shortcut __ARGS((int key)); -void gui_show_popupmenu __ARGS((void)); -void gui_mch_toggle_tearoffs __ARGS((int enable)); -void ex_emenu __ARGS((exarg_T *eap)); -vimmenu_T *gui_find_menu __ARGS((char_u *path_name)); -void ex_menutranslate __ARGS((exarg_T *eap)); -/* vim: set ft=c : */ diff --git a/src/proto/message.pro b/src/proto/message.pro deleted file mode 100644 index ece1985213..0000000000 --- a/src/proto/message.pro +++ /dev/null @@ -1,80 +0,0 @@ -/* message.c */ -int msg __ARGS((char_u *s)); -int verb_msg __ARGS((char_u *s)); -int msg_attr __ARGS((char_u *s, int attr)); -int msg_attr_keep __ARGS((char_u *s, int attr, int keep)); -char_u *msg_strtrunc __ARGS((char_u *s, int force)); -void trunc_string __ARGS((char_u *s, char_u *buf, int room, int buflen)); -void reset_last_sourcing __ARGS((void)); -void msg_source __ARGS((int attr)); -int emsg_not_now __ARGS((void)); -int emsg __ARGS((char_u *s)); -int emsg2 __ARGS((char_u *s, char_u *a1)); -void emsg_invreg __ARGS((int name)); -char_u *msg_trunc_attr __ARGS((char_u *s, int force, int attr)); -char_u *msg_may_trunc __ARGS((int force, char_u *s)); -int delete_first_msg __ARGS((void)); -void ex_messages __ARGS((exarg_T *eap)); -void msg_end_prompt __ARGS((void)); -void wait_return __ARGS((int redraw)); -void set_keep_msg __ARGS((char_u *s, int attr)); -void set_keep_msg_from_hist __ARGS((void)); -void msg_start __ARGS((void)); -void msg_starthere __ARGS((void)); -void msg_putchar __ARGS((int c)); -void msg_putchar_attr __ARGS((int c, int attr)); -void msg_outnum __ARGS((long n)); -void msg_home_replace __ARGS((char_u *fname)); -void msg_home_replace_hl __ARGS((char_u *fname)); -int msg_outtrans __ARGS((char_u *str)); -int msg_outtrans_attr __ARGS((char_u *str, int attr)); -int msg_outtrans_len __ARGS((char_u *str, int len)); -char_u *msg_outtrans_one __ARGS((char_u *p, int attr)); -int msg_outtrans_len_attr __ARGS((char_u *msgstr, int len, int attr)); -void msg_make __ARGS((char_u *arg)); -int msg_outtrans_special __ARGS((char_u *strstart, int from)); -char_u *str2special_save __ARGS((char_u *str, int is_lhs)); -char_u *str2special __ARGS((char_u **sp, int from)); -void str2specialbuf __ARGS((char_u *sp, char_u *buf, int len)); -void msg_prt_line __ARGS((char_u *s, int list)); -void msg_puts __ARGS((char_u *s)); -void msg_puts_title __ARGS((char_u *s)); -void msg_puts_long_attr __ARGS((char_u *longstr, int attr)); -void msg_puts_long_len_attr __ARGS((char_u *longstr, int len, int attr)); -void msg_puts_attr __ARGS((char_u *s, int attr)); -void may_clear_sb_text __ARGS((void)); -void clear_sb_text __ARGS((void)); -void show_sb_text __ARGS((void)); -void msg_sb_eol __ARGS((void)); -int msg_use_printf __ARGS((void)); -void mch_errmsg __ARGS((char *str)); -void mch_msg __ARGS((char *str)); -void msg_moremsg __ARGS((int full)); -void repeat_message __ARGS((void)); -void msg_clr_eos __ARGS((void)); -void msg_clr_eos_force __ARGS((void)); -void msg_clr_cmdline __ARGS((void)); -int msg_end __ARGS((void)); -void msg_check __ARGS((void)); -int redirecting __ARGS((void)); -void verbose_enter __ARGS((void)); -void verbose_leave __ARGS((void)); -void verbose_enter_scroll __ARGS((void)); -void verbose_leave_scroll __ARGS((void)); -void verbose_stop __ARGS((void)); -int verbose_open __ARGS((void)); -void give_warning __ARGS((char_u *message, int hl)); -void msg_advance __ARGS((int col)); -int do_dialog __ARGS((int type, char_u *title, char_u *message, char_u *buttons, - int dfltbutton, char_u *textfield, - int ex_cmd)); -void display_confirm_msg __ARGS((void)); -int vim_dialog_yesno __ARGS((int type, char_u *title, char_u *message, int dflt)); -int vim_dialog_yesnocancel __ARGS((int type, char_u *title, char_u *message, - int dflt)); -int vim_dialog_yesnoallcancel __ARGS((int type, char_u *title, char_u *message, - int dflt)); -char_u *do_browse __ARGS((int flags, char_u *title, char_u *dflt, char_u *ext, - char_u *initdir, char_u *filter, - buf_T *buf)); -/* vim: set ft=c : */ diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro deleted file mode 100644 index 0497096791..0000000000 --- a/src/proto/misc1.pro +++ /dev/null @@ -1,117 +0,0 @@ -/* misc1.c */ -int get_indent __ARGS((void)); -int get_indent_lnum __ARGS((linenr_T lnum)); -int get_indent_buf __ARGS((buf_T *buf, linenr_T lnum)); -int get_indent_str __ARGS((char_u *ptr, int ts)); -int set_indent __ARGS((int size, int flags)); -int get_number_indent __ARGS((linenr_T lnum)); -int open_line __ARGS((int dir, int flags, int second_line_indent)); -int get_leader_len __ARGS((char_u *line, char_u **flags, int backward, - int include_space)); -int get_last_leader_offset __ARGS((char_u *line, char_u **flags)); -int plines __ARGS((linenr_T lnum)); -int plines_win __ARGS((win_T *wp, linenr_T lnum, int winheight)); -int plines_nofill __ARGS((linenr_T lnum)); -int plines_win_nofill __ARGS((win_T *wp, linenr_T lnum, int winheight)); -int plines_win_nofold __ARGS((win_T *wp, linenr_T lnum)); -int plines_win_col __ARGS((win_T *wp, linenr_T lnum, long column)); -int plines_m_win __ARGS((win_T *wp, linenr_T first, linenr_T last)); -void ins_bytes __ARGS((char_u *p)); -void ins_bytes_len __ARGS((char_u *p, int len)); -void ins_char __ARGS((int c)); -void ins_char_bytes __ARGS((char_u *buf, int charlen)); -void ins_str __ARGS((char_u *s)); -int del_char __ARGS((int fixpos)); -int del_chars __ARGS((long count, int fixpos)); -int del_bytes __ARGS((long count, int fixpos_arg, int use_delcombine)); -int truncate_line __ARGS((int fixpos)); -void del_lines __ARGS((long nlines, int undo)); -int gchar_pos __ARGS((pos_T *pos)); -int gchar_cursor __ARGS((void)); -void pchar_cursor __ARGS((int c)); -int inindent __ARGS((int extra)); -char_u *skip_to_option_part __ARGS((char_u *p)); -void changed __ARGS((void)); -void changed_int __ARGS((void)); -void changed_bytes __ARGS((linenr_T lnum, colnr_T col)); -void appended_lines __ARGS((linenr_T lnum, long count)); -void appended_lines_mark __ARGS((linenr_T lnum, long count)); -void deleted_lines __ARGS((linenr_T lnum, long count)); -void deleted_lines_mark __ARGS((linenr_T lnum, long count)); -void changed_lines __ARGS((linenr_T lnum, colnr_T col, linenr_T lnume, - long xtra)); -void unchanged __ARGS((buf_T *buf, int ff)); -void check_status __ARGS((buf_T *buf)); -void change_warning __ARGS((int col)); -int ask_yesno __ARGS((char_u *str, int direct)); -int is_mouse_key __ARGS((int c)); -int get_keystroke __ARGS((void)); -int get_number __ARGS((int colon, int *mouse_used)); -int prompt_for_number __ARGS((int *mouse_used)); -void msgmore __ARGS((long n)); -void beep_flush __ARGS((void)); -void vim_beep __ARGS((void)); -void init_homedir __ARGS((void)); -void free_homedir __ARGS((void)); -void free_users __ARGS((void)); -char_u *expand_env_save __ARGS((char_u *src)); -char_u *expand_env_save_opt __ARGS((char_u *src, int one)); -void expand_env __ARGS((char_u *src, char_u *dst, int dstlen)); -void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, - int one, - char_u *startstr)); -char_u *vim_getenv __ARGS((char_u *name, int *mustfree)); -void vim_setenv __ARGS((char_u *name, char_u *val)); -char_u *get_env_name __ARGS((expand_T *xp, int idx)); -char_u *get_users __ARGS((expand_T *xp, int idx)); -int match_user __ARGS((char_u *name)); -void home_replace __ARGS((buf_T *buf, char_u *src, char_u *dst, int dstlen, - int one)); -char_u *home_replace_save __ARGS((buf_T *buf, char_u *src)); -int fullpathcmp __ARGS((char_u *s1, char_u *s2, int checkname)); -char_u *gettail __ARGS((char_u *fname)); -char_u *gettail_sep __ARGS((char_u *fname)); -char_u *getnextcomp __ARGS((char_u *fname)); -char_u *get_past_head __ARGS((char_u *path)); -int vim_ispathsep __ARGS((int c)); -int vim_ispathsep_nocolon __ARGS((int c)); -int vim_ispathlistsep __ARGS((int c)); -void shorten_dir __ARGS((char_u *str)); -int dir_of_file_exists __ARGS((char_u *fname)); -int vim_fnamecmp __ARGS((char_u *x, char_u *y)); -int vim_fnamencmp __ARGS((char_u *x, char_u *y, size_t len)); -char_u *concat_fnames __ARGS((char_u *fname1, char_u *fname2, int sep)); -char_u *concat_str __ARGS((char_u *str1, char_u *str2)); -void add_pathsep __ARGS((char_u *p)); -char_u *FullName_save __ARGS((char_u *fname, int force)); -pos_T *find_start_comment __ARGS((int ind_maxcomment)); -void do_c_expr_indent __ARGS((void)); -int cin_islabel __ARGS((void)); -int cin_iscase __ARGS((char_u *s, int strict)); -int cin_isscopedecl __ARGS((char_u *s)); -void parse_cino __ARGS((buf_T *buf)); -int get_c_indent __ARGS((void)); -int get_expr_indent __ARGS((void)); -int get_lisp_indent __ARGS((void)); -void prepare_to_exit __ARGS((void)); -void preserve_exit __ARGS((void)); -int vim_fexists __ARGS((char_u *fname)); -void line_breakcheck __ARGS((void)); -void fast_breakcheck __ARGS((void)); -int expand_wildcards_eval __ARGS((char_u **pat, int *num_file, char_u ***file, - int flags)); -int expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u * - **file, - int flags)); -int match_suffix __ARGS((char_u *fname)); -int unix_expandpath __ARGS((garray_T *gap, char_u *path, int wildoff, int flags, - int didstar)); -void remove_duplicates __ARGS((garray_T *gap)); -int gen_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, - char_u ***file, - int flags)); -void addfile __ARGS((garray_T *gap, char_u *f, int flags)); -char_u *get_cmd_output __ARGS((char_u *cmd, char_u *infile, int flags)); -void FreeWild __ARGS((int count, char_u **files)); -int goto_im __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro deleted file mode 100644 index c0fd06ff77..0000000000 --- a/src/proto/misc2.pro +++ /dev/null @@ -1,133 +0,0 @@ -/* misc2.c */ -int virtual_active __ARGS((void)); -int getviscol __ARGS((void)); -int getviscol2 __ARGS((colnr_T col, colnr_T coladd)); -int coladvance_force __ARGS((colnr_T wcol)); -int coladvance __ARGS((colnr_T wcol)); -int getvpos __ARGS((pos_T *pos, colnr_T wcol)); -int inc_cursor __ARGS((void)); -int inc __ARGS((pos_T *lp)); -int incl __ARGS((pos_T *lp)); -int dec_cursor __ARGS((void)); -int dec __ARGS((pos_T *lp)); -int decl __ARGS((pos_T *lp)); -linenr_T get_cursor_rel_lnum __ARGS((win_T *wp, linenr_T lnum)); -void check_cursor_lnum __ARGS((void)); -void check_cursor_col __ARGS((void)); -void check_cursor_col_win __ARGS((win_T *win)); -void check_cursor __ARGS((void)); -void adjust_cursor_col __ARGS((void)); -int leftcol_changed __ARGS((void)); -void vim_mem_profile_dump __ARGS((void)); -char_u *alloc __ARGS((unsigned size)); -char_u *alloc_clear __ARGS((unsigned size)); -char_u *alloc_check __ARGS((unsigned size)); -char_u *lalloc_clear __ARGS((long_u size, int message)); -char_u *lalloc __ARGS((long_u size, int message)); -void *mem_realloc __ARGS((void *ptr, size_t size)); -void do_outofmem_msg __ARGS((long_u size)); -void free_all_mem __ARGS((void)); -char_u *vim_strsave __ARGS((char_u *string)); -char_u *vim_strnsave __ARGS((char_u *string, int len)); -char_u *vim_strsave_escaped __ARGS((char_u *string, char_u *esc_chars)); -char_u *vim_strsave_escaped_ext __ARGS((char_u *string, char_u *esc_chars, - int cc, - int bsl)); -int csh_like_shell __ARGS((void)); -char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special)); -char_u *vim_strsave_up __ARGS((char_u *string)); -char_u *vim_strnsave_up __ARGS((char_u *string, int len)); -void vim_strup __ARGS((char_u *p)); -char_u *strup_save __ARGS((char_u *orig)); -void copy_spaces __ARGS((char_u *ptr, size_t count)); -void copy_chars __ARGS((char_u *ptr, size_t count, int c)); -void del_trailing_spaces __ARGS((char_u *ptr)); -void vim_strncpy __ARGS((char_u *to, char_u *from, size_t len)); -void vim_strcat __ARGS((char_u *to, char_u *from, size_t tosize)); -int copy_option_part __ARGS((char_u **option, char_u *buf, int maxlen, - char *sep_chars)); -void vim_free __ARGS((void *x)); -int vim_stricmp __ARGS((char *s1, char *s2)); -int vim_strnicmp __ARGS((char *s1, char *s2, size_t len)); -char_u *vim_strchr __ARGS((char_u *string, int c)); -char_u *vim_strbyte __ARGS((char_u *string, int c)); -char_u *vim_strrchr __ARGS((char_u *string, int c)); -int vim_isspace __ARGS((int x)); -void ga_clear __ARGS((garray_T *gap)); -void ga_clear_strings __ARGS((garray_T *gap)); -void ga_init __ARGS((garray_T *gap)); -void ga_init2 __ARGS((garray_T *gap, int itemsize, int growsize)); -int ga_grow __ARGS((garray_T *gap, int n)); -char_u *ga_concat_strings __ARGS((garray_T *gap)); -void ga_concat __ARGS((garray_T *gap, char_u *s)); -void ga_append __ARGS((garray_T *gap, int c)); -void append_ga_line __ARGS((garray_T *gap)); -int name_to_mod_mask __ARGS((int c)); -int simplify_key __ARGS((int key, int *modifiers)); -int handle_x_keys __ARGS((int key)); -char_u *get_special_key_name __ARGS((int c, int modifiers)); -int trans_special __ARGS((char_u **srcp, char_u *dst, int keycode)); -int find_special_key __ARGS((char_u **srcp, int *modp, int keycode, - int keep_x_key)); -int extract_modifiers __ARGS((int key, int *modp)); -int find_special_key_in_table __ARGS((int c)); -int get_special_key_code __ARGS((char_u *name)); -char_u *get_key_name __ARGS((int i)); -int get_mouse_button __ARGS((int code, int *is_click, int *is_drag)); -int get_pseudo_mouse_code __ARGS((int button, int is_click, int is_drag)); -int get_fileformat __ARGS((buf_T *buf)); -int get_fileformat_force __ARGS((buf_T *buf, exarg_T *eap)); -void set_fileformat __ARGS((int t, int opt_flags)); -int default_fileformat __ARGS((void)); -int call_shell __ARGS((char_u *cmd, int opt)); -int get_real_state __ARGS((void)); -int after_pathsep __ARGS((char_u *b, char_u *p)); -int same_directory __ARGS((char_u *f1, char_u *f2)); -int vim_chdirfile __ARGS((char_u *fname)); -int illegal_slash __ARGS((char *name)); -char_u *parse_shape_opt __ARGS((int what)); -int get_shape_idx __ARGS((int mouse)); -void update_mouseshape __ARGS((int shape_idx)); -int crypt_method_from_string __ARGS((char_u *s)); -int get_crypt_method __ARGS((buf_T *buf)); -void set_crypt_method __ARGS((buf_T *buf, int method)); -void crypt_push_state __ARGS((void)); -void crypt_pop_state __ARGS((void)); -void crypt_encode __ARGS((char_u *from, size_t len, char_u *to)); -void crypt_decode __ARGS((char_u *ptr, long len)); -void crypt_init_keys __ARGS((char_u *passwd)); -void free_crypt_key __ARGS((char_u *key)); -char_u *get_crypt_key __ARGS((int store, int twice)); -void *vim_findfile_init __ARGS((char_u *path, char_u *filename, char_u * - stopdirs, int level, int free_visited, - int find_what, void *search_ctx_arg, - int tagfile, - char_u *rel_fname)); -char_u *vim_findfile_stopdir __ARGS((char_u *buf)); -void vim_findfile_cleanup __ARGS((void *ctx)); -char_u *vim_findfile __ARGS((void *search_ctx_arg)); -void vim_findfile_free_visited __ARGS((void *search_ctx_arg)); -char_u *find_file_in_path __ARGS((char_u *ptr, int len, int options, int first, - char_u *rel_fname)); -char_u *find_directory_in_path __ARGS((char_u *ptr, int len, int options, - char_u *rel_fname)); -char_u *find_file_in_path_option __ARGS((char_u *ptr, int len, int options, - int first, char_u *path_option, - int find_what, char_u *rel_fname, - char_u *suffixes)); -int vim_chdir __ARGS((char_u *new_dir)); -int get_user_name __ARGS((char_u *buf, int len)); -void sort_strings __ARGS((char_u **files, int count)); -int pathcmp __ARGS((const char *p, const char *q, int maxlen)); -int filewritable __ARGS((char_u *fname)); -int emsg3 __ARGS((char_u *s, char_u *a1, char_u *a2)); -int emsgn __ARGS((char_u *s, long n)); -int get2c __ARGS((FILE *fd)); -int get3c __ARGS((FILE *fd)); -int get4c __ARGS((FILE *fd)); -time_t get8ctime __ARGS((FILE *fd)); -char_u *read_string __ARGS((FILE *fd, int cnt)); -int put_bytes __ARGS((FILE *fd, long_u nr, int len)); -void put_time __ARGS((FILE *fd, time_t the_time)); -int has_non_ascii __ARGS((char_u *s)); -/* vim: set ft=c : */ diff --git a/src/proto/move.pro b/src/proto/move.pro deleted file mode 100644 index 595e3b8dd7..0000000000 --- a/src/proto/move.pro +++ /dev/null @@ -1,41 +0,0 @@ -/* move.c */ -void update_topline_redraw __ARGS((void)); -void update_topline __ARGS((void)); -void update_curswant __ARGS((void)); -void check_cursor_moved __ARGS((win_T *wp)); -void changed_window_setting __ARGS((void)); -void changed_window_setting_win __ARGS((win_T *wp)); -void set_topline __ARGS((win_T *wp, linenr_T lnum)); -void changed_cline_bef_curs __ARGS((void)); -void changed_cline_bef_curs_win __ARGS((win_T *wp)); -void changed_line_abv_curs __ARGS((void)); -void changed_line_abv_curs_win __ARGS((win_T *wp)); -void validate_botline __ARGS((void)); -void invalidate_botline __ARGS((void)); -void invalidate_botline_win __ARGS((win_T *wp)); -void approximate_botline_win __ARGS((win_T *wp)); -int cursor_valid __ARGS((void)); -void validate_cursor __ARGS((void)); -void validate_cline_row __ARGS((void)); -void validate_virtcol __ARGS((void)); -void validate_virtcol_win __ARGS((win_T *wp)); -void validate_cursor_col __ARGS((void)); -int win_col_off __ARGS((win_T *wp)); -int curwin_col_off __ARGS((void)); -int win_col_off2 __ARGS((win_T *wp)); -int curwin_col_off2 __ARGS((void)); -void curs_columns __ARGS((int may_scroll)); -void scrolldown __ARGS((long line_count, int byfold)); -void scrollup __ARGS((long line_count, int byfold)); -void check_topfill __ARGS((win_T *wp, int down)); -void scrolldown_clamp __ARGS((void)); -void scrollup_clamp __ARGS((void)); -void scroll_cursor_top __ARGS((int min_scroll, int always)); -void set_empty_rows __ARGS((win_T *wp, int used)); -void scroll_cursor_bot __ARGS((int min_scroll, int set_topbot)); -void scroll_cursor_halfway __ARGS((int atend)); -void cursor_correct __ARGS((void)); -int onepage __ARGS((int dir, long count)); -void halfpage __ARGS((int flag, linenr_T Prenum)); -void do_check_cursorbind __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/normal.pro b/src/proto/normal.pro deleted file mode 100644 index a178751474..0000000000 --- a/src/proto/normal.pro +++ /dev/null @@ -1,29 +0,0 @@ -/* normal.c */ -void init_normal_cmds __ARGS((void)); -void normal_cmd __ARGS((oparg_T *oap, int toplevel)); -void do_pending_operator __ARGS((cmdarg_T *cap, int old_col, int gui_yank)); -int do_mouse __ARGS((oparg_T *oap, int c, int dir, long count, int fixindent)); -void check_visual_highlight __ARGS((void)); -void end_visual_mode __ARGS((void)); -void reset_VIsual_and_resel __ARGS((void)); -void reset_VIsual __ARGS((void)); -int find_ident_under_cursor __ARGS((char_u **string, int find_type)); -int find_ident_at_pos __ARGS((win_T *wp, linenr_T lnum, colnr_T startcol, - char_u **string, - int find_type)); -void clear_showcmd __ARGS((void)); -int add_to_showcmd __ARGS((int c)); -void add_to_showcmd_c __ARGS((int c)); -void push_showcmd __ARGS((void)); -void pop_showcmd __ARGS((void)); -void do_check_scrollbind __ARGS((int check)); -void check_scrollbind __ARGS((linenr_T topline_diff, long leftcol_diff)); -int find_decl __ARGS((char_u *ptr, int len, int locally, int thisblock, - int searchflags)); -void scroll_redraw __ARGS((int up, long count)); -void handle_tabmenu __ARGS((void)); -void do_nv_ident __ARGS((int c1, int c2)); -int get_visual_text __ARGS((cmdarg_T *cap, char_u **pp, int *lenp)); -void start_selection __ARGS((void)); -void may_start_select __ARGS((int c)); -/* vim: set ft=c : */ diff --git a/src/proto/ops.pro b/src/proto/ops.pro deleted file mode 100644 index f69f71ae25..0000000000 --- a/src/proto/ops.pro +++ /dev/null @@ -1,66 +0,0 @@ -/* ops.c */ -int get_op_type __ARGS((int char1, int char2)); -int op_on_lines __ARGS((int op)); -int get_op_char __ARGS((int optype)); -int get_extra_op_char __ARGS((int optype)); -void op_shift __ARGS((oparg_T *oap, int curs_top, int amount)); -void shift_line __ARGS((int left, int round, int amount, int call_changed_bytes)); -void op_reindent __ARGS((oparg_T *oap, int (*how)(void))); -int get_expr_register __ARGS((void)); -void set_expr_line __ARGS((char_u *new_line)); -char_u *get_expr_line __ARGS((void)); -char_u *get_expr_line_src __ARGS((void)); -int valid_yank_reg __ARGS((int regname, int writing)); -void get_yank_register __ARGS((int regname, int writing)); -int may_get_selection __ARGS((int regname)); -void *get_register __ARGS((int name, int copy)); -void put_register __ARGS((int name, void *reg)); -void free_register __ARGS((void *reg)); -int yank_register_mline __ARGS((int regname)); -int do_record __ARGS((int c)); -int do_execreg __ARGS((int regname, int colon, int addcr, int silent)); -int insert_reg __ARGS((int regname, int literally)); -int get_spec_reg __ARGS((int regname, char_u **argp, int *allocated, int errmsg)); -int cmdline_paste_reg __ARGS((int regname, int literally, int remcr)); -void adjust_clip_reg __ARGS((int *rp)); -int op_delete __ARGS((oparg_T *oap)); -int op_replace __ARGS((oparg_T *oap, int c)); -void op_tilde __ARGS((oparg_T *oap)); -int swapchar __ARGS((int op_type, pos_T *pos)); -void op_insert __ARGS((oparg_T *oap, long count1)); -int op_change __ARGS((oparg_T *oap)); -void init_yank __ARGS((void)); -void clear_registers __ARGS((void)); -int op_yank __ARGS((oparg_T *oap, int deleting, int mess)); -void do_put __ARGS((int regname, int dir, long count, int flags)); -void adjust_cursor_eol __ARGS((void)); -int preprocs_left __ARGS((void)); -int get_register_name __ARGS((int num)); -void ex_display __ARGS((exarg_T *eap)); -int do_join __ARGS((long count, int insert_space, int save_undo, - int use_formatoptions)); -void op_format __ARGS((oparg_T *oap, int keep_cursor)); -void op_formatexpr __ARGS((oparg_T *oap)); -int fex_format __ARGS((linenr_T lnum, long count, int c)); -void format_lines __ARGS((linenr_T line_count, int avoid_fex)); -int paragraph_start __ARGS((linenr_T lnum)); -int do_addsub __ARGS((int command, linenr_T Prenum1)); -int read_viminfo_register __ARGS((vir_T *virp, int force)); -void write_viminfo_registers __ARGS((FILE *fp)); -void x11_export_final_selection __ARGS((void)); -void clip_free_selection __ARGS((VimClipboard *cbd)); -void clip_get_selection __ARGS((VimClipboard *cbd)); -void clip_yank_selection __ARGS((int type, char_u *str, long len, - VimClipboard *cbd)); -int clip_convert_selection __ARGS((char_u **str, long_u *len, VimClipboard *cbd)); -void dnd_yank_drag_data __ARGS((char_u *str, long len)); -char_u get_reg_type __ARGS((int regname, long *reglen)); -char_u *get_reg_contents __ARGS((int regname, int allowexpr, int expr_src)); -void write_reg_contents __ARGS((int name, char_u *str, int maxlen, - int must_append)); -void write_reg_contents_ex __ARGS((int name, char_u *str, int maxlen, - int must_append, int yank_type, - long block_len)); -void clear_oparg __ARGS((oparg_T *oap)); -void cursor_pos_info __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/option.pro b/src/proto/option.pro deleted file mode 100644 index 00aa74d34a..0000000000 --- a/src/proto/option.pro +++ /dev/null @@ -1,74 +0,0 @@ -/* option.c */ -void set_init_1 __ARGS((void)); -void set_string_default __ARGS((char *name, char_u *val)); -void set_number_default __ARGS((char *name, long val)); -void free_all_options __ARGS((void)); -void set_init_2 __ARGS((void)); -void set_init_3 __ARGS((void)); -void set_helplang_default __ARGS((char_u *lang)); -void init_gui_options __ARGS((void)); -void set_title_defaults __ARGS((void)); -int do_set __ARGS((char_u *arg, int opt_flags)); -void set_options_bin __ARGS((int oldval, int newval, int opt_flags)); -int get_viminfo_parameter __ARGS((int type)); -char_u *find_viminfo_parameter __ARGS((int type)); -void check_options __ARGS((void)); -void check_buf_options __ARGS((buf_T *buf)); -void free_string_option __ARGS((char_u *p)); -void clear_string_option __ARGS((char_u **pp)); -void set_term_option_alloced __ARGS((char_u **p)); -int was_set_insecurely __ARGS((char_u *opt, int opt_flags)); -void set_string_option_direct __ARGS((char_u *name, int opt_idx, char_u *val, - int opt_flags, - int set_sid)); -char_u *check_colorcolumn __ARGS((win_T *wp)); -char_u *check_stl_option __ARGS((char_u *s)); -int get_option_value __ARGS((char_u *name, long *numval, char_u **stringval, - int opt_flags)); -int get_option_value_strict __ARGS((char_u *name, long *numval, char_u * - *stringval, int opt_type, - void *from)); -char_u *option_iter_next __ARGS((void **option, int opt_type)); -char_u *set_option_value __ARGS((char_u *name, long number, char_u *string, - int opt_flags)); -char_u *get_term_code __ARGS((char_u *tname)); -char_u *get_highlight_default __ARGS((void)); -char_u *get_encoding_default __ARGS((void)); -int makeset __ARGS((FILE *fd, int opt_flags, int local_only)); -int makefoldset __ARGS((FILE *fd)); -void clear_termoptions __ARGS((void)); -void free_termoptions __ARGS((void)); -void free_one_termoption __ARGS((char_u *var)); -void set_term_defaults __ARGS((void)); -void comp_col __ARGS((void)); -void unset_global_local_option __ARGS((char_u *name, void *from)); -char_u *get_equalprg __ARGS((void)); -void win_copy_options __ARGS((win_T *wp_from, win_T *wp_to)); -void copy_winopt __ARGS((winopt_T *from, winopt_T *to)); -void check_win_options __ARGS((win_T *win)); -void check_winopt __ARGS((winopt_T *wop)); -void clear_winopt __ARGS((winopt_T *wop)); -void buf_copy_options __ARGS((buf_T *buf, int flags)); -void reset_modifiable __ARGS((void)); -void set_iminsert_global __ARGS((void)); -void set_imsearch_global __ARGS((void)); -void set_context_in_set_cmd __ARGS((expand_T *xp, char_u *arg, int opt_flags)); -int ExpandSettings __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, - char_u ***file)); -int ExpandOldSetting __ARGS((int *num_file, char_u ***file)); -int langmap_adjust_mb __ARGS((int c)); -int has_format_option __ARGS((int x)); -int shortmess __ARGS((int x)); -void vimrc_found __ARGS((char_u *fname, char_u *envname)); -void change_compatible __ARGS((int on)); -int option_was_set __ARGS((char_u *name)); -void reset_option_was_set __ARGS((char_u *name)); -int can_bs __ARGS((int what)); -void save_file_ff __ARGS((buf_T *buf)); -int file_ff_differs __ARGS((buf_T *buf, int ignore_empty)); -int check_ff_value __ARGS((char_u *p)); -long get_sw_value __ARGS((buf_T *buf)); -long get_sts_value __ARGS((void)); -void find_mps_values __ARGS((int *initc, int *findc, int *backwards, - int switchit)); -/* vim: set ft=c : */ diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro deleted file mode 100644 index 3d03df1eaf..0000000000 --- a/src/proto/os_unix.pro +++ /dev/null @@ -1,75 +0,0 @@ -/* os_unix.c */ -void mch_write __ARGS((char_u *s, int len)); -int mch_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); -int mch_char_avail __ARGS((void)); -void mch_delay __ARGS((long msec, int ignoreinput)); -int mch_stackcheck __ARGS((char *p)); -void mch_startjmp __ARGS((void)); -void mch_endjmp __ARGS((void)); -void mch_didjmp __ARGS((void)); -void mch_suspend __ARGS((void)); -void mch_init __ARGS((void)); -void reset_signals __ARGS((void)); -int vim_handle_signal __ARGS((int sig)); -int mch_check_win __ARGS((int argc, char **argv)); -int mch_input_isatty __ARGS((void)); -int mch_can_restore_title __ARGS((void)); -int mch_can_restore_icon __ARGS((void)); -void mch_settitle __ARGS((char_u *title, char_u *icon)); -void mch_restore_title __ARGS((int which)); -int vim_is_xterm __ARGS((char_u *name)); -int use_xterm_like_mouse __ARGS((char_u *name)); -int use_xterm_mouse __ARGS((void)); -int vim_is_iris __ARGS((char_u *name)); -int vim_is_vt300 __ARGS((char_u *name)); -int vim_is_fastterm __ARGS((char_u *name)); -int mch_get_user_name __ARGS((char_u *s, int len)); -int mch_get_uname __ARGS((uid_t uid, char_u *s, int len)); -void mch_get_host_name __ARGS((char_u *s, int len)); -long mch_get_pid __ARGS((void)); -void slash_adjust __ARGS((char_u *p)); -void fname_case __ARGS((char_u *name, int len)); -long mch_getperm __ARGS((char_u *name)); -int mch_setperm __ARGS((char_u *name, long perm)); -void mch_copy_sec __ARGS((char_u *from_file, char_u *to_file)); -vim_acl_T mch_get_acl __ARGS((char_u *fname)); -void mch_set_acl __ARGS((char_u *fname, vim_acl_T aclent)); -void mch_free_acl __ARGS((vim_acl_T aclent)); -void mch_hide __ARGS((char_u *name)); -int mch_isdir __ARGS((char_u *name)); -int mch_can_exe __ARGS((char_u *name)); -int mch_nodetype __ARGS((char_u *name)); -void mch_early_init __ARGS((void)); -void mch_free_mem __ARGS((void)); -void mch_exit __ARGS((int r)); -void mch_settmode __ARGS((int tmode)); -void get_stty __ARGS((void)); -void mch_setmouse __ARGS((int on)); -void check_mouse_termcode __ARGS((void)); -int mch_screenmode __ARGS((char_u *arg)); -int mch_get_shellsize __ARGS((void)); -void mch_set_shellsize __ARGS((void)); -void mch_new_shellsize __ARGS((void)); -int mch_call_shell __ARGS((char_u *cmd, int options)); -void mch_breakcheck __ARGS((void)); -int mch_expandpath __ARGS((garray_T *gap, char_u *path, int flags)); -int mch_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, - char_u ***file, - int flags)); -int mch_has_exp_wildcard __ARGS((char_u *p)); -int mch_has_wildcard __ARGS((char_u *p)); -int mch_libcall __ARGS((char_u *libname, char_u *funcname, char_u *argstring, - int argint, char_u **string_result, - int *number_result)); -void setup_term_clip __ARGS((void)); -void start_xterm_trace __ARGS((int button)); -void stop_xterm_trace __ARGS((void)); -void clear_xterm_clip __ARGS((void)); -int clip_xterm_own_selection __ARGS((VimClipboard *cbd)); -void clip_xterm_lose_selection __ARGS((VimClipboard *cbd)); -void clip_xterm_request_selection __ARGS((VimClipboard *cbd)); -void clip_xterm_set_selection __ARGS((VimClipboard *cbd)); -int xsmp_handle_requests __ARGS((void)); -void xsmp_init __ARGS((void)); -void xsmp_close __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/popupmnu.pro b/src/proto/popupmnu.pro deleted file mode 100644 index 74a53e2f0e..0000000000 --- a/src/proto/popupmnu.pro +++ /dev/null @@ -1,8 +0,0 @@ -/* popupmnu.c */ -void pum_display __ARGS((pumitem_T *array, int size, int selected)); -void pum_redraw __ARGS((void)); -void pum_undisplay __ARGS((void)); -void pum_clear __ARGS((void)); -int pum_visible __ARGS((void)); -int pum_get_height __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro deleted file mode 100644 index 98d64a7a3f..0000000000 --- a/src/proto/quickfix.pro +++ /dev/null @@ -1,33 +0,0 @@ -/* quickfix.c */ -int qf_init __ARGS((win_T *wp, char_u *efile, char_u *errorformat, int newlist, - char_u *qf_title)); -void qf_free_all __ARGS((win_T *wp)); -void copy_loclist __ARGS((win_T *from, win_T *to)); -void qf_jump __ARGS((qf_info_T *qi, int dir, int errornr, int forceit)); -void qf_list __ARGS((exarg_T *eap)); -void qf_age __ARGS((exarg_T *eap)); -void qf_mark_adjust __ARGS((win_T *wp, linenr_T line1, linenr_T line2, - long amount, - long amount_after)); -void ex_cwindow __ARGS((exarg_T *eap)); -void ex_cclose __ARGS((exarg_T *eap)); -void ex_copen __ARGS((exarg_T *eap)); -linenr_T qf_current_entry __ARGS((win_T *wp)); -int bt_quickfix __ARGS((buf_T *buf)); -int bt_nofile __ARGS((buf_T *buf)); -int bt_dontwrite __ARGS((buf_T *buf)); -int bt_dontwrite_msg __ARGS((buf_T *buf)); -int buf_hide __ARGS((buf_T *buf)); -int grep_internal __ARGS((cmdidx_T cmdidx)); -void ex_make __ARGS((exarg_T *eap)); -void ex_cc __ARGS((exarg_T *eap)); -void ex_cnext __ARGS((exarg_T *eap)); -void ex_cfile __ARGS((exarg_T *eap)); -void ex_vimgrep __ARGS((exarg_T *eap)); -char_u *skip_vimgrep_pat __ARGS((char_u *p, char_u **s, int *flags)); -int get_errorlist __ARGS((win_T *wp, list_T *list)); -int set_errorlist __ARGS((win_T *wp, list_T *list, int action, char_u *title)); -void ex_cbuffer __ARGS((exarg_T *eap)); -void ex_cexpr __ARGS((exarg_T *eap)); -void ex_helpgrep __ARGS((exarg_T *eap)); -/* vim: set ft=c : */ diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro deleted file mode 100644 index b77a8e8ea9..0000000000 --- a/src/proto/regexp.pro +++ /dev/null @@ -1,24 +0,0 @@ -/* regexp.c */ -int re_multiline __ARGS((regprog_T *prog)); -int re_lookbehind __ARGS((regprog_T *prog)); -char_u *skip_regexp __ARGS((char_u *startp, int dirc, int magic, char_u **newp)); -int vim_regcomp_had_eol __ARGS((void)); -void free_regexp_stuff __ARGS((void)); -reg_extmatch_T *ref_extmatch __ARGS((reg_extmatch_T *em)); -void unref_extmatch __ARGS((reg_extmatch_T *em)); -char_u *regtilde __ARGS((char_u *source, int magic)); -int vim_regsub __ARGS((regmatch_T *rmp, char_u *source, char_u *dest, int copy, - int magic, - int backslash)); -int vim_regsub_multi __ARGS((regmmatch_T *rmp, linenr_T lnum, char_u *source, - char_u *dest, int copy, int magic, - int backslash)); -char_u *reg_submatch __ARGS((int no)); -regprog_T *vim_regcomp __ARGS((char_u *expr_arg, int re_flags)); -void vim_regfree __ARGS((regprog_T *prog)); -int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); -int vim_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); -long vim_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, - linenr_T lnum, colnr_T col, - proftime_T *tm)); -/* vim: set ft=c : */ diff --git a/src/proto/screen.pro b/src/proto/screen.pro deleted file mode 100644 index 53a909e242..0000000000 --- a/src/proto/screen.pro +++ /dev/null @@ -1,66 +0,0 @@ -/* screen.c */ -void redraw_later __ARGS((int type)); -void redraw_win_later __ARGS((win_T *wp, int type)); -void redraw_later_clear __ARGS((void)); -void redraw_all_later __ARGS((int type)); -void redraw_curbuf_later __ARGS((int type)); -void redraw_buf_later __ARGS((buf_T *buf, int type)); -int redraw_asap __ARGS((int type)); -void redrawWinline __ARGS((linenr_T lnum, int invalid)); -void update_curbuf __ARGS((int type)); -void update_screen __ARGS((int type)); -int conceal_cursor_line __ARGS((win_T *wp)); -void conceal_check_cursur_line __ARGS((void)); -void update_single_line __ARGS((win_T *wp, linenr_T lnum)); -void update_debug_sign __ARGS((buf_T *buf, linenr_T lnum)); -void updateWindow __ARGS((win_T *wp)); -void rl_mirror __ARGS((char_u *str)); -void status_redraw_all __ARGS((void)); -void status_redraw_curbuf __ARGS((void)); -void redraw_statuslines __ARGS((void)); -void win_redraw_last_status __ARGS((frame_T *frp)); -void win_redr_status_matches __ARGS((expand_T *xp, int num_matches, char_u * - *matches, int match, - int showtail)); -void win_redr_status __ARGS((win_T *wp)); -int stl_connected __ARGS((win_T *wp)); -int get_keymap_str __ARGS((win_T *wp, char_u *buf, int len)); -void screen_putchar __ARGS((int c, int row, int col, int attr)); -void screen_getbytes __ARGS((int row, int col, char_u *bytes, int *attrp)); -void screen_puts __ARGS((char_u *text, int row, int col, int attr)); -void screen_puts_len __ARGS((char_u *text, int len, int row, int col, int attr)); -void screen_stop_highlight __ARGS((void)); -void reset_cterm_colors __ARGS((void)); -void screen_draw_rectangle __ARGS((int row, int col, int height, int width, - int invert)); -void screen_fill __ARGS((int start_row, int end_row, int start_col, int end_col, - int c1, int c2, - int attr)); -void check_for_delay __ARGS((int check_msg_scroll)); -int screen_valid __ARGS((int doclear)); -void screenalloc __ARGS((int doclear)); -void free_screenlines __ARGS((void)); -void screenclear __ARGS((void)); -int can_clear __ARGS((char_u *p)); -void screen_start __ARGS((void)); -void windgoto __ARGS((int row, int col)); -void setcursor __ARGS((void)); -int win_ins_lines __ARGS((win_T *wp, int row, int line_count, int invalid, - int mayclear)); -int win_del_lines __ARGS((win_T *wp, int row, int line_count, int invalid, - int mayclear)); -int screen_ins_lines __ARGS((int off, int row, int line_count, int end, - win_T *wp)); -int screen_del_lines __ARGS((int off, int row, int line_count, int end, - int force, - win_T *wp)); -int showmode __ARGS((void)); -void unshowmode __ARGS((int force)); -void get_trans_bufname __ARGS((buf_T *buf)); -int redrawing __ARGS((void)); -int messaging __ARGS((void)); -void showruler __ARGS((int always)); -int number_width __ARGS((win_T *wp)); -int screen_screencol __ARGS((void)); -int screen_screenrow __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/search.pro b/src/proto/search.pro deleted file mode 100644 index 9c3c520c9f..0000000000 --- a/src/proto/search.pro +++ /dev/null @@ -1,49 +0,0 @@ -/* search.c */ -int search_regcomp __ARGS((char_u *pat, int pat_save, int pat_use, int options, - regmmatch_T *regmatch)); -char_u *get_search_pat __ARGS((void)); -char_u *reverse_text __ARGS((char_u *s)); -void save_search_patterns __ARGS((void)); -void restore_search_patterns __ARGS((void)); -void free_search_patterns __ARGS((void)); -int ignorecase __ARGS((char_u *pat)); -int pat_has_uppercase __ARGS((char_u *pat)); -char_u *last_search_pat __ARGS((void)); -void reset_search_dir __ARGS((void)); -void set_last_search_pat __ARGS((char_u *s, int idx, int magic, int setlast)); -void last_pat_prog __ARGS((regmmatch_T *regmatch)); -int searchit __ARGS((win_T *win, buf_T *buf, pos_T *pos, int dir, char_u *pat, - long count, int options, int pat_use, linenr_T stop_lnum, - proftime_T *tm)); -void set_search_direction __ARGS((int cdir)); -int do_search __ARGS((oparg_T *oap, int dirc, char_u *pat, long count, - int options, - proftime_T *tm)); -int search_for_exact_line __ARGS((buf_T *buf, pos_T *pos, int dir, char_u *pat)); -int searchc __ARGS((cmdarg_T *cap, int t_cmd)); -pos_T *findmatch __ARGS((oparg_T *oap, int initc)); -pos_T *findmatchlimit __ARGS((oparg_T *oap, int initc, int flags, int maxtravel)); -void showmatch __ARGS((int c)); -int findsent __ARGS((int dir, long count)); -int findpar __ARGS((int *pincl, int dir, long count, int what, int both)); -int startPS __ARGS((linenr_T lnum, int para, int both)); -int fwd_word __ARGS((long count, int bigword, int eol)); -int bck_word __ARGS((long count, int bigword, int stop)); -int end_word __ARGS((long count, int bigword, int stop, int empty)); -int bckend_word __ARGS((long count, int bigword, int eol)); -int current_word __ARGS((oparg_T *oap, long count, int include, int bigword)); -int current_sent __ARGS((oparg_T *oap, long count, int include)); -int current_block __ARGS((oparg_T *oap, long count, int include, int what, - int other)); -int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include)); -int current_par __ARGS((oparg_T *oap, long count, int include, int type)); -int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar)); -int current_search __ARGS((long count, int forward)); -int linewhite __ARGS((linenr_T lnum)); -void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, - int skip_comments, int type, long count, - int action, linenr_T start_lnum, - linenr_T end_lnum)); -int read_viminfo_search_pattern __ARGS((vir_T *virp, int force)); -void write_viminfo_search_pattern __ARGS((FILE *fp)); -/* vim: set ft=c : */ diff --git a/src/proto/sha256.pro b/src/proto/sha256.pro deleted file mode 100644 index dca9e37998..0000000000 --- a/src/proto/sha256.pro +++ /dev/null @@ -1,12 +0,0 @@ -/* sha256.c */ -void sha256_start __ARGS((context_sha256_T *ctx)); -void sha256_update __ARGS((context_sha256_T *ctx, char_u *input, - UINT32_T length)); -void sha256_finish __ARGS((context_sha256_T *ctx, char_u digest[32])); -char_u *sha256_bytes __ARGS((char_u *buf, int buf_len, char_u *salt, - int salt_len)); -char_u *sha256_key __ARGS((char_u *buf, char_u *salt, int salt_len)); -int sha256_self_test __ARGS((void)); -void sha2_seed __ARGS((char_u *header, int header_len, char_u *salt, - int salt_len)); -/* vim: set ft=c : */ diff --git a/src/proto/spell.pro b/src/proto/spell.pro deleted file mode 100644 index cba277509e..0000000000 --- a/src/proto/spell.pro +++ /dev/null @@ -1,30 +0,0 @@ -/* spell.c */ -int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, - int docount)); -int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, - hlf_T *attrp)); -void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen)); -char_u *did_set_spelllang __ARGS((win_T *wp)); -void spell_delete_wordlist __ARGS((void)); -void spell_free_all __ARGS((void)); -void spell_reload __ARGS((void)); -int spell_check_msm __ARGS((void)); -void ex_mkspell __ARGS((exarg_T *eap)); -void ex_spell __ARGS((exarg_T *eap)); -void spell_add_word __ARGS((char_u *word, int len, int bad, int idx, int undo)); -void init_spell_chartab __ARGS((void)); -int spell_check_sps __ARGS((void)); -void spell_suggest __ARGS((int count)); -void ex_spellrepall __ARGS((exarg_T *eap)); -void spell_suggest_list __ARGS((garray_T *gap, char_u *word, int maxcount, - int need_cap, - int interactive)); -char_u *eval_soundfold __ARGS((char_u *word)); -void ex_spellinfo __ARGS((exarg_T *eap)); -void ex_spelldump __ARGS((exarg_T *eap)); -void spell_dump_compl __ARGS((char_u *pat, int ic, int *dir, int dumpflags_arg)); -char_u *spell_to_word_end __ARGS((char_u *start, win_T *win)); -int spell_word_start __ARGS((int startcol)); -void spell_expand_check_cap __ARGS((colnr_T col)); -int expand_spelling __ARGS((linenr_T lnum, char_u *pat, char_u ***matchp)); -/* vim: set ft=c : */ diff --git a/src/proto/syntax.pro b/src/proto/syntax.pro deleted file mode 100644 index 0d5f23910f..0000000000 --- a/src/proto/syntax.pro +++ /dev/null @@ -1,58 +0,0 @@ -/* syntax.c */ -void syntax_start __ARGS((win_T *wp, linenr_T lnum)); -void syn_stack_free_all __ARGS((synblock_T *block)); -void syn_stack_apply_changes __ARGS((buf_T *buf)); -void syntax_end_parsing __ARGS((linenr_T lnum)); -int syntax_check_changed __ARGS((linenr_T lnum)); -int get_syntax_attr __ARGS((colnr_T col, int *can_spell, int keep_state)); -void syntax_clear __ARGS((synblock_T *block)); -void reset_synblock __ARGS((win_T *wp)); -void ex_syntax __ARGS((exarg_T *eap)); -void ex_ownsyntax __ARGS((exarg_T *eap)); -int syntax_present __ARGS((win_T *win)); -void reset_expand_highlight __ARGS((void)); -void set_context_in_echohl_cmd __ARGS((expand_T *xp, char_u *arg)); -void set_context_in_syntax_cmd __ARGS((expand_T *xp, char_u *arg)); -char_u *get_syntax_name __ARGS((expand_T *xp, int idx)); -int syn_get_id __ARGS((win_T *wp, long lnum, colnr_T col, int trans, - int *spellp, - int keep_state)); -int get_syntax_info __ARGS((int *seqnrp)); -int syn_get_sub_char __ARGS((void)); -int syn_get_stack_item __ARGS((int i)); -int syn_get_foldlevel __ARGS((win_T *wp, long lnum)); -void ex_syntime __ARGS((exarg_T *eap)); -char_u *get_syntime_arg __ARGS((expand_T *xp, int idx)); -void init_highlight __ARGS((int both, int reset)); -int load_colors __ARGS((char_u *name)); -void do_highlight __ARGS((char_u *line, int forceit, int init)); -void free_highlight __ARGS((void)); -void restore_cterm_colors __ARGS((void)); -void set_normal_colors __ARGS((void)); -char_u *hl_get_font_name __ARGS((void)); -void hl_set_font_name __ARGS((char_u *font_name)); -void hl_set_bg_color_name __ARGS((char_u *name)); -void hl_set_fg_color_name __ARGS((char_u *name)); -void clear_hl_tables __ARGS((void)); -int hl_combine_attr __ARGS((int char_attr, int prim_attr)); -attrentry_T *syn_gui_attr2entry __ARGS((int attr)); -int syn_attr2attr __ARGS((int attr)); -attrentry_T *syn_term_attr2entry __ARGS((int attr)); -attrentry_T *syn_cterm_attr2entry __ARGS((int attr)); -char_u *highlight_has_attr __ARGS((int id, int flag, int modec)); -char_u *highlight_color __ARGS((int id, char_u *what, int modec)); -long_u highlight_gui_color_rgb __ARGS((int id, int fg)); -int syn_name2id __ARGS((char_u *name)); -int highlight_exists __ARGS((char_u *name)); -char_u *syn_id2name __ARGS((int id)); -int syn_namen2id __ARGS((char_u *linep, int len)); -int syn_check_group __ARGS((char_u *pp, int len)); -int syn_id2attr __ARGS((int hl_id)); -int syn_id2colors __ARGS((int hl_id, guicolor_T *fgp, guicolor_T *bgp)); -int syn_get_final_id __ARGS((int hl_id)); -void highlight_gui_started __ARGS((void)); -int highlight_changed __ARGS((void)); -void set_context_in_highlight_cmd __ARGS((expand_T *xp, char_u *arg)); -char_u *get_highlight_name __ARGS((expand_T *xp, int idx)); -void free_highlight_fonts __ARGS((void)); -/* vim: set ft=c : */ diff --git a/src/proto/tag.pro b/src/proto/tag.pro deleted file mode 100644 index fedbc93745..0000000000 --- a/src/proto/tag.pro +++ /dev/null @@ -1,15 +0,0 @@ -/* tag.c */ -int do_tag __ARGS((char_u *tag, int type, int count, int forceit, int verbose)); -void tag_freematch __ARGS((void)); -void do_tags __ARGS((exarg_T *eap)); -int find_tags __ARGS((char_u *pat, int *num_matches, char_u ***matchesp, - int flags, int mincount, - char_u *buf_ffname)); -void free_tag_stuff __ARGS((void)); -int get_tagfname __ARGS((tagname_T *tnp, int first, char_u *buf)); -void tagname_free __ARGS((tagname_T *tnp)); -void simplify_filename __ARGS((char_u *filename)); -int expand_tags __ARGS((int tagnames, char_u *pat, int *num_file, - char_u ***file)); -int get_tags __ARGS((list_T *list, char_u *pat)); -/* vim: set ft=c : */ diff --git a/src/proto/term.pro b/src/proto/term.pro deleted file mode 100644 index 9a348c0a72..0000000000 --- a/src/proto/term.pro +++ /dev/null @@ -1,65 +0,0 @@ -/* term.c */ -int set_termname __ARGS((char_u *term)); -void set_mouse_termcode __ARGS((int n, char_u *s)); -void del_mouse_termcode __ARGS((int n)); -void getlinecol __ARGS((long *cp, long *rp)); -int add_termcap_entry __ARGS((char_u *name, int force)); -int term_is_8bit __ARGS((char_u *name)); -int term_is_gui __ARGS((char_u *name)); -char_u *tltoa __ARGS((unsigned long i)); -void termcapinit __ARGS((char_u *name)); -void out_flush __ARGS((void)); -void out_flush_check __ARGS((void)); -void out_trash __ARGS((void)); -void out_char __ARGS((unsigned c)); -void out_str_nf __ARGS((char_u *s)); -void out_str __ARGS((char_u *s)); -void term_windgoto __ARGS((int row, int col)); -void term_cursor_right __ARGS((int i)); -void term_append_lines __ARGS((int line_count)); -void term_delete_lines __ARGS((int line_count)); -void term_set_winpos __ARGS((int x, int y)); -void term_set_winsize __ARGS((int width, int height)); -void term_fg_color __ARGS((int n)); -void term_bg_color __ARGS((int n)); -void term_settitle __ARGS((char_u *title)); -void ttest __ARGS((int pairs)); -void add_long_to_buf __ARGS((long_u val, char_u *dst)); -void check_shellsize __ARGS((void)); -void limit_screen_size __ARGS((void)); -void win_new_shellsize __ARGS((void)); -void shell_resized __ARGS((void)); -void shell_resized_check __ARGS((void)); -void set_shellsize __ARGS((int width, int height, int mustset)); -void settmode __ARGS((int tmode)); -void starttermcap __ARGS((void)); -void stoptermcap __ARGS((void)); -void may_req_termresponse __ARGS((void)); -void may_req_ambiguous_char_width __ARGS((void)); -int swapping_screen __ARGS((void)); -void setmouse __ARGS((void)); -int mouse_has __ARGS((int c)); -int mouse_model_popup __ARGS((void)); -void scroll_start __ARGS((void)); -void cursor_on __ARGS((void)); -void cursor_off __ARGS((void)); -void term_cursor_shape __ARGS((void)); -void scroll_region_set __ARGS((win_T *wp, int off)); -void scroll_region_reset __ARGS((void)); -void clear_termcodes __ARGS((void)); -void add_termcode __ARGS((char_u *name, char_u *string, int flags)); -char_u *find_termcode __ARGS((char_u *name)); -char_u *get_termcode __ARGS((int i)); -void del_termcode __ARGS((char_u *name)); -void set_mouse_topline __ARGS((win_T *wp)); -int check_termcode __ARGS((int max_offset, char_u *buf, int bufsize, - int *buflen)); -char_u *replace_termcodes __ARGS((char_u *from, char_u **bufp, int from_part, - int do_lt, - int special)); -int find_term_bykeys __ARGS((char_u *src)); -void show_termcodes __ARGS((void)); -int show_one_termcode __ARGS((char_u *name, char_u *code, int printit)); -char_u *translate_mapping __ARGS((char_u *str, int expmap)); -void update_tcap __ARGS((int attr)); -/* vim: set ft=c : */ diff --git a/src/proto/ui.pro b/src/proto/ui.pro deleted file mode 100644 index 2f37fb9dfe..0000000000 --- a/src/proto/ui.pro +++ /dev/null @@ -1,67 +0,0 @@ -/* ui.c */ -void ui_write __ARGS((char_u *s, int len)); -void ui_inchar_undo __ARGS((char_u *s, int len)); -int ui_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); -int ui_char_avail __ARGS((void)); -void ui_delay __ARGS((long msec, int ignoreinput)); -void ui_suspend __ARGS((void)); -void suspend_shell __ARGS((void)); -int ui_get_shellsize __ARGS((void)); -void ui_set_shellsize __ARGS((int mustset)); -void ui_new_shellsize __ARGS((void)); -void ui_breakcheck __ARGS((void)); -void clip_init __ARGS((int can_use)); -void clip_update_selection __ARGS((VimClipboard *clip)); -void clip_own_selection __ARGS((VimClipboard *cbd)); -void clip_lose_selection __ARGS((VimClipboard *cbd)); -void clip_auto_select __ARGS((void)); -int clip_isautosel_star __ARGS((void)); -int clip_isautosel_plus __ARGS((void)); -void clip_modeless __ARGS((int button, int is_click, int is_drag)); -void clip_start_selection __ARGS((int col, int row, int repeated_click)); -void clip_process_selection __ARGS((int button, int col, int row, - int_u repeated_click)); -void clip_may_redraw_selection __ARGS((int row, int col, int len)); -void clip_clear_selection __ARGS((VimClipboard *cbd)); -void clip_may_clear_selection __ARGS((int row1, int row2)); -void clip_scroll_selection __ARGS((int rows)); -void clip_copy_modeless_selection __ARGS((int both)); -int clip_gen_own_selection __ARGS((VimClipboard *cbd)); -void clip_gen_lose_selection __ARGS((VimClipboard *cbd)); -void clip_gen_set_selection __ARGS((VimClipboard *cbd)); -void clip_gen_request_selection __ARGS((VimClipboard *cbd)); -int clip_gen_owner_exists __ARGS((VimClipboard *cbd)); -int vim_is_input_buf_full __ARGS((void)); -int vim_is_input_buf_empty __ARGS((void)); -int vim_free_in_input_buf __ARGS((void)); -int vim_used_in_input_buf __ARGS((void)); -char_u *get_input_buf __ARGS((void)); -void set_input_buf __ARGS((char_u *p)); -void add_to_input_buf __ARGS((char_u *s, int len)); -void add_to_input_buf_csi __ARGS((char_u *str, int len)); -void push_raw_key __ARGS((char_u *s, int len)); -void trash_input_buf __ARGS((void)); -int read_from_input_buf __ARGS((char_u *buf, long maxlen)); -void fill_input_buf __ARGS((int exit_on_error)); -void read_error_exit __ARGS((void)); -void ui_cursor_shape __ARGS((void)); -int check_col __ARGS((int col)); -int check_row __ARGS((int row)); -void open_app_context __ARGS((void)); -void x11_setup_atoms __ARGS((Display *dpy)); -void x11_setup_selection __ARGS((Widget w)); -void clip_x11_request_selection __ARGS((Widget myShell, Display *dpy, - VimClipboard *cbd)); -void clip_x11_lose_selection __ARGS((Widget myShell, VimClipboard *cbd)); -int clip_x11_own_selection __ARGS((Widget myShell, VimClipboard *cbd)); -void clip_x11_set_selection __ARGS((VimClipboard *cbd)); -int clip_x11_owner_exists __ARGS((VimClipboard *cbd)); -void yank_cut_buffer0 __ARGS((Display *dpy, VimClipboard *cbd)); -int jump_to_mouse __ARGS((int flags, int *inclusive, int which_button)); -int mouse_comp_pos __ARGS((win_T *win, int *rowp, int *colp, linenr_T *lnump)); -win_T *mouse_find_win __ARGS((int *rowp, int *colp)); -int get_fpos_of_mouse __ARGS((pos_T *mpos)); -int vcol2col __ARGS((win_T *wp, linenr_T lnum, int vcol)); -void ui_focus_change __ARGS((int in_focus)); -void im_save_status __ARGS((long *psave)); -/* vim: set ft=c : */ diff --git a/src/proto/undo.pro b/src/proto/undo.pro deleted file mode 100644 index dfbb07ac26..0000000000 --- a/src/proto/undo.pro +++ /dev/null @@ -1,31 +0,0 @@ -/* undo.c */ -int u_save_cursor __ARGS((void)); -int u_save __ARGS((linenr_T top, linenr_T bot)); -int u_savesub __ARGS((linenr_T lnum)); -int u_inssub __ARGS((linenr_T lnum)); -int u_savedel __ARGS((linenr_T lnum, long nlines)); -int undo_allowed __ARGS((void)); -int u_savecommon __ARGS((linenr_T top, linenr_T bot, linenr_T newbot, - int reload)); -void u_compute_hash __ARGS((char_u *hash)); -char_u *u_get_undo_file_name __ARGS((char_u *buf_ffname, int reading)); -void u_write_undo __ARGS((char_u *name, int forceit, buf_T *buf, char_u *hash)); -void u_read_undo __ARGS((char_u *name, char_u *hash, char_u *orig_name)); -void u_undo __ARGS((int count)); -void u_redo __ARGS((int count)); -void undo_time __ARGS((long step, int sec, int file, int absolute)); -void u_sync __ARGS((int force)); -void ex_undolist __ARGS((exarg_T *eap)); -void ex_undojoin __ARGS((exarg_T *eap)); -void u_unchanged __ARGS((buf_T *buf)); -void u_find_first_changed __ARGS((void)); -void u_update_save_nr __ARGS((buf_T *buf)); -void u_clearall __ARGS((buf_T *buf)); -void u_saveline __ARGS((linenr_T lnum)); -void u_clearline __ARGS((void)); -void u_undoline __ARGS((void)); -void u_blockfree __ARGS((buf_T *buf)); -int bufIsChanged __ARGS((buf_T *buf)); -int curbufIsChanged __ARGS((void)); -void u_eval_tree __ARGS((u_header_T *first_uhp, list_T *list)); -/* vim: set ft=c : */ diff --git a/src/proto/version.pro b/src/proto/version.pro deleted file mode 100644 index e6fb78f069..0000000000 --- a/src/proto/version.pro +++ /dev/null @@ -1,10 +0,0 @@ -/* version.c */ -void make_version __ARGS((void)); -int highest_patch __ARGS((void)); -int has_patch __ARGS((int n)); -void ex_version __ARGS((exarg_T *eap)); -void list_version __ARGS((void)); -void maybe_intro_message __ARGS((void)); -void intro_message __ARGS((int colon)); -void ex_intro __ARGS((exarg_T *eap)); -/* vim: set ft=c : */ diff --git a/src/proto/window.pro b/src/proto/window.pro deleted file mode 100644 index bf82ca1982..0000000000 --- a/src/proto/window.pro +++ /dev/null @@ -1,93 +0,0 @@ -/* window.c */ -void do_window __ARGS((int nchar, long Prenum, int xchar)); -int win_split __ARGS((int size, int flags)); -int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir)); -int win_valid __ARGS((win_T *win)); -int win_count __ARGS((void)); -int make_windows __ARGS((int count, int vertical)); -void win_move_after __ARGS((win_T *win1, win_T *win2)); -void win_equal __ARGS((win_T *next_curwin, int current, int dir)); -void close_windows __ARGS((buf_T *buf, int keep_curwin)); -int one_window __ARGS((void)); -int win_close __ARGS((win_T *win, int free_buf)); -void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp)); -void win_free_all __ARGS((void)); -win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp)); -void close_others __ARGS((int message, int forceit)); -void curwin_init __ARGS((void)); -void win_init_empty __ARGS((win_T *wp)); -int win_alloc_first __ARGS((void)); -void win_alloc_aucmd_win __ARGS((void)); -void win_init_size __ARGS((void)); -void free_tabpage __ARGS((tabpage_T *tp)); -int win_new_tabpage __ARGS((int after)); -int may_open_tabpage __ARGS((void)); -int make_tabpages __ARGS((int maxcount)); -int valid_tabpage __ARGS((tabpage_T *tpc)); -tabpage_T *find_tabpage __ARGS((int n)); -int tabpage_index __ARGS((tabpage_T *ftp)); -void goto_tabpage __ARGS((int n)); -void goto_tabpage_tp __ARGS((tabpage_T *tp, int trigger_enter_autocmds, - int trigger_leave_autocmds)); -void goto_tabpage_win __ARGS((tabpage_T *tp, win_T *wp)); -void tabpage_move __ARGS((int nr)); -void win_goto __ARGS((win_T *wp)); -win_T *win_find_nr __ARGS((int winnr)); -tabpage_T *win_find_tabpage __ARGS((win_T *win)); -void win_enter __ARGS((win_T *wp, int undo_sync)); -win_T *buf_jump_open_win __ARGS((buf_T *buf)); -win_T *buf_jump_open_tab __ARGS((buf_T *buf)); -void win_append __ARGS((win_T *after, win_T *wp)); -void win_remove __ARGS((win_T *wp, tabpage_T *tp)); -int win_alloc_lines __ARGS((win_T *wp)); -void win_free_lsize __ARGS((win_T *wp)); -void shell_new_rows __ARGS((void)); -void shell_new_columns __ARGS((void)); -void win_size_save __ARGS((garray_T *gap)); -void win_size_restore __ARGS((garray_T *gap)); -int win_comp_pos __ARGS((void)); -void win_setheight __ARGS((int height)); -void win_setheight_win __ARGS((int height, win_T *win)); -void win_setwidth __ARGS((int width)); -void win_setwidth_win __ARGS((int width, win_T *wp)); -void win_setminheight __ARGS((void)); -void win_drag_status_line __ARGS((win_T *dragwin, int offset)); -void win_drag_vsep_line __ARGS((win_T *dragwin, int offset)); -void win_new_height __ARGS((win_T *wp, int height)); -void win_new_width __ARGS((win_T *wp, int width)); -void win_comp_scroll __ARGS((win_T *wp)); -void command_height __ARGS((void)); -void last_status __ARGS((int morewin)); -int tabline_height __ARGS((void)); -char_u *grab_file_name __ARGS((long count, linenr_T *file_lnum)); -char_u *file_name_at_cursor __ARGS((int options, long count, - linenr_T *file_lnum)); -char_u *file_name_in_line __ARGS((char_u *line, int col, int options, - long count, char_u *rel_fname, - linenr_T *file_lnum)); -char_u *find_file_name_in_path __ARGS((char_u *ptr, int len, int options, - long count, - char_u *rel_fname)); -int path_with_url __ARGS((char_u *fname)); -int vim_isAbsName __ARGS((char_u *name)); -int vim_FullName __ARGS((char_u *fname, char_u *buf, int len, int force)); -int min_rows __ARGS((void)); -int only_one_window __ARGS((void)); -void check_lnums __ARGS((int do_curwin)); -void make_snapshot __ARGS((int idx)); -void restore_snapshot __ARGS((int idx, int close_curwin)); -int switch_win __ARGS((win_T **save_curwin, tabpage_T **save_curtab, win_T *win, - tabpage_T *tp, - int no_display)); -void restore_win __ARGS((win_T *save_curwin, tabpage_T *save_curtab, - int no_display)); -void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf)); -void restore_buffer __ARGS((buf_T *save_curbuf)); -int win_hasvertsplit __ARGS((void)); -int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id)); -int match_delete __ARGS((win_T *wp, int id, int perr)); -void clear_matches __ARGS((win_T *wp)); -matchitem_T *get_match __ARGS((win_T *wp, int id)); -int get_win_number __ARGS((win_T *wp, win_T *first_win)); -int get_tab_number __ARGS((tabpage_T *tp)); -/* vim: set ft=c : */ diff --git a/src/quickfix.c b/src/quickfix.c index a141d9834b..af134d19f9 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -12,6 +12,34 @@ */ #include "vim.h" +#include "quickfix.h" +#include "buffer.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "term.h" +#include "ui.h" +#include "window.h" #include "os/os.h" diff --git a/src/quickfix.h b/src/quickfix.h new file mode 100644 index 0000000000..949d60bd73 --- /dev/null +++ b/src/quickfix.h @@ -0,0 +1,36 @@ +#ifndef NEOVIM_QUICKFIX_H +#define NEOVIM_QUICKFIX_H +/* quickfix.c */ +int qf_init __ARGS((win_T *wp, char_u *efile, char_u *errorformat, int newlist, + char_u *qf_title)); +void qf_free_all __ARGS((win_T *wp)); +void copy_loclist __ARGS((win_T *from, win_T *to)); +void qf_jump __ARGS((qf_info_T *qi, int dir, int errornr, int forceit)); +void qf_list __ARGS((exarg_T *eap)); +void qf_age __ARGS((exarg_T *eap)); +void qf_mark_adjust __ARGS((win_T *wp, linenr_T line1, linenr_T line2, + long amount, + long amount_after)); +void ex_cwindow __ARGS((exarg_T *eap)); +void ex_cclose __ARGS((exarg_T *eap)); +void ex_copen __ARGS((exarg_T *eap)); +linenr_T qf_current_entry __ARGS((win_T *wp)); +int bt_quickfix __ARGS((buf_T *buf)); +int bt_nofile __ARGS((buf_T *buf)); +int bt_dontwrite __ARGS((buf_T *buf)); +int bt_dontwrite_msg __ARGS((buf_T *buf)); +int buf_hide __ARGS((buf_T *buf)); +int grep_internal __ARGS((cmdidx_T cmdidx)); +void ex_make __ARGS((exarg_T *eap)); +void ex_cc __ARGS((exarg_T *eap)); +void ex_cnext __ARGS((exarg_T *eap)); +void ex_cfile __ARGS((exarg_T *eap)); +void ex_vimgrep __ARGS((exarg_T *eap)); +char_u *skip_vimgrep_pat __ARGS((char_u *p, char_u **s, int *flags)); +int get_errorlist __ARGS((win_T *wp, list_T *list)); +int set_errorlist __ARGS((win_T *wp, list_T *list, int action, char_u *title)); +void ex_cbuffer __ARGS((exarg_T *eap)); +void ex_cexpr __ARGS((exarg_T *eap)); +void ex_helpgrep __ARGS((exarg_T *eap)); +/* vim: set ft=c : */ +#endif /* NEOVIM_QUICKFIX_H */ diff --git a/src/regexp.c b/src/regexp.c index de98543a11..3641f16cdb 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -45,6 +45,15 @@ /* #define REGEXP_DEBUG */ #include "vim.h" +#include "regexp.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "mark.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" #ifdef REGEXP_DEBUG /* show/save debugging data when BT engine is used */ @@ -56,7 +65,7 @@ #endif /* - * The "internal use only" fields in regexp.h are present to pass info from + * The "internal use only" fields in regexp_defs.h are present to pass info from * compile to execute that permits the execute phase to run lots faster on * simple cases. They are: * diff --git a/src/regexp.h b/src/regexp.h index 0426f242a4..a843983e3c 100644 --- a/src/regexp.h +++ b/src/regexp.h @@ -1,152 +1,27 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE - * - * This is NOT the original regular expression code as written by Henry - * Spencer. This code has been modified specifically for use with Vim, and - * should not be used apart from compiling Vim. If you want a good regular - * expression library, get the original code. - * - * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE - */ - -#ifndef _REGEXP_H -#define _REGEXP_H - -/* - * The number of sub-matches is limited to 10. - * The first one (index 0) is the whole match, referenced with "\0". - * The second one (index 1) is the first sub-match, referenced with "\1". - * This goes up to the tenth (index 9), referenced with "\9". - */ -#define NSUBEXP 10 - -/* - * In the NFA engine: how many braces are allowed. - * TODO(RE): Use dynamic memory allocation instead of static, like here - */ -#define NFA_MAX_BRACES 20 - -typedef struct regengine regengine_T; - -/* - * Structure returned by vim_regcomp() to pass on to vim_regexec(). - * This is the general structure. For the actual matcher, two specific - * structures are used. See code below. - */ -typedef struct regprog { - regengine_T *engine; - unsigned regflags; -} regprog_T; - -/* - * Structure used by the back track matcher. - * These fields are only to be used in regexp.c! - * See regexp.c for an explanation. - */ -typedef struct { - /* These two members implement regprog_T */ - regengine_T *engine; - unsigned regflags; - - int regstart; - char_u reganch; - char_u *regmust; - int regmlen; - char_u reghasz; - char_u program[1]; /* actually longer.. */ -} bt_regprog_T; - -/* - * Structure representing a NFA state. - * A NFA state may have no outgoing edge, when it is a NFA_MATCH state. - */ -typedef struct nfa_state nfa_state_T; -struct nfa_state { - int c; - nfa_state_T *out; - nfa_state_T *out1; - int id; - int lastlist[2]; /* 0: normal, 1: recursive */ - int val; -}; - -/* - * Structure used by the NFA matcher. - */ -typedef struct { - /* These two members implement regprog_T */ - regengine_T *engine; - unsigned regflags; - - nfa_state_T *start; /* points into state[] */ - - int reganch; /* pattern starts with ^ */ - int regstart; /* char at start of pattern */ - char_u *match_text; /* plain text to match with */ - - int has_zend; /* pattern contains \ze */ - int has_backref; /* pattern contains \1 .. \9 */ - int reghasz; -#ifdef DEBUG - char_u *pattern; -#endif - int nsubexp; /* number of () */ - int nstate; - nfa_state_T state[1]; /* actually longer.. */ -} nfa_regprog_T; - -/* - * Structure to be used for single-line matching. - * Sub-match "no" starts at "startp[no]" and ends just before "endp[no]". - * When there is no match, the pointer is NULL. - */ -typedef struct { - regprog_T *regprog; - char_u *startp[NSUBEXP]; - char_u *endp[NSUBEXP]; - int rm_ic; -} regmatch_T; - -/* - * Structure to be used for multi-line matching. - * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" - * and ends in line "endpos[no].lnum" just before column "endpos[no].col". - * The line numbers are relative to the first line, thus startpos[0].lnum is - * always 0. - * When there is no match, the line number is -1. - */ -typedef struct { - regprog_T *regprog; - lpos_T startpos[NSUBEXP]; - lpos_T endpos[NSUBEXP]; - int rmm_ic; - colnr_T rmm_maxcol; /* when not zero: maximum column */ -} regmmatch_T; - -/* - * Structure used to store external references: "\z\(\)" to "\z\1". - * Use a reference count to avoid the need to copy this around. When it goes - * from 1 to zero the matches need to be freed. - */ -typedef struct { - short refcnt; - char_u *matches[NSUBEXP]; -} reg_extmatch_T; - -struct regengine { - regprog_T *(*regcomp)(char_u*, int); - void (*regfree)(regprog_T *); - int (*regexec)(regmatch_T*, char_u*, colnr_T); -#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \ - || defined(FIND_REPLACE_DIALOG) || defined(PROTO) - int (*regexec_nl)(regmatch_T*, char_u*, colnr_T); -#endif - long (*regexec_multi)(regmmatch_T*, win_T*, buf_T*, linenr_T, colnr_T, - proftime_T*); -#ifdef DEBUG - char_u *expr; -#endif -}; - -#endif /* _REGEXP_H */ +#ifndef NEOVIM_REGEXP_H +#define NEOVIM_REGEXP_H +/* regexp.c */ +int re_multiline __ARGS((regprog_T *prog)); +int re_lookbehind __ARGS((regprog_T *prog)); +char_u *skip_regexp __ARGS((char_u *startp, int dirc, int magic, char_u **newp)); +int vim_regcomp_had_eol __ARGS((void)); +void free_regexp_stuff __ARGS((void)); +reg_extmatch_T *ref_extmatch __ARGS((reg_extmatch_T *em)); +void unref_extmatch __ARGS((reg_extmatch_T *em)); +char_u *regtilde __ARGS((char_u *source, int magic)); +int vim_regsub __ARGS((regmatch_T *rmp, char_u *source, char_u *dest, int copy, + int magic, + int backslash)); +int vim_regsub_multi __ARGS((regmmatch_T *rmp, linenr_T lnum, char_u *source, + char_u *dest, int copy, int magic, + int backslash)); +char_u *reg_submatch __ARGS((int no)); +regprog_T *vim_regcomp __ARGS((char_u *expr_arg, int re_flags)); +void vim_regfree __ARGS((regprog_T *prog)); +int vim_regexec __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); +int vim_regexec_nl __ARGS((regmatch_T *rmp, char_u *line, colnr_T col)); +long vim_regexec_multi __ARGS((regmmatch_T *rmp, win_T *win, buf_T *buf, + linenr_T lnum, colnr_T col, + proftime_T *tm)); +/* vim: set ft=c : */ +#endif /* NEOVIM_REGEXP_H */ diff --git a/src/regexp_defs.h b/src/regexp_defs.h new file mode 100644 index 0000000000..0426f242a4 --- /dev/null +++ b/src/regexp_defs.h @@ -0,0 +1,152 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE + * + * This is NOT the original regular expression code as written by Henry + * Spencer. This code has been modified specifically for use with Vim, and + * should not be used apart from compiling Vim. If you want a good regular + * expression library, get the original code. + * + * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE + */ + +#ifndef _REGEXP_H +#define _REGEXP_H + +/* + * The number of sub-matches is limited to 10. + * The first one (index 0) is the whole match, referenced with "\0". + * The second one (index 1) is the first sub-match, referenced with "\1". + * This goes up to the tenth (index 9), referenced with "\9". + */ +#define NSUBEXP 10 + +/* + * In the NFA engine: how many braces are allowed. + * TODO(RE): Use dynamic memory allocation instead of static, like here + */ +#define NFA_MAX_BRACES 20 + +typedef struct regengine regengine_T; + +/* + * Structure returned by vim_regcomp() to pass on to vim_regexec(). + * This is the general structure. For the actual matcher, two specific + * structures are used. See code below. + */ +typedef struct regprog { + regengine_T *engine; + unsigned regflags; +} regprog_T; + +/* + * Structure used by the back track matcher. + * These fields are only to be used in regexp.c! + * See regexp.c for an explanation. + */ +typedef struct { + /* These two members implement regprog_T */ + regengine_T *engine; + unsigned regflags; + + int regstart; + char_u reganch; + char_u *regmust; + int regmlen; + char_u reghasz; + char_u program[1]; /* actually longer.. */ +} bt_regprog_T; + +/* + * Structure representing a NFA state. + * A NFA state may have no outgoing edge, when it is a NFA_MATCH state. + */ +typedef struct nfa_state nfa_state_T; +struct nfa_state { + int c; + nfa_state_T *out; + nfa_state_T *out1; + int id; + int lastlist[2]; /* 0: normal, 1: recursive */ + int val; +}; + +/* + * Structure used by the NFA matcher. + */ +typedef struct { + /* These two members implement regprog_T */ + regengine_T *engine; + unsigned regflags; + + nfa_state_T *start; /* points into state[] */ + + int reganch; /* pattern starts with ^ */ + int regstart; /* char at start of pattern */ + char_u *match_text; /* plain text to match with */ + + int has_zend; /* pattern contains \ze */ + int has_backref; /* pattern contains \1 .. \9 */ + int reghasz; +#ifdef DEBUG + char_u *pattern; +#endif + int nsubexp; /* number of () */ + int nstate; + nfa_state_T state[1]; /* actually longer.. */ +} nfa_regprog_T; + +/* + * Structure to be used for single-line matching. + * Sub-match "no" starts at "startp[no]" and ends just before "endp[no]". + * When there is no match, the pointer is NULL. + */ +typedef struct { + regprog_T *regprog; + char_u *startp[NSUBEXP]; + char_u *endp[NSUBEXP]; + int rm_ic; +} regmatch_T; + +/* + * Structure to be used for multi-line matching. + * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col" + * and ends in line "endpos[no].lnum" just before column "endpos[no].col". + * The line numbers are relative to the first line, thus startpos[0].lnum is + * always 0. + * When there is no match, the line number is -1. + */ +typedef struct { + regprog_T *regprog; + lpos_T startpos[NSUBEXP]; + lpos_T endpos[NSUBEXP]; + int rmm_ic; + colnr_T rmm_maxcol; /* when not zero: maximum column */ +} regmmatch_T; + +/* + * Structure used to store external references: "\z\(\)" to "\z\1". + * Use a reference count to avoid the need to copy this around. When it goes + * from 1 to zero the matches need to be freed. + */ +typedef struct { + short refcnt; + char_u *matches[NSUBEXP]; +} reg_extmatch_T; + +struct regengine { + regprog_T *(*regcomp)(char_u*, int); + void (*regfree)(regprog_T *); + int (*regexec)(regmatch_T*, char_u*, colnr_T); +#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) \ + || defined(FIND_REPLACE_DIALOG) || defined(PROTO) + int (*regexec_nl)(regmatch_T*, char_u*, colnr_T); +#endif + long (*regexec_multi)(regmmatch_T*, win_T*, buf_T*, linenr_T, colnr_T, + proftime_T*); +#ifdef DEBUG + char_u *expr; +#endif +}; + +#endif /* _REGEXP_H */ diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index 50e193924a..75deff1b3e 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -5,6 +5,8 @@ * This file is included in "regexp.c". */ +#include "misc2.h" + /* * Logging of NFA engine. * diff --git a/src/screen.c b/src/screen.c index 3f544ad423..293a41b9c6 100644 --- a/src/screen.c +++ b/src/screen.c @@ -88,6 +88,37 @@ */ #include "vim.h" +#include "screen.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mbyte.h" +#include "memline.h" +#include "menu.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "popupmnu.h" +#include "quickfix.h" +#include "regexp.h" +#include "search.h" +#include "spell.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" +#include "undo.h" +#include "version.h" +#include "window.h" #define MB_FILLER_CHAR '<' /* character used when a double-width character * doesn't fit. */ diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000000..2f25798757 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,69 @@ +#ifndef NEOVIM_SCREEN_H +#define NEOVIM_SCREEN_H +/* screen.c */ +void redraw_later __ARGS((int type)); +void redraw_win_later __ARGS((win_T *wp, int type)); +void redraw_later_clear __ARGS((void)); +void redraw_all_later __ARGS((int type)); +void redraw_curbuf_later __ARGS((int type)); +void redraw_buf_later __ARGS((buf_T *buf, int type)); +int redraw_asap __ARGS((int type)); +void redrawWinline __ARGS((linenr_T lnum, int invalid)); +void update_curbuf __ARGS((int type)); +void update_screen __ARGS((int type)); +int conceal_cursor_line __ARGS((win_T *wp)); +void conceal_check_cursur_line __ARGS((void)); +void update_single_line __ARGS((win_T *wp, linenr_T lnum)); +void update_debug_sign __ARGS((buf_T *buf, linenr_T lnum)); +void updateWindow __ARGS((win_T *wp)); +void rl_mirror __ARGS((char_u *str)); +void status_redraw_all __ARGS((void)); +void status_redraw_curbuf __ARGS((void)); +void redraw_statuslines __ARGS((void)); +void win_redraw_last_status __ARGS((frame_T *frp)); +void win_redr_status_matches __ARGS((expand_T *xp, int num_matches, char_u * + *matches, int match, + int showtail)); +void win_redr_status __ARGS((win_T *wp)); +int stl_connected __ARGS((win_T *wp)); +int get_keymap_str __ARGS((win_T *wp, char_u *buf, int len)); +void screen_putchar __ARGS((int c, int row, int col, int attr)); +void screen_getbytes __ARGS((int row, int col, char_u *bytes, int *attrp)); +void screen_puts __ARGS((char_u *text, int row, int col, int attr)); +void screen_puts_len __ARGS((char_u *text, int len, int row, int col, int attr)); +void screen_stop_highlight __ARGS((void)); +void reset_cterm_colors __ARGS((void)); +void screen_draw_rectangle __ARGS((int row, int col, int height, int width, + int invert)); +void screen_fill __ARGS((int start_row, int end_row, int start_col, int end_col, + int c1, int c2, + int attr)); +void check_for_delay __ARGS((int check_msg_scroll)); +int screen_valid __ARGS((int doclear)); +void screenalloc __ARGS((int doclear)); +void free_screenlines __ARGS((void)); +void screenclear __ARGS((void)); +int can_clear __ARGS((char_u *p)); +void screen_start __ARGS((void)); +void windgoto __ARGS((int row, int col)); +void setcursor __ARGS((void)); +int win_ins_lines __ARGS((win_T *wp, int row, int line_count, int invalid, + int mayclear)); +int win_del_lines __ARGS((win_T *wp, int row, int line_count, int invalid, + int mayclear)); +int screen_ins_lines __ARGS((int off, int row, int line_count, int end, + win_T *wp)); +int screen_del_lines __ARGS((int off, int row, int line_count, int end, + int force, + win_T *wp)); +int showmode __ARGS((void)); +void unshowmode __ARGS((int force)); +void get_trans_bufname __ARGS((buf_T *buf)); +int redrawing __ARGS((void)); +int messaging __ARGS((void)); +void showruler __ARGS((int always)); +int number_width __ARGS((win_T *wp)); +int screen_screencol __ARGS((void)); +int screen_screenrow __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_SCREEN_H */ diff --git a/src/search.c b/src/search.c index a46637efdb..7c89b775d0 100644 --- a/src/search.c +++ b/src/search.c @@ -11,6 +11,31 @@ */ #include "vim.h" +#include "search.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "main.h" +#include "mark.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "regexp.h" +#include "screen.h" +#include "term.h" +#include "ui.h" +#include "window.h" static void save_re_pat __ARGS((int idx, char_u *pat, int magic)); static void set_vv_searchforward __ARGS((void)); diff --git a/src/search.h b/src/search.h new file mode 100644 index 0000000000..b24d2aa69a --- /dev/null +++ b/src/search.h @@ -0,0 +1,52 @@ +#ifndef NEOVIM_SEARCH_H +#define NEOVIM_SEARCH_H +/* search.c */ +int search_regcomp __ARGS((char_u *pat, int pat_save, int pat_use, int options, + regmmatch_T *regmatch)); +char_u *get_search_pat __ARGS((void)); +char_u *reverse_text __ARGS((char_u *s)); +void save_search_patterns __ARGS((void)); +void restore_search_patterns __ARGS((void)); +void free_search_patterns __ARGS((void)); +int ignorecase __ARGS((char_u *pat)); +int pat_has_uppercase __ARGS((char_u *pat)); +char_u *last_search_pat __ARGS((void)); +void reset_search_dir __ARGS((void)); +void set_last_search_pat __ARGS((char_u *s, int idx, int magic, int setlast)); +void last_pat_prog __ARGS((regmmatch_T *regmatch)); +int searchit __ARGS((win_T *win, buf_T *buf, pos_T *pos, int dir, char_u *pat, + long count, int options, int pat_use, linenr_T stop_lnum, + proftime_T *tm)); +void set_search_direction __ARGS((int cdir)); +int do_search __ARGS((oparg_T *oap, int dirc, char_u *pat, long count, + int options, + proftime_T *tm)); +int search_for_exact_line __ARGS((buf_T *buf, pos_T *pos, int dir, char_u *pat)); +int searchc __ARGS((cmdarg_T *cap, int t_cmd)); +pos_T *findmatch __ARGS((oparg_T *oap, int initc)); +pos_T *findmatchlimit __ARGS((oparg_T *oap, int initc, int flags, int maxtravel)); +void showmatch __ARGS((int c)); +int findsent __ARGS((int dir, long count)); +int findpar __ARGS((int *pincl, int dir, long count, int what, int both)); +int startPS __ARGS((linenr_T lnum, int para, int both)); +int fwd_word __ARGS((long count, int bigword, int eol)); +int bck_word __ARGS((long count, int bigword, int stop)); +int end_word __ARGS((long count, int bigword, int stop, int empty)); +int bckend_word __ARGS((long count, int bigword, int eol)); +int current_word __ARGS((oparg_T *oap, long count, int include, int bigword)); +int current_sent __ARGS((oparg_T *oap, long count, int include)); +int current_block __ARGS((oparg_T *oap, long count, int include, int what, + int other)); +int current_tagblock __ARGS((oparg_T *oap, long count_arg, int include)); +int current_par __ARGS((oparg_T *oap, long count, int include, int type)); +int current_quote __ARGS((oparg_T *oap, long count, int include, int quotechar)); +int current_search __ARGS((long count, int forward)); +int linewhite __ARGS((linenr_T lnum)); +void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, + int skip_comments, int type, long count, + int action, linenr_T start_lnum, + linenr_T end_lnum)); +int read_viminfo_search_pattern __ARGS((vir_T *virp, int force)); +void write_viminfo_search_pattern __ARGS((FILE *fp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_SEARCH_H */ diff --git a/src/sha256.c b/src/sha256.c index 16ee6cfad0..bc2be2678f 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -21,7 +21,7 @@ */ #include "vim.h" - +#include "sha256.h" static void sha256_process __ARGS((context_sha256_T *ctx, char_u data[64])); diff --git a/src/sha256.h b/src/sha256.h new file mode 100644 index 0000000000..03e8aa6bea --- /dev/null +++ b/src/sha256.h @@ -0,0 +1,15 @@ +#ifndef NEOVIM_SHA256_H +#define NEOVIM_SHA256_H +/* sha256.c */ +void sha256_start __ARGS((context_sha256_T *ctx)); +void sha256_update __ARGS((context_sha256_T *ctx, char_u *input, + UINT32_T length)); +void sha256_finish __ARGS((context_sha256_T *ctx, char_u digest[32])); +char_u *sha256_bytes __ARGS((char_u *buf, int buf_len, char_u *salt, + int salt_len)); +char_u *sha256_key __ARGS((char_u *buf, char_u *salt, int salt_len)); +int sha256_self_test __ARGS((void)); +void sha2_seed __ARGS((char_u *header, int header_len, char_u *salt, + int salt_len)); +/* vim: set ft=c : */ +#endif /* NEOVIM_SHA256_H */ diff --git a/src/spell.c b/src/spell.c index 941ac08b05..3fae72ffd2 100644 --- a/src/spell.c +++ b/src/spell.c @@ -298,9 +298,34 @@ */ #include "vim.h" - - -#ifndef UNIX /* it's in os_unix.h for Unix */ +#include "spell.h" +#include "buffer.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "fileio.h" +#include "getchar.h" +#include "hashtab.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "syntax.h" +#include "term.h" +#include "ui.h" +#include "undo.h" + +#ifndef UNIX /* it's in os_unix_defs.h for Unix */ # include /* for time_t */ #endif diff --git a/src/spell.h b/src/spell.h new file mode 100644 index 0000000000..8a349300a3 --- /dev/null +++ b/src/spell.h @@ -0,0 +1,33 @@ +#ifndef NEOVIM_SPELL_H +#define NEOVIM_SPELL_H +/* spell.c */ +int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, + int docount)); +int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, + hlf_T *attrp)); +void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen)); +char_u *did_set_spelllang __ARGS((win_T *wp)); +void spell_delete_wordlist __ARGS((void)); +void spell_free_all __ARGS((void)); +void spell_reload __ARGS((void)); +int spell_check_msm __ARGS((void)); +void ex_mkspell __ARGS((exarg_T *eap)); +void ex_spell __ARGS((exarg_T *eap)); +void spell_add_word __ARGS((char_u *word, int len, int bad, int idx, int undo)); +void init_spell_chartab __ARGS((void)); +int spell_check_sps __ARGS((void)); +void spell_suggest __ARGS((int count)); +void ex_spellrepall __ARGS((exarg_T *eap)); +void spell_suggest_list __ARGS((garray_T *gap, char_u *word, int maxcount, + int need_cap, + int interactive)); +char_u *eval_soundfold __ARGS((char_u *word)); +void ex_spellinfo __ARGS((exarg_T *eap)); +void ex_spelldump __ARGS((exarg_T *eap)); +void spell_dump_compl __ARGS((char_u *pat, int ic, int *dir, int dumpflags_arg)); +char_u *spell_to_word_end __ARGS((char_u *start, win_T *win)); +int spell_word_start __ARGS((int startcol)); +void spell_expand_check_cap __ARGS((colnr_T col)); +int expand_spelling __ARGS((linenr_T lnum, char_u *pat, char_u ***matchp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_SPELL_H */ diff --git a/src/structs.h b/src/structs.h index c29848a9af..639d50f674 100644 --- a/src/structs.h +++ b/src/structs.h @@ -56,9 +56,9 @@ typedef int scid_T; /* script ID */ typedef struct file_buffer buf_T; /* forward declaration */ /* - * This is here because regexp.h needs pos_T and below regprog_T is used. + * This is here because regexp_defs.h needs pos_T and below regprog_T is used. */ -#include "regexp.h" +#include "regexp_defs.h" /* * This is here because gui.h needs the pos_T and win_T, and win_T needs gui.h diff --git a/src/syntax.c b/src/syntax.c index e576185b7d..4b22137fda 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -12,6 +12,25 @@ */ #include "vim.h" +#include "syntax.h" +#include "charset.h" +#include "eval.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "fileio.h" +#include "fold.h" +#include "hashtab.h" +#include "mbyte.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "os_unix.h" +#include "regexp.h" +#include "screen.h" +#include "term.h" +#include "ui.h" #include "os/os.h" /* diff --git a/src/syntax.h b/src/syntax.h new file mode 100644 index 0000000000..e05d342927 --- /dev/null +++ b/src/syntax.h @@ -0,0 +1,61 @@ +#ifndef NEOVIM_SYNTAX_H +#define NEOVIM_SYNTAX_H +/* syntax.c */ +void syntax_start __ARGS((win_T *wp, linenr_T lnum)); +void syn_stack_free_all __ARGS((synblock_T *block)); +void syn_stack_apply_changes __ARGS((buf_T *buf)); +void syntax_end_parsing __ARGS((linenr_T lnum)); +int syntax_check_changed __ARGS((linenr_T lnum)); +int get_syntax_attr __ARGS((colnr_T col, int *can_spell, int keep_state)); +void syntax_clear __ARGS((synblock_T *block)); +void reset_synblock __ARGS((win_T *wp)); +void ex_syntax __ARGS((exarg_T *eap)); +void ex_ownsyntax __ARGS((exarg_T *eap)); +int syntax_present __ARGS((win_T *win)); +void reset_expand_highlight __ARGS((void)); +void set_context_in_echohl_cmd __ARGS((expand_T *xp, char_u *arg)); +void set_context_in_syntax_cmd __ARGS((expand_T *xp, char_u *arg)); +char_u *get_syntax_name __ARGS((expand_T *xp, int idx)); +int syn_get_id __ARGS((win_T *wp, long lnum, colnr_T col, int trans, + int *spellp, + int keep_state)); +int get_syntax_info __ARGS((int *seqnrp)); +int syn_get_sub_char __ARGS((void)); +int syn_get_stack_item __ARGS((int i)); +int syn_get_foldlevel __ARGS((win_T *wp, long lnum)); +void ex_syntime __ARGS((exarg_T *eap)); +char_u *get_syntime_arg __ARGS((expand_T *xp, int idx)); +void init_highlight __ARGS((int both, int reset)); +int load_colors __ARGS((char_u *name)); +void do_highlight __ARGS((char_u *line, int forceit, int init)); +void free_highlight __ARGS((void)); +void restore_cterm_colors __ARGS((void)); +void set_normal_colors __ARGS((void)); +char_u *hl_get_font_name __ARGS((void)); +void hl_set_font_name __ARGS((char_u *font_name)); +void hl_set_bg_color_name __ARGS((char_u *name)); +void hl_set_fg_color_name __ARGS((char_u *name)); +void clear_hl_tables __ARGS((void)); +int hl_combine_attr __ARGS((int char_attr, int prim_attr)); +attrentry_T *syn_gui_attr2entry __ARGS((int attr)); +int syn_attr2attr __ARGS((int attr)); +attrentry_T *syn_term_attr2entry __ARGS((int attr)); +attrentry_T *syn_cterm_attr2entry __ARGS((int attr)); +char_u *highlight_has_attr __ARGS((int id, int flag, int modec)); +char_u *highlight_color __ARGS((int id, char_u *what, int modec)); +long_u highlight_gui_color_rgb __ARGS((int id, int fg)); +int syn_name2id __ARGS((char_u *name)); +int highlight_exists __ARGS((char_u *name)); +char_u *syn_id2name __ARGS((int id)); +int syn_namen2id __ARGS((char_u *linep, int len)); +int syn_check_group __ARGS((char_u *pp, int len)); +int syn_id2attr __ARGS((int hl_id)); +int syn_id2colors __ARGS((int hl_id, guicolor_T *fgp, guicolor_T *bgp)); +int syn_get_final_id __ARGS((int hl_id)); +void highlight_gui_started __ARGS((void)); +int highlight_changed __ARGS((void)); +void set_context_in_highlight_cmd __ARGS((expand_T *xp, char_u *arg)); +char_u *get_highlight_name __ARGS((expand_T *xp, int idx)); +void free_highlight_fonts __ARGS((void)); +/* vim: set ft=c : */ +#endif /* NEOVIM_SYNTAX_H */ diff --git a/src/tag.c b/src/tag.c index 671f624ce8..ebdfb6b2a2 100644 --- a/src/tag.c +++ b/src/tag.c @@ -12,6 +12,33 @@ */ #include "vim.h" +#include "tag.h" +#include "buffer.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "if_cscope.h" +#include "mark.h" +#include "mbyte.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "term.h" +#include "ui.h" +#include "window.h" /* * Structure to hold pointers to various items in a tag line. diff --git a/src/tag.h b/src/tag.h new file mode 100644 index 0000000000..829d48ff7b --- /dev/null +++ b/src/tag.h @@ -0,0 +1,18 @@ +#ifndef NEOVIM_TAG_H +#define NEOVIM_TAG_H +/* tag.c */ +int do_tag __ARGS((char_u *tag, int type, int count, int forceit, int verbose)); +void tag_freematch __ARGS((void)); +void do_tags __ARGS((exarg_T *eap)); +int find_tags __ARGS((char_u *pat, int *num_matches, char_u ***matchesp, + int flags, int mincount, + char_u *buf_ffname)); +void free_tag_stuff __ARGS((void)); +int get_tagfname __ARGS((tagname_T *tnp, int first, char_u *buf)); +void tagname_free __ARGS((tagname_T *tnp)); +void simplify_filename __ARGS((char_u *filename)); +int expand_tags __ARGS((int tagnames, char_u *pat, int *num_file, + char_u ***file)); +int get_tags __ARGS((list_T *list, char_u *pat)); +/* vim: set ft=c : */ +#endif /* NEOVIM_TAG_H */ diff --git a/src/term.c b/src/term.c index a15e281de5..8488376a25 100644 --- a/src/term.c +++ b/src/term.c @@ -24,6 +24,25 @@ #define tgetstr tgetstr_defined_wrong #include "vim.h" +#include "term.h" +#include "buffer.h" +#include "charset.h" +#include "edit.h" +#include "eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "getchar.h" +#include "message.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "popupmnu.h" +#include "screen.h" +#include "syntax.h" +#include "ui.h" +#include "window.h" #ifdef HAVE_TGETENT # ifdef HAVE_TERMIOS_H diff --git a/src/term.h b/src/term.h index 0ba5a19c13..792d9b7484 100644 --- a/src/term.h +++ b/src/term.h @@ -1,156 +1,68 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * This file contains the defines for the machine dependent escape sequences - * that the editor needs to perform various operations. All of the sequences - * here are optional, except "cm" (cursor motion). - */ - - -/* - * Index of the termcap codes in the term_strings array. - */ -enum SpecialKey { - KS_NAME = 0, /* name of this terminal entry */ - KS_CE, /* clear to end of line */ - KS_AL, /* add new blank line */ - KS_CAL, /* add number of blank lines */ - KS_DL, /* delete line */ - KS_CDL, /* delete number of lines */ - KS_CS, /* scroll region */ - KS_CL, /* clear screen */ - KS_CD, /* clear to end of display */ - KS_UT, /* clearing uses current background color */ - KS_DA, /* text may be scrolled down from up */ - KS_DB, /* text may be scrolled up from down */ - KS_VI, /* cursor invisible */ - KS_VE, /* cursor visible */ - KS_VS, /* cursor very visible */ - KS_ME, /* normal mode */ - KS_MR, /* reverse mode */ - KS_MD, /* bold mode */ - KS_SE, /* normal mode */ - KS_SO, /* standout mode */ - KS_CZH, /* italic mode start */ - KS_CZR, /* italic mode end */ - KS_UE, /* exit underscore (underline) mode */ - KS_US, /* underscore (underline) mode */ - KS_UCE, /* exit undercurl mode */ - KS_UCS, /* undercurl mode */ - KS_MS, /* save to move cur in reverse mode */ - KS_CM, /* cursor motion */ - KS_SR, /* scroll reverse (backward) */ - KS_CRI, /* cursor number of chars right */ - KS_VB, /* visual bell */ - KS_KS, /* put term in "keypad transmit" mode */ - KS_KE, /* out of "keypad transmit" mode */ - KS_TI, /* put terminal in termcap mode */ - KS_TE, /* out of termcap mode */ - KS_BC, /* backspace character (cursor left) */ - KS_CCS, /* cur is relative to scroll region */ - KS_CCO, /* number of colors */ - KS_CSF, /* set foreground color */ - KS_CSB, /* set background color */ - KS_XS, /* standout not erased by overwriting (hpterm) */ - KS_MB, /* blink mode */ - KS_CAF, /* set foreground color (ANSI) */ - KS_CAB, /* set background color (ANSI) */ - KS_LE, /* cursor left (mostly backspace) */ - KS_ND, /* cursor right */ - KS_CIS, /* set icon text start */ - KS_CIE, /* set icon text end */ - KS_TS, /* set window title start (to status line)*/ - KS_FS, /* set window title end (from status line) */ - KS_CWP, /* set window position in pixels */ - KS_CWS, /* set window size in characters */ - KS_CRV, /* request version string */ - KS_CSI, /* start insert mode (bar cursor) */ - KS_CEI, /* end insert mode (block cursor) */ - KS_CSV, /* scroll region vertical */ - KS_OP, /* original color pair */ - KS_U7 /* request cursor position */ -}; - -#define KS_LAST KS_U7 - -/* - * the terminal capabilities are stored in this array - * IMPORTANT: When making changes, note the following: - * - there should be an entry for each code in the builtin termcaps - * - there should be an option for each code in option.c - * - there should be code in term.c to obtain the value from the termcap - */ - -extern char_u *(term_strings[]); /* current terminal strings */ - -/* - * strings used for terminal - */ -#define T_NAME (term_str(KS_NAME)) /* terminal name */ -#define T_CE (term_str(KS_CE)) /* clear to end of line */ -#define T_AL (term_str(KS_AL)) /* add new blank line */ -#define T_CAL (term_str(KS_CAL)) /* add number of blank lines */ -#define T_DL (term_str(KS_DL)) /* delete line */ -#define T_CDL (term_str(KS_CDL)) /* delete number of lines */ -#define T_CS (term_str(KS_CS)) /* scroll region */ -#define T_CSV (term_str(KS_CSV)) /* scroll region vertical */ -#define T_CL (term_str(KS_CL)) /* clear screen */ -#define T_CD (term_str(KS_CD)) /* clear to end of display */ -#define T_UT (term_str(KS_UT)) /* clearing uses background color */ -#define T_DA (term_str(KS_DA)) /* text may be scrolled down from up */ -#define T_DB (term_str(KS_DB)) /* text may be scrolled up from down */ -#define T_VI (term_str(KS_VI)) /* cursor invisible */ -#define T_VE (term_str(KS_VE)) /* cursor visible */ -#define T_VS (term_str(KS_VS)) /* cursor very visible */ -#define T_ME (term_str(KS_ME)) /* normal mode */ -#define T_MR (term_str(KS_MR)) /* reverse mode */ -#define T_MD (term_str(KS_MD)) /* bold mode */ -#define T_SE (term_str(KS_SE)) /* normal mode */ -#define T_SO (term_str(KS_SO)) /* standout mode */ -#define T_CZH (term_str(KS_CZH)) /* italic mode start */ -#define T_CZR (term_str(KS_CZR)) /* italic mode end */ -#define T_UE (term_str(KS_UE)) /* exit underscore (underline) mode */ -#define T_US (term_str(KS_US)) /* underscore (underline) mode */ -#define T_UCE (term_str(KS_UCE)) /* exit undercurl mode */ -#define T_UCS (term_str(KS_UCS)) /* undercurl mode */ -#define T_MS (term_str(KS_MS)) /* save to move cur in reverse mode */ -#define T_CM (term_str(KS_CM)) /* cursor motion */ -#define T_SR (term_str(KS_SR)) /* scroll reverse (backward) */ -#define T_CRI (term_str(KS_CRI)) /* cursor number of chars right */ -#define T_VB (term_str(KS_VB)) /* visual bell */ -#define T_KS (term_str(KS_KS)) /* put term in "keypad transmit" mode */ -#define T_KE (term_str(KS_KE)) /* out of "keypad transmit" mode */ -#define T_TI (term_str(KS_TI)) /* put terminal in termcap mode */ -#define T_TE (term_str(KS_TE)) /* out of termcap mode */ -#define T_BC (term_str(KS_BC)) /* backspace character */ -#define T_CCS (term_str(KS_CCS)) /* cur is relative to scroll region */ -#define T_CCO (term_str(KS_CCO)) /* number of colors */ -#define T_CSF (term_str(KS_CSF)) /* set foreground color */ -#define T_CSB (term_str(KS_CSB)) /* set background color */ -#define T_XS (term_str(KS_XS)) /* standout not erased by overwriting */ -#define T_MB (term_str(KS_MB)) /* blink mode */ -#define T_CAF (term_str(KS_CAF)) /* set foreground color (ANSI) */ -#define T_CAB (term_str(KS_CAB)) /* set background color (ANSI) */ -#define T_LE (term_str(KS_LE)) /* cursor left */ -#define T_ND (term_str(KS_ND)) /* cursor right */ -#define T_CIS (term_str(KS_CIS)) /* set icon text start */ -#define T_CIE (term_str(KS_CIE)) /* set icon text end */ -#define T_TS (term_str(KS_TS)) /* set window title start */ -#define T_FS (term_str(KS_FS)) /* set window title end */ -#define T_CWP (term_str(KS_CWP)) /* window position */ -#define T_CWS (term_str(KS_CWS)) /* window size */ -#define T_CSI (term_str(KS_CSI)) /* start insert mode */ -#define T_CEI (term_str(KS_CEI)) /* end insert mode */ -#define T_CRV (term_str(KS_CRV)) /* request version string */ -#define T_OP (term_str(KS_OP)) /* original color pair */ -#define T_U7 (term_str(KS_U7)) /* request cursor position */ - -#define TMODE_COOK 0 /* terminal mode for external cmds and Ex mode */ -#define TMODE_SLEEP 1 /* terminal mode for sleeping (cooked but no echo) */ -#define TMODE_RAW 2 /* terminal mode for Normal and Insert mode */ +#ifndef NEOVIM_TERM_H +#define NEOVIM_TERM_H +/* term.c */ +int set_termname __ARGS((char_u *term)); +void set_mouse_termcode __ARGS((int n, char_u *s)); +void del_mouse_termcode __ARGS((int n)); +void getlinecol __ARGS((long *cp, long *rp)); +int add_termcap_entry __ARGS((char_u *name, int force)); +int term_is_8bit __ARGS((char_u *name)); +int term_is_gui __ARGS((char_u *name)); +char_u *tltoa __ARGS((unsigned long i)); +void termcapinit __ARGS((char_u *name)); +void out_flush __ARGS((void)); +void out_flush_check __ARGS((void)); +void out_trash __ARGS((void)); +void out_char __ARGS((unsigned c)); +void out_str_nf __ARGS((char_u *s)); +void out_str __ARGS((char_u *s)); +void term_windgoto __ARGS((int row, int col)); +void term_cursor_right __ARGS((int i)); +void term_append_lines __ARGS((int line_count)); +void term_delete_lines __ARGS((int line_count)); +void term_set_winpos __ARGS((int x, int y)); +void term_set_winsize __ARGS((int width, int height)); +void term_fg_color __ARGS((int n)); +void term_bg_color __ARGS((int n)); +void term_settitle __ARGS((char_u *title)); +void ttest __ARGS((int pairs)); +void add_long_to_buf __ARGS((long_u val, char_u *dst)); +void check_shellsize __ARGS((void)); +void limit_screen_size __ARGS((void)); +void win_new_shellsize __ARGS((void)); +void shell_resized __ARGS((void)); +void shell_resized_check __ARGS((void)); +void set_shellsize __ARGS((int width, int height, int mustset)); +void settmode __ARGS((int tmode)); +void starttermcap __ARGS((void)); +void stoptermcap __ARGS((void)); +void may_req_termresponse __ARGS((void)); +void may_req_ambiguous_char_width __ARGS((void)); +int swapping_screen __ARGS((void)); +void setmouse __ARGS((void)); +int mouse_has __ARGS((int c)); +int mouse_model_popup __ARGS((void)); +void scroll_start __ARGS((void)); +void cursor_on __ARGS((void)); +void cursor_off __ARGS((void)); +void term_cursor_shape __ARGS((void)); +void scroll_region_set __ARGS((win_T *wp, int off)); +void scroll_region_reset __ARGS((void)); +void clear_termcodes __ARGS((void)); +void add_termcode __ARGS((char_u *name, char_u *string, int flags)); +char_u *find_termcode __ARGS((char_u *name)); +char_u *get_termcode __ARGS((int i)); +void del_termcode __ARGS((char_u *name)); +void set_mouse_topline __ARGS((win_T *wp)); +int check_termcode __ARGS((int max_offset, char_u *buf, int bufsize, + int *buflen)); +char_u *replace_termcodes __ARGS((char_u *from, char_u **bufp, int from_part, + int do_lt, + int special)); +int find_term_bykeys __ARGS((char_u *src)); +void show_termcodes __ARGS((void)); +int show_one_termcode __ARGS((char_u *name, char_u *code, int printit)); +char_u *translate_mapping __ARGS((char_u *str, int expmap)); +void update_tcap __ARGS((int attr)); +/* vim: set ft=c : */ +#endif /* NEOVIM_TERM_H */ diff --git a/src/term_defs.h b/src/term_defs.h new file mode 100644 index 0000000000..0ba5a19c13 --- /dev/null +++ b/src/term_defs.h @@ -0,0 +1,156 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * This file contains the defines for the machine dependent escape sequences + * that the editor needs to perform various operations. All of the sequences + * here are optional, except "cm" (cursor motion). + */ + + +/* + * Index of the termcap codes in the term_strings array. + */ +enum SpecialKey { + KS_NAME = 0, /* name of this terminal entry */ + KS_CE, /* clear to end of line */ + KS_AL, /* add new blank line */ + KS_CAL, /* add number of blank lines */ + KS_DL, /* delete line */ + KS_CDL, /* delete number of lines */ + KS_CS, /* scroll region */ + KS_CL, /* clear screen */ + KS_CD, /* clear to end of display */ + KS_UT, /* clearing uses current background color */ + KS_DA, /* text may be scrolled down from up */ + KS_DB, /* text may be scrolled up from down */ + KS_VI, /* cursor invisible */ + KS_VE, /* cursor visible */ + KS_VS, /* cursor very visible */ + KS_ME, /* normal mode */ + KS_MR, /* reverse mode */ + KS_MD, /* bold mode */ + KS_SE, /* normal mode */ + KS_SO, /* standout mode */ + KS_CZH, /* italic mode start */ + KS_CZR, /* italic mode end */ + KS_UE, /* exit underscore (underline) mode */ + KS_US, /* underscore (underline) mode */ + KS_UCE, /* exit undercurl mode */ + KS_UCS, /* undercurl mode */ + KS_MS, /* save to move cur in reverse mode */ + KS_CM, /* cursor motion */ + KS_SR, /* scroll reverse (backward) */ + KS_CRI, /* cursor number of chars right */ + KS_VB, /* visual bell */ + KS_KS, /* put term in "keypad transmit" mode */ + KS_KE, /* out of "keypad transmit" mode */ + KS_TI, /* put terminal in termcap mode */ + KS_TE, /* out of termcap mode */ + KS_BC, /* backspace character (cursor left) */ + KS_CCS, /* cur is relative to scroll region */ + KS_CCO, /* number of colors */ + KS_CSF, /* set foreground color */ + KS_CSB, /* set background color */ + KS_XS, /* standout not erased by overwriting (hpterm) */ + KS_MB, /* blink mode */ + KS_CAF, /* set foreground color (ANSI) */ + KS_CAB, /* set background color (ANSI) */ + KS_LE, /* cursor left (mostly backspace) */ + KS_ND, /* cursor right */ + KS_CIS, /* set icon text start */ + KS_CIE, /* set icon text end */ + KS_TS, /* set window title start (to status line)*/ + KS_FS, /* set window title end (from status line) */ + KS_CWP, /* set window position in pixels */ + KS_CWS, /* set window size in characters */ + KS_CRV, /* request version string */ + KS_CSI, /* start insert mode (bar cursor) */ + KS_CEI, /* end insert mode (block cursor) */ + KS_CSV, /* scroll region vertical */ + KS_OP, /* original color pair */ + KS_U7 /* request cursor position */ +}; + +#define KS_LAST KS_U7 + +/* + * the terminal capabilities are stored in this array + * IMPORTANT: When making changes, note the following: + * - there should be an entry for each code in the builtin termcaps + * - there should be an option for each code in option.c + * - there should be code in term.c to obtain the value from the termcap + */ + +extern char_u *(term_strings[]); /* current terminal strings */ + +/* + * strings used for terminal + */ +#define T_NAME (term_str(KS_NAME)) /* terminal name */ +#define T_CE (term_str(KS_CE)) /* clear to end of line */ +#define T_AL (term_str(KS_AL)) /* add new blank line */ +#define T_CAL (term_str(KS_CAL)) /* add number of blank lines */ +#define T_DL (term_str(KS_DL)) /* delete line */ +#define T_CDL (term_str(KS_CDL)) /* delete number of lines */ +#define T_CS (term_str(KS_CS)) /* scroll region */ +#define T_CSV (term_str(KS_CSV)) /* scroll region vertical */ +#define T_CL (term_str(KS_CL)) /* clear screen */ +#define T_CD (term_str(KS_CD)) /* clear to end of display */ +#define T_UT (term_str(KS_UT)) /* clearing uses background color */ +#define T_DA (term_str(KS_DA)) /* text may be scrolled down from up */ +#define T_DB (term_str(KS_DB)) /* text may be scrolled up from down */ +#define T_VI (term_str(KS_VI)) /* cursor invisible */ +#define T_VE (term_str(KS_VE)) /* cursor visible */ +#define T_VS (term_str(KS_VS)) /* cursor very visible */ +#define T_ME (term_str(KS_ME)) /* normal mode */ +#define T_MR (term_str(KS_MR)) /* reverse mode */ +#define T_MD (term_str(KS_MD)) /* bold mode */ +#define T_SE (term_str(KS_SE)) /* normal mode */ +#define T_SO (term_str(KS_SO)) /* standout mode */ +#define T_CZH (term_str(KS_CZH)) /* italic mode start */ +#define T_CZR (term_str(KS_CZR)) /* italic mode end */ +#define T_UE (term_str(KS_UE)) /* exit underscore (underline) mode */ +#define T_US (term_str(KS_US)) /* underscore (underline) mode */ +#define T_UCE (term_str(KS_UCE)) /* exit undercurl mode */ +#define T_UCS (term_str(KS_UCS)) /* undercurl mode */ +#define T_MS (term_str(KS_MS)) /* save to move cur in reverse mode */ +#define T_CM (term_str(KS_CM)) /* cursor motion */ +#define T_SR (term_str(KS_SR)) /* scroll reverse (backward) */ +#define T_CRI (term_str(KS_CRI)) /* cursor number of chars right */ +#define T_VB (term_str(KS_VB)) /* visual bell */ +#define T_KS (term_str(KS_KS)) /* put term in "keypad transmit" mode */ +#define T_KE (term_str(KS_KE)) /* out of "keypad transmit" mode */ +#define T_TI (term_str(KS_TI)) /* put terminal in termcap mode */ +#define T_TE (term_str(KS_TE)) /* out of termcap mode */ +#define T_BC (term_str(KS_BC)) /* backspace character */ +#define T_CCS (term_str(KS_CCS)) /* cur is relative to scroll region */ +#define T_CCO (term_str(KS_CCO)) /* number of colors */ +#define T_CSF (term_str(KS_CSF)) /* set foreground color */ +#define T_CSB (term_str(KS_CSB)) /* set background color */ +#define T_XS (term_str(KS_XS)) /* standout not erased by overwriting */ +#define T_MB (term_str(KS_MB)) /* blink mode */ +#define T_CAF (term_str(KS_CAF)) /* set foreground color (ANSI) */ +#define T_CAB (term_str(KS_CAB)) /* set background color (ANSI) */ +#define T_LE (term_str(KS_LE)) /* cursor left */ +#define T_ND (term_str(KS_ND)) /* cursor right */ +#define T_CIS (term_str(KS_CIS)) /* set icon text start */ +#define T_CIE (term_str(KS_CIE)) /* set icon text end */ +#define T_TS (term_str(KS_TS)) /* set window title start */ +#define T_FS (term_str(KS_FS)) /* set window title end */ +#define T_CWP (term_str(KS_CWP)) /* window position */ +#define T_CWS (term_str(KS_CWS)) /* window size */ +#define T_CSI (term_str(KS_CSI)) /* start insert mode */ +#define T_CEI (term_str(KS_CEI)) /* end insert mode */ +#define T_CRV (term_str(KS_CRV)) /* request version string */ +#define T_OP (term_str(KS_OP)) /* original color pair */ +#define T_U7 (term_str(KS_U7)) /* request cursor position */ + +#define TMODE_COOK 0 /* terminal mode for external cmds and Ex mode */ +#define TMODE_SLEEP 1 /* terminal mode for sleeping (cooked but no echo) */ +#define TMODE_RAW 2 /* terminal mode for Normal and Insert mode */ diff --git a/src/ui.c b/src/ui.c index 76eca6fff9..3396f2e6ef 100644 --- a/src/ui.c +++ b/src/ui.c @@ -17,7 +17,21 @@ */ #include "vim.h" - +#include "ui.h" +#include "diff.h" +#include "ex_cmds2.h" +#include "fold.h" +#include "main.h" +#include "mbyte.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "screen.h" +#include "term.h" +#include "window.h" void ui_write(char_u *s, int len) { diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000000..bcd6afd426 --- /dev/null +++ b/src/ui.h @@ -0,0 +1,70 @@ +#ifndef NEOVIM_UI_H +#define NEOVIM_UI_H +/* ui.c */ +void ui_write __ARGS((char_u *s, int len)); +void ui_inchar_undo __ARGS((char_u *s, int len)); +int ui_inchar __ARGS((char_u *buf, int maxlen, long wtime, int tb_change_cnt)); +int ui_char_avail __ARGS((void)); +void ui_delay __ARGS((long msec, int ignoreinput)); +void ui_suspend __ARGS((void)); +void suspend_shell __ARGS((void)); +int ui_get_shellsize __ARGS((void)); +void ui_set_shellsize __ARGS((int mustset)); +void ui_new_shellsize __ARGS((void)); +void ui_breakcheck __ARGS((void)); +void clip_init __ARGS((int can_use)); +void clip_update_selection __ARGS((VimClipboard *clip)); +void clip_own_selection __ARGS((VimClipboard *cbd)); +void clip_lose_selection __ARGS((VimClipboard *cbd)); +void clip_auto_select __ARGS((void)); +int clip_isautosel_star __ARGS((void)); +int clip_isautosel_plus __ARGS((void)); +void clip_modeless __ARGS((int button, int is_click, int is_drag)); +void clip_start_selection __ARGS((int col, int row, int repeated_click)); +void clip_process_selection __ARGS((int button, int col, int row, + int_u repeated_click)); +void clip_may_redraw_selection __ARGS((int row, int col, int len)); +void clip_clear_selection __ARGS((VimClipboard *cbd)); +void clip_may_clear_selection __ARGS((int row1, int row2)); +void clip_scroll_selection __ARGS((int rows)); +void clip_copy_modeless_selection __ARGS((int both)); +int clip_gen_own_selection __ARGS((VimClipboard *cbd)); +void clip_gen_lose_selection __ARGS((VimClipboard *cbd)); +void clip_gen_set_selection __ARGS((VimClipboard *cbd)); +void clip_gen_request_selection __ARGS((VimClipboard *cbd)); +int clip_gen_owner_exists __ARGS((VimClipboard *cbd)); +int vim_is_input_buf_full __ARGS((void)); +int vim_is_input_buf_empty __ARGS((void)); +int vim_free_in_input_buf __ARGS((void)); +int vim_used_in_input_buf __ARGS((void)); +char_u *get_input_buf __ARGS((void)); +void set_input_buf __ARGS((char_u *p)); +void add_to_input_buf __ARGS((char_u *s, int len)); +void add_to_input_buf_csi __ARGS((char_u *str, int len)); +void push_raw_key __ARGS((char_u *s, int len)); +void trash_input_buf __ARGS((void)); +int read_from_input_buf __ARGS((char_u *buf, long maxlen)); +void fill_input_buf __ARGS((int exit_on_error)); +void read_error_exit __ARGS((void)); +void ui_cursor_shape __ARGS((void)); +int check_col __ARGS((int col)); +int check_row __ARGS((int row)); +void open_app_context __ARGS((void)); +void x11_setup_atoms __ARGS((Display *dpy)); +void x11_setup_selection __ARGS((Widget w)); +void clip_x11_request_selection __ARGS((Widget myShell, Display *dpy, + VimClipboard *cbd)); +void clip_x11_lose_selection __ARGS((Widget myShell, VimClipboard *cbd)); +int clip_x11_own_selection __ARGS((Widget myShell, VimClipboard *cbd)); +void clip_x11_set_selection __ARGS((VimClipboard *cbd)); +int clip_x11_owner_exists __ARGS((VimClipboard *cbd)); +void yank_cut_buffer0 __ARGS((Display *dpy, VimClipboard *cbd)); +int jump_to_mouse __ARGS((int flags, int *inclusive, int which_button)); +int mouse_comp_pos __ARGS((win_T *win, int *rowp, int *colp, linenr_T *lnump)); +win_T *mouse_find_win __ARGS((int *rowp, int *colp)); +int get_fpos_of_mouse __ARGS((pos_T *mpos)); +int vcol2col __ARGS((win_T *wp, linenr_T lnum, int vcol)); +void ui_focus_change __ARGS((int in_focus)); +void im_save_status __ARGS((long *psave)); +/* vim: set ft=c : */ +#endif /* NEOVIM_UI_H */ diff --git a/src/undo.c b/src/undo.c index d5bdfb53b1..b63e89458e 100644 --- a/src/undo.c +++ b/src/undo.c @@ -82,6 +82,21 @@ #define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ #include "vim.h" +#include "undo.h" +#include "edit.h" +#include "eval.h" +#include "fileio.h" +#include "fold.h" +#include "mark.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "screen.h" +#include "sha256.h" static long get_undolevel __ARGS((void)); static void u_unch_branch __ARGS((u_header_T *uhp)); diff --git a/src/undo.h b/src/undo.h new file mode 100644 index 0000000000..aecab36875 --- /dev/null +++ b/src/undo.h @@ -0,0 +1,34 @@ +#ifndef NEOVIM_UNDO_H +#define NEOVIM_UNDO_H +/* undo.c */ +int u_save_cursor __ARGS((void)); +int u_save __ARGS((linenr_T top, linenr_T bot)); +int u_savesub __ARGS((linenr_T lnum)); +int u_inssub __ARGS((linenr_T lnum)); +int u_savedel __ARGS((linenr_T lnum, long nlines)); +int undo_allowed __ARGS((void)); +int u_savecommon __ARGS((linenr_T top, linenr_T bot, linenr_T newbot, + int reload)); +void u_compute_hash __ARGS((char_u *hash)); +char_u *u_get_undo_file_name __ARGS((char_u *buf_ffname, int reading)); +void u_write_undo __ARGS((char_u *name, int forceit, buf_T *buf, char_u *hash)); +void u_read_undo __ARGS((char_u *name, char_u *hash, char_u *orig_name)); +void u_undo __ARGS((int count)); +void u_redo __ARGS((int count)); +void undo_time __ARGS((long step, int sec, int file, int absolute)); +void u_sync __ARGS((int force)); +void ex_undolist __ARGS((exarg_T *eap)); +void ex_undojoin __ARGS((exarg_T *eap)); +void u_unchanged __ARGS((buf_T *buf)); +void u_find_first_changed __ARGS((void)); +void u_update_save_nr __ARGS((buf_T *buf)); +void u_clearall __ARGS((buf_T *buf)); +void u_saveline __ARGS((linenr_T lnum)); +void u_clearline __ARGS((void)); +void u_undoline __ARGS((void)); +void u_blockfree __ARGS((buf_T *buf)); +int bufIsChanged __ARGS((buf_T *buf)); +int curbufIsChanged __ARGS((void)); +void u_eval_tree __ARGS((u_header_T *first_uhp, list_T *list)); +/* vim: set ft=c : */ +#endif /* NEOVIM_UNDO_H */ diff --git a/src/version.c b/src/version.c index a928e840bd..e85f7a57ec 100644 --- a/src/version.c +++ b/src/version.c @@ -8,7 +8,12 @@ */ #include "vim.h" - +#include "version.h" +#include "charset.h" +#include "memline.h" +#include "message.h" +#include "misc2.h" +#include "screen.h" /* * Vim originated from Stevie version 3.6 (Fish disk 217) by GRWalter (Fred) @@ -22,7 +27,7 @@ * interesting. */ -#include "version.h" +#include "version_defs.h" char *Version = VIM_VERSION_SHORT; static char *mediumVersion = VIM_VERSION_MEDIUM; diff --git a/src/version.h b/src/version.h index ee49a6d97c..b2828980f3 100644 --- a/src/version.h +++ b/src/version.h @@ -1,40 +1,13 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * Define the version number, name, etc. - * The patchlevel is in included_patches[], in version.c. - * - * This doesn't use string concatenation, some compilers don't support it. - */ - -#define VIM_VERSION_MAJOR 7 -#define VIM_VERSION_MAJOR_STR "7" -#define VIM_VERSION_MINOR 4 -#define VIM_VERSION_MINOR_STR "4" -#define VIM_VERSION_100 (VIM_VERSION_MAJOR * 100 + VIM_VERSION_MINOR) - -#define VIM_VERSION_BUILD 280 -#define VIM_VERSION_BUILD_BCD 0x118 -#define VIM_VERSION_BUILD_STR "280" -#define VIM_VERSION_PATCHLEVEL 0 -#define VIM_VERSION_PATCHLEVEL_STR "0" -/* Used by MacOS port should be one of: development, alpha, beta, final */ -#define VIM_VERSION_RELEASE final - -/* - * VIM_VERSION_NODOT is used for the runtime directory name. - * VIM_VERSION_SHORT is copied into the swap file (max. length is 6 chars). - * VIM_VERSION_MEDIUM is used for the startup-screen. - * VIM_VERSION_LONG is used for the ":version" command and "Vim -h". - */ -#define VIM_VERSION_NODOT "vim74" -#define VIM_VERSION_SHORT "7.4" -#define VIM_VERSION_MEDIUM "7.4" -#define VIM_VERSION_LONG "VIM - Vi IMproved 7.4 (2013 Aug 10)" -#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.4 (2013 Aug 10, compiled " +#ifndef NEOVIM_VERSION_H +#define NEOVIM_VERSION_H +/* version.c */ +void make_version __ARGS((void)); +int highest_patch __ARGS((void)); +int has_patch __ARGS((int n)); +void ex_version __ARGS((exarg_T *eap)); +void list_version __ARGS((void)); +void maybe_intro_message __ARGS((void)); +void intro_message __ARGS((int colon)); +void ex_intro __ARGS((exarg_T *eap)); +/* vim: set ft=c : */ +#endif /* NEOVIM_VERSION_H */ diff --git a/src/version_defs.h b/src/version_defs.h new file mode 100644 index 0000000000..ee49a6d97c --- /dev/null +++ b/src/version_defs.h @@ -0,0 +1,40 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + */ + +/* + * Define the version number, name, etc. + * The patchlevel is in included_patches[], in version.c. + * + * This doesn't use string concatenation, some compilers don't support it. + */ + +#define VIM_VERSION_MAJOR 7 +#define VIM_VERSION_MAJOR_STR "7" +#define VIM_VERSION_MINOR 4 +#define VIM_VERSION_MINOR_STR "4" +#define VIM_VERSION_100 (VIM_VERSION_MAJOR * 100 + VIM_VERSION_MINOR) + +#define VIM_VERSION_BUILD 280 +#define VIM_VERSION_BUILD_BCD 0x118 +#define VIM_VERSION_BUILD_STR "280" +#define VIM_VERSION_PATCHLEVEL 0 +#define VIM_VERSION_PATCHLEVEL_STR "0" +/* Used by MacOS port should be one of: development, alpha, beta, final */ +#define VIM_VERSION_RELEASE final + +/* + * VIM_VERSION_NODOT is used for the runtime directory name. + * VIM_VERSION_SHORT is copied into the swap file (max. length is 6 chars). + * VIM_VERSION_MEDIUM is used for the startup-screen. + * VIM_VERSION_LONG is used for the ":version" command and "Vim -h". + */ +#define VIM_VERSION_NODOT "vim74" +#define VIM_VERSION_SHORT "7.4" +#define VIM_VERSION_MEDIUM "7.4" +#define VIM_VERSION_LONG "VIM - Vi IMproved 7.4 (2013 Aug 10)" +#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.4 (2013 Aug 10, compiled " diff --git a/src/vim.h b/src/vim.h index fab3d70568..75c2b14d38 100644 --- a/src/vim.h +++ b/src/vim.h @@ -6,8 +6,8 @@ * Do ":help credits" in Vim to see a list of people who contributed. */ -#ifndef VIM__H -# define VIM__H +#ifndef NEOVIM_VIM_H +# define NEOVIM_VIM_H /* Included when ported to cmake */ /* This is needed to replace TRUE/FALSE macros by true/false from c99 */ #include @@ -62,7 +62,7 @@ Error: configure did not run properly.Check auto/config.log. # define VIMPACKAGE "vim" #endif -#include "os_unix.h" /* bring lots of system header files */ +#include "os_unix_defs.h" /* bring lots of system header files */ #ifndef __ARGS # if defined(__STDC__) || defined(__GNUC__) || defined(WIN3264) @@ -154,7 +154,7 @@ typedef unsigned long u8char_T; /* long should be 32 bits or more */ #include "ascii.h" #include "keymap.h" -#include "term.h" +#include "term_defs.h" #include "macros.h" #include @@ -1260,9 +1260,9 @@ int vim_memcmp __ARGS((void *, void *, size_t)); typedef struct timeval proftime_T; -/* Include option.h before structs.h, because the number of window-local and +/* Include option_defs.h before structs.h, because the number of window-local and * buffer-local options is used there. */ -#include "option.h" /* options and default values */ +#include "option_defs.h" /* options and default values */ /* Note that gui.h is included by structs.h */ @@ -1412,7 +1412,7 @@ typedef struct timeval proftime_T; typedef int VimClipboard; /* This is required for the prototypes. */ -#include "ex_cmds.h" /* Ex command defines */ +#include "ex_cmds_defs.h" /* Ex command defines */ #include "proto.h" /* function prototypes */ /* This has to go after the include of proto.h, as proto/gui.pro declares @@ -1594,4 +1594,4 @@ typedef int VimClipboard; /* This is required for the prototypes. */ # define SET_NO_HLSEARCH(flag) no_hlsearch = (flag); set_vim_var_nr( \ VV_HLSEARCH, !no_hlsearch) -#endif /* VIM__H */ +#endif /* NEOVIM_VIM_H */ diff --git a/src/window.c b/src/window.c index 5256fbd1fa..fb95ec1239 100644 --- a/src/window.c +++ b/src/window.c @@ -8,6 +8,38 @@ */ #include "vim.h" +#include "window.h" +#include "buffer.h" +#include "charset.h" +#include "diff.h" +#include "edit.h" +#include "eval.h" +#include "ex_cmds.h" +#include "ex_cmds2.h" +#include "ex_docmd.h" +#include "ex_eval.h" +#include "ex_getln.h" +#include "fileio.h" +#include "fold.h" +#include "getchar.h" +#include "hashtab.h" +#include "main.h" +#include "mark.h" +#include "memline.h" +#include "message.h" +#include "misc1.h" +#include "misc2.h" +#include "move.h" +#include "normal.h" +#include "option.h" +#include "os_unix.h" +#include "quickfix.h" +#include "regexp.h" +#include "screen.h" +#include "search.h" +#include "syntax.h" +#include "term.h" +#include "undo.h" #include "os/os.h" static int path_is_url __ARGS((char_u *p)); diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000000..1fa7c302fd --- /dev/null +++ b/src/window.h @@ -0,0 +1,96 @@ +#ifndef NEOVIM_WINDOW_H +#define NEOVIM_WINDOW_H +/* window.c */ +void do_window __ARGS((int nchar, long Prenum, int xchar)); +int win_split __ARGS((int size, int flags)); +int win_split_ins __ARGS((int size, int flags, win_T *new_wp, int dir)); +int win_valid __ARGS((win_T *win)); +int win_count __ARGS((void)); +int make_windows __ARGS((int count, int vertical)); +void win_move_after __ARGS((win_T *win1, win_T *win2)); +void win_equal __ARGS((win_T *next_curwin, int current, int dir)); +void close_windows __ARGS((buf_T *buf, int keep_curwin)); +int one_window __ARGS((void)); +int win_close __ARGS((win_T *win, int free_buf)); +void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp)); +void win_free_all __ARGS((void)); +win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp)); +void close_others __ARGS((int message, int forceit)); +void curwin_init __ARGS((void)); +void win_init_empty __ARGS((win_T *wp)); +int win_alloc_first __ARGS((void)); +void win_alloc_aucmd_win __ARGS((void)); +void win_init_size __ARGS((void)); +void free_tabpage __ARGS((tabpage_T *tp)); +int win_new_tabpage __ARGS((int after)); +int may_open_tabpage __ARGS((void)); +int make_tabpages __ARGS((int maxcount)); +int valid_tabpage __ARGS((tabpage_T *tpc)); +tabpage_T *find_tabpage __ARGS((int n)); +int tabpage_index __ARGS((tabpage_T *ftp)); +void goto_tabpage __ARGS((int n)); +void goto_tabpage_tp __ARGS((tabpage_T *tp, int trigger_enter_autocmds, + int trigger_leave_autocmds)); +void goto_tabpage_win __ARGS((tabpage_T *tp, win_T *wp)); +void tabpage_move __ARGS((int nr)); +void win_goto __ARGS((win_T *wp)); +win_T *win_find_nr __ARGS((int winnr)); +tabpage_T *win_find_tabpage __ARGS((win_T *win)); +void win_enter __ARGS((win_T *wp, int undo_sync)); +win_T *buf_jump_open_win __ARGS((buf_T *buf)); +win_T *buf_jump_open_tab __ARGS((buf_T *buf)); +void win_append __ARGS((win_T *after, win_T *wp)); +void win_remove __ARGS((win_T *wp, tabpage_T *tp)); +int win_alloc_lines __ARGS((win_T *wp)); +void win_free_lsize __ARGS((win_T *wp)); +void shell_new_rows __ARGS((void)); +void shell_new_columns __ARGS((void)); +void win_size_save __ARGS((garray_T *gap)); +void win_size_restore __ARGS((garray_T *gap)); +int win_comp_pos __ARGS((void)); +void win_setheight __ARGS((int height)); +void win_setheight_win __ARGS((int height, win_T *win)); +void win_setwidth __ARGS((int width)); +void win_setwidth_win __ARGS((int width, win_T *wp)); +void win_setminheight __ARGS((void)); +void win_drag_status_line __ARGS((win_T *dragwin, int offset)); +void win_drag_vsep_line __ARGS((win_T *dragwin, int offset)); +void win_new_height __ARGS((win_T *wp, int height)); +void win_new_width __ARGS((win_T *wp, int width)); +void win_comp_scroll __ARGS((win_T *wp)); +void command_height __ARGS((void)); +void last_status __ARGS((int morewin)); +int tabline_height __ARGS((void)); +char_u *grab_file_name __ARGS((long count, linenr_T *file_lnum)); +char_u *file_name_at_cursor __ARGS((int options, long count, + linenr_T *file_lnum)); +char_u *file_name_in_line __ARGS((char_u *line, int col, int options, + long count, char_u *rel_fname, + linenr_T *file_lnum)); +char_u *find_file_name_in_path __ARGS((char_u *ptr, int len, int options, + long count, + char_u *rel_fname)); +int path_with_url __ARGS((char_u *fname)); +int vim_isAbsName __ARGS((char_u *name)); +int vim_FullName __ARGS((char_u *fname, char_u *buf, int len, int force)); +int min_rows __ARGS((void)); +int only_one_window __ARGS((void)); +void check_lnums __ARGS((int do_curwin)); +void make_snapshot __ARGS((int idx)); +void restore_snapshot __ARGS((int idx, int close_curwin)); +int switch_win __ARGS((win_T **save_curwin, tabpage_T **save_curtab, win_T *win, + tabpage_T *tp, + int no_display)); +void restore_win __ARGS((win_T *save_curwin, tabpage_T *save_curtab, + int no_display)); +void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf)); +void restore_buffer __ARGS((buf_T *save_curbuf)); +int win_hasvertsplit __ARGS((void)); +int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id)); +int match_delete __ARGS((win_T *wp, int id, int perr)); +void clear_matches __ARGS((win_T *wp)); +matchitem_T *get_match __ARGS((win_T *wp, int id)); +int get_win_number __ARGS((win_T *wp, win_T *first_win)); +int get_tab_number __ARGS((tabpage_T *tp)); +/* vim: set ft=c : */ +#endif /* NEOVIM_WINDOW_H */ -- cgit From a74c059a3e322f1abc0e98b76e16a7b92d499654 Mon Sep 17 00:00:00 2001 From: Scott Nielsen Date: Wed, 26 Feb 2014 01:56:40 -0700 Subject: Remove implicit declaration of vim_strrchr and vim_strncpy --- src/os/fs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/os/fs.c b/src/os/fs.c index 3529ab4f46..bc9a495984 100644 --- a/src/os/fs.c +++ b/src/os/fs.c @@ -15,6 +15,7 @@ #include "os.h" #include "../message.h" +#include "../misc2.h" int mch_chdir(char *path) { if (p_verbose >= 5) { -- cgit From def17b25fe601682d30c04f06c08dd467292951d Mon Sep 17 00:00:00 2001 From: Scott Nielsen Date: Wed, 26 Feb 2014 02:25:46 -0700 Subject: Remove final build warning This commit removes a K&R promoted parameter error, the final warning I have when building. I realize that this creates only one function that is written in a different style, but I thought it might be worth it to have a warning free build. --- src/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index 418c579209..c5d7d528cf 100644 --- a/src/main.c +++ b/src/main.c @@ -966,9 +966,7 @@ static void parse_command_name(mparm_T *parmp) } } -static bool parse_char_i(input, val) - char_u **input; - char val; +static bool parse_char_i(char_u **input, char val) { if (TOLOWER_ASC(**input) == val) { *input += 1; /* or (*input)++ WITH parens */ -- cgit From 809885ea7dc239f59bb396adc4f1646177fd6052 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:54:45 +0000 Subject: add custom CMake module path --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0a04efe23..ae3a891553 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required (VERSION 2.6) project (NEOVIM) +# Point CMake at any custom modules we may ship +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + set(NEOVIM_VERSION_MAJOR 0) set(NEOVIM_VERSION_MINOR 0) set(NEOVIM_VERSION_PATCH 0) -- cgit From e10290c3eaab56a5822e214508b531cfc19357da Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:55:11 +0000 Subject: add LibFindMacros CMake macro library --- cmake/LibFindMacros.cmake | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 cmake/LibFindMacros.cmake diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake new file mode 100644 index 0000000000..aa2143c82d --- /dev/null +++ b/cmake/LibFindMacros.cmake @@ -0,0 +1,112 @@ +# Version 1.0 (2013-04-12) +# Public Domain, originally written by Lasse Kärkkäinen +# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries + +# If you improve the script, please modify the forementioned wiki page because +# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free +# to remove this entire header if you use real version control instead. + +# Changelog: +# 2013-04-12 Added version number (1.0) and this header, no other changes +# 2009-10-08 Originally published + + +# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments +# used for the current package. For this to work, the first parameter must be the +# prefix of the current package, then the prefix of the new package etc, which are +# passed to find_package. +macro (libfind_package PREFIX) + set (LIBFIND_PACKAGE_ARGS ${ARGN}) + if (${PREFIX}_FIND_QUIETLY) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) + endif (${PREFIX}_FIND_QUIETLY) + if (${PREFIX}_FIND_REQUIRED) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) + endif (${PREFIX}_FIND_REQUIRED) + find_package(${LIBFIND_PACKAGE_ARGS}) +endmacro (libfind_package) + +# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) +# where they added pkg_check_modules. Consequently I need to support both in my scripts +# to avoid those deprecated warnings. Here's a helper that does just that. +# Works identically to pkg_check_modules, except that no checks are needed prior to use. +macro (libfind_pkg_check_modules PREFIX PKGNAME) + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) +endmacro (libfind_pkg_check_modules) + +# Do the final processing once the paths have been detected. +# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain +# all the variables, each of which contain one include directory. +# Ditto for ${PREFIX}_PROCESS_LIBS and library files. +# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. +# Also handles errors in case library detection was required, etc. +macro (libfind_process PREFIX) + # Skip processing if already processed during this run + if (NOT ${PREFIX}_FOUND) + # Start with the assumption that the library was found + set (${PREFIX}_FOUND TRUE) + + # Process all includes and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_INCLUDES}) + if (${i}) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Process all libraries and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_LIBS}) + if (${i}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Print message and/or exit on fatal error + if (${PREFIX}_FOUND) + if (NOT ${PREFIX}_FIND_QUIETLY) + message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") + endif (NOT ${PREFIX}_FIND_QUIETLY) + else (${PREFIX}_FOUND) + if (${PREFIX}_FIND_REQUIRED) + foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) + message("${i}=${${i}}") + endforeach (i) + message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") + endif (${PREFIX}_FIND_REQUIRED) + endif (${PREFIX}_FOUND) + endif (NOT ${PREFIX}_FOUND) +endmacro (libfind_process) + +macro(libfind_library PREFIX basename) + set(TMP "") + if(MSVC80) + set(TMP -vc80) + endif(MSVC80) + if(MSVC90) + set(TMP -vc90) + endif(MSVC90) + set(${PREFIX}_LIBNAMES ${basename}${TMP}) + if(${ARGC} GREATER 2) + set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) + string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) + set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) + endif(${ARGC} GREATER 2) + find_library(${PREFIX}_LIBRARY + NAMES ${${PREFIX}_LIBNAMES} + PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} + ) +endmacro(libfind_library) + -- cgit From 8aa1d8c71a0437ff09872877107dab30ee0c44f0 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:56:00 +0000 Subject: Makefile: add .deps/ to CMake prefix path The CMake prefix path is the set of directories CMake searches for libraries, header files, etc. Use the .deps directory we create when building libuv as one of those locations. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ffc4a2c72c..8907eb1d1e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -include local.mk -CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug +CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=.deps/usr # Extra CMake flags which extend the default set CMAKE_EXTRA_FLAGS := -- cgit From 00ca93fb5037173897f2055a8dc9af143c031931 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:57:04 +0000 Subject: automatically discover libuv in CMake Idiomatically discover if libuv is installed. --- CMakeLists.txt | 3 +++ cmake/FindLibUV.cmake | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 cmake/FindLibUV.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ae3a891553..abc80bf66b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,9 @@ if(NOT CMAKE_USE_PTHREADS_INIT) message(SEND_ERROR "The pthread library must be installed on your system.") endif(NOT CMAKE_USE_PTHREADS_INIT) +# Require libuv +find_package(LibUV REQUIRED) + # add dependencies to include/lib directories link_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/lib") include_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/include") diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake new file mode 100644 index 0000000000..3aeb01195e --- /dev/null +++ b/cmake/FindLibUV.cmake @@ -0,0 +1,24 @@ +# - Try to find libuv +# Once done, this will define +# +# LibUV_FOUND - system has libuv +# LibUV_INCLUDE_DIRS - the libuv include directories +# LibUV_LIBRARIES - link these to use libuv + +include(LibFindMacros) + +# Include dir +find_path(LibUV_INCLUDE_DIR + NAMES uv.h +) + +# The library itself +find_library(LibUV_LIBRARY + NAMES uv +) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +set(LibUV_PROCESS_INCLUDES LibUV_INCLUDE_DIR) +set(LibUV_PROCESS_LIBS LibUV_LIBRARY) +libfind_process(LibUV) -- cgit From 598f9fba861beb7a208e03c3ba71e57deb31a43d Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 21:00:39 +0000 Subject: Makefile: fetch deps before running CMake CMake now required libuv so fetch it first. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8907eb1d1e..fae3699746 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ deps: .deps/usr/lib/libuv.a .deps/usr/lib/libuv.a: sh -e scripts/compile-libuv.sh -cmake: clean +cmake: clean deps mkdir build cd build && cmake $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) ../ -- cgit From 2a6780431e7a8a4ecf41e44d72d8bac639df7ee3 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 20:59:03 +0000 Subject: make use of libuv when found by CMake --- CMakeLists.txt | 1 + src/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index abc80bf66b..0f8f41f7a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ endif(NOT CMAKE_USE_PTHREADS_INIT) # Require libuv find_package(LibUV REQUIRED) +include_directories(${LibUV_INCLUDE_DIRS}) # add dependencies to include/lib directories link_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/lib") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dfd0764a94..96c0b01f3d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ file( GLOB OS_SOURCES os/*.c ) add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES}) -target_link_libraries (nvim m uv ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (vim m ${LibUV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) include(CheckLibraryExists) check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP) -- cgit From e94f933f396e0f08243994679977602d341b117a Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Mon, 24 Feb 2014 21:01:52 +0000 Subject: CMakeLists: remove hardcoded .deps directory We use the standard CMAKE_PREFIX_PATH variable to pass the location of .deps as a search location on the command line. There is now no need for explicitly hard-coding it. --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f8f41f7a4..b057a67f69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,10 +31,6 @@ endif(NOT CMAKE_USE_PTHREADS_INIT) find_package(LibUV REQUIRED) include_directories(${LibUV_INCLUDE_DIRS}) -# add dependencies to include/lib directories -link_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/lib") -include_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/include") - include_directories ("${PROJECT_BINARY_DIR}/config") set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -- cgit From c3ff8cbb7cfe715604099809d0f5f2de84514717 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Tue, 25 Feb 2014 00:00:10 +0000 Subject: prefer linking to static libuv Explicitly try to find the static libuv library first. This might be considered a hack and if it weren't a single-use module it might be preferable to control static versus shared preferences with a configuration variable. --- cmake/FindLibUV.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake index 3aeb01195e..d0cedfb37d 100644 --- a/cmake/FindLibUV.cmake +++ b/cmake/FindLibUV.cmake @@ -12,9 +12,9 @@ find_path(LibUV_INCLUDE_DIR NAMES uv.h ) -# The library itself +# The library itself. Note that we prefer the static version. find_library(LibUV_LIBRARY - NAMES uv + NAMES libuv.a uv ) # Set the include dir variables and the libraries and let libfind_process do the rest. -- cgit From de4fbf92d0da17e2c7f31df29bc72c44702b4e7c Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Wed, 26 Feb 2014 10:06:59 +0000 Subject: link to rt if it provides clock_gettime As noted in #128, if clock_gettime is provided by librt then it does not end up being linked into the static libuv.a binary. This might be considered a bug in libuv but we can address it here. Detect if librt provides the clock_gettime symbol and, if so, append it to the list of libraries linked into nvim. On non-librt systems the behaviour should be as before. --- CMakeLists.txt | 9 ++++++++- src/CMakeLists.txt | 13 +++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b057a67f69..04df162f07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,9 @@ else() set(DEBUG 0) endif() +# Modules used by platform auto-detection +include(CheckLibraryExists) + # Determine platform's threading library. Set CMAKE_THREAD_PREFER_PTHREAD # explicitly to indicate a strong preference for pthread. It is an error to not # have pthread installed even if, for example, the Win32 threading API is found. @@ -27,11 +30,15 @@ if(NOT CMAKE_USE_PTHREADS_INIT) message(SEND_ERROR "The pthread library must be installed on your system.") endif(NOT CMAKE_USE_PTHREADS_INIT) +# Detect if clock_gettime exists in -lrt. If so we need to link with it because +# the static libuv doesn't but uses clock_gettime. +check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) + # Require libuv find_package(LibUV REQUIRED) include_directories(${LibUV_INCLUDE_DIRS}) -include_directories ("${PROJECT_BINARY_DIR}/config") +include_directories ("${PROJECT_BINARY_DIR}/config") set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 96c0b01f3d..a7e815fd7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,16 @@ file( GLOB OS_SOURCES os/*.c ) add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES}) -target_link_libraries (vim m ${LibUV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +# The libraries we link against for nvim +set(NVIM_LINK_LIBRARIES m ${LibUV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + +# Add any libraries needed for a specific platform +if(HAVE_CLOCK_GETTIME) + # Work around libuv.a not linking in rt. + list(APPEND NVIM_LINK_LIBRARIES rt) +endif(HAVE_CLOCK_GETTIME) + +target_link_libraries (nvim ${NVIM_LINK_LIBRARIES}) include(CheckLibraryExists) check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP) @@ -30,6 +39,6 @@ else() endif() endif() -include_directories ("${PROJECT_SOURCE_DIR}/src/proto") +include_directories ("${PROJECT_SOURCE_DIR}/src/proto") install(TARGETS nvim RUNTIME DESTINATION bin) -- cgit From d12322c5b72e908e6401be46f86d4f1950c084e9 Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Wed, 26 Feb 2014 10:30:05 +0000 Subject: Makefile: use "make -C build" idiom Change an explicit ``cd build && make`` into the more usual ``${MAKE} -C build`` style of invoking make in a subdirectory. This should mean that ``make -jN`` from the top-level Makefile should work. Closes #162. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fae3699746..41d26b69ec 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=.deps/usr CMAKE_EXTRA_FLAGS := build/bin/nvim: deps - cd build && make + ${MAKE} -C build test: build/bin/nvim cd src/testdir && make @@ -27,7 +27,7 @@ clean: done install: build/bin/nvim - cd build && make install + ${MAKE} -C build install .PHONY: test deps cmake install -- cgit