diff options
381 files changed, 79974 insertions, 14499 deletions
diff --git a/.gitignore b/.gitignore index c0ce35dc48..a36e19fe97 100644 --- a/.gitignore +++ b/.gitignore @@ -10,16 +10,19 @@ 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 src/testdir/*.failed src/testdir/X* + +# local make targets +local.mk diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..d1a0445925 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +language: c +script: make cmake CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=$PWD/dist" && make && make test > /dev/null 2>&1 && make install diff --git a/CMakeLists.txt b/CMakeLists.txt index adb9894a3c..04df162f07 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) @@ -15,11 +18,29 @@ else() set(DEBUG 0) endif() -# add dependencies to include/lib directories -link_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/lib") -include_directories ("${PROJECT_SOURCE_DIR}/.deps/usr/include") +# 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. +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) + +# 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) add_subdirectory(src) add_subdirectory(config) @@ -1,19 +1,24 @@ -CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug +-include local.mk -build/src/vim: deps - cd build && make +CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=.deps/usr -test: build/src/vim +# Extra CMake flags which extend the default set +CMAKE_EXTRA_FLAGS := + +build/bin/nvim: deps + ${MAKE} -C build + +test: build/bin/nvim cd src/testdir && make 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 +cmake: clean deps mkdir build - cd build && cmake $(CMAKE_FLAGS) ../ + cd build && cmake $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) ../ clean: rm -rf build @@ -21,6 +26,9 @@ clean: rm -f src/testdir/$$file.vim; \ done -.PHONY: test deps cmake +install: build/bin/nvim + ${MAKE} -C build install + +.PHONY: test deps cmake install -.DEFAULT: build/src/vim +.DEFAULT: build/bin/nvim @@ -1,5 +1,27 @@ # neovim ([bountysource fundraiser](https://www.bountysource.com/fundraisers/539-neovim-first-iteration)) +[](https://travis-ci.org/neovim/neovim) +[](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 @@ -252,7 +274,11 @@ and what is currently being worked on: #### Ubuntu/Debian - sudo apt-get install build-essential cmake libncurses5-dev + sudo apt-get install libtool autoconf cmake libncurses5-dev g++ + +#### FreeBSD 10 + + sudo pkg install cmake libtool sha #### Arch Linux @@ -263,16 +289,18 @@ and what is currently being worked on: * Install [Xcode](https://developer.apple.com/) * Install sha1sum +If you run into wget certificate errors, you may be missing the root SSL +certificates or have not set them up correctly: + Via MacPorts: - sudo port install md5sha1sum cmake libtool + sudo port install curl-ca-bundle + echo CA_CERTIFICATE=/opt/local/share/curl/curl-ca-bundle.crt >> ~/.wgetrc Via Homebrew: - brew install md5sha1sum cmake libtool - -#### TODO -* Release the Dockerfile which has this in it. + brew install curl-ca-bundle + echo CA_CERTIFICATE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt >> ~/.wgetrc ### Building @@ -285,8 +313,34 @@ 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. +Join the community on IRC in #neovim on Freenode or the [mailing list](https://groups.google.com/forum/#!forum/neovim) + +### 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. +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. <!-- vim: set tw=80: --> diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake new file mode 100644 index 0000000000..d0cedfb37d --- /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. Note that we prefer the static version. +find_library(LibUV_LIBRARY + NAMES libuv.a 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) 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 <tronic@zi.fi> +# 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) + 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/neovim.rb b/neovim.rb new file mode 100644 index 0000000000..45e8b4018a --- /dev/null +++ b/neovim.rb @@ -0,0 +1,16 @@ +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" + system "make", "PREFIX=#{prefix}" + end +end diff --git a/scripts/common.sh b/scripts/common.sh index d7653c6aa1..9efa3d5e6c 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" @@ -10,23 +23,34 @@ 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=$(sha1sum < "$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 --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 + # 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" + echo "Downloading $url..." + # download, untar and calculate sha1 sum in one pass + ($download_command | tee "$fifo" | \ + (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 } 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1c7829e7d6..a7e815fd7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,24 +10,35 @@ 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 (vim ${NEOVIM_SOURCES} ${IO_SOURCES}) +add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES}) -target_link_libraries (vim m uv pthread) +# 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) 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() endif() -include_directories ("${PROJECT_SOURCE_DIR}/src/proto") +include_directories ("${PROJECT_SOURCE_DIR}/src/proto") + +install(TARGETS nvim RUNTIME DESTINATION bin) diff --git a/src/arabic.c b/src/arabic.c index c8d3fc2a69..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 * @@ -42,8 +44,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 +94,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 +143,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 +194,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 +321,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 +448,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 +575,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 +712,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 +797,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 +904,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 +932,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 +959,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 +977,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 +1038,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 +1054,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 +1064,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 +1076,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 +1088,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 +1098,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 +1108,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/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 2e4d8cf1af..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])) @@ -319,9 +321,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 +346,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 +364,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 +417,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 +457,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 +502,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 +533,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 +549,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 +565,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 +587,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 +599,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 +611,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/proto/blowfish.pro b/src/blowfish.h index 51e4fa9ec5..d4d8f36429 100644 --- a/src/proto/blowfish.pro +++ b/src/blowfish.h @@ -1,3 +1,5 @@ +#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)); @@ -8,3 +10,4 @@ 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 bffae5388d..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 @@ -64,10 +97,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 +266,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 +293,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 +457,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 +479,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 +539,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 +550,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 +573,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 +591,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 +626,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 +687,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 +792,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 +838,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 +1129,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 +1185,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 +1263,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 +1283,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 +1479,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 +1542,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 +1618,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 +1640,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 +1666,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 +1681,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 +1703,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 +1814,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 +1902,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 +1918,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 +1945,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 +1963,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 +1984,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 +2040,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 +2062,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 +2091,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 +2118,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 +2133,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 +2141,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 +2189,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 +2209,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 +2301,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 +2322,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 +2344,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 +2359,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 +2381,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 +2395,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 +2412,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 +2421,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 +2430,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 +2475,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 +2490,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 +2501,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 +2604,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 +2619,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 +2786,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 +2803,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 +2830,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 +3556,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 +3580,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 +3612,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 +3654,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 +3680,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 +3694,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 +3935,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 +4117,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; @@ -4168,15 +4144,17 @@ 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 * 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 +4259,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 +4306,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 +4354,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 +4389,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 +4404,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 +4419,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 +4471,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/proto/buffer.pro b/src/buffer.h index 060008db77..3ca525612d 100644 --- a/src/proto/buffer.pro +++ b/src/buffer.h @@ -1,3 +1,5 @@ +#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)); @@ -79,3 +81,4 @@ 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 1eee20f66c..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)); @@ -56,13 +64,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 +256,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 +291,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 +349,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 +443,7 @@ int buflen; */ static char_u transchar_buf[7]; -char_u * transchar(c) -int c; +char_u *transchar(int c) { int i; @@ -469,8 +471,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 +485,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 +517,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 +537,7 @@ int c; * Lower case letters are used to avoid the confusion of <F1> 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 +552,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 +564,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 +587,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 +600,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 +609,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 +645,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 +660,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 +668,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 +680,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 +694,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 +704,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 +723,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 +741,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 +752,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 +766,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 +777,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 +789,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 +802,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 +818,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 +927,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 +950,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 +976,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 +1078,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 +1092,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 +1133,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 +1160,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 +1172,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 +1184,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 +1196,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 +1208,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 +1223,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 +1233,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 +1256,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 +1277,7 @@ int c; return islower(c); } -int vim_isupper(c) -int c; +int vim_isupper(int c) { if (c <= '@') return FALSE; @@ -1367,8 +1298,7 @@ int c; return isupper(c); } -int vim_toupper(c) -int c; +int vim_toupper(int c) { if (c <= '@') return c; @@ -1389,8 +1319,7 @@ int c; return TOUPPER_LOC(c); } -int vim_tolower(c) -int c; +int vim_tolower(int c) { if (c <= '@') return c; @@ -1414,8 +1343,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 +1355,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 +1370,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 +1387,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 +1411,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 +1496,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 +1511,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 +1532,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 +1552,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 +1562,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/proto/charset.pro b/src/charset.h index d0223f1e9c..d680522880 100644 --- a/src/proto/charset.pro +++ b/src/charset.h @@ -1,3 +1,5 @@ +#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)); @@ -62,3 +64,4 @@ 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 ad31128575..626271a7b5 100644 --- a/src/diff.c +++ b/src/diff.c @@ -12,7 +12,27 @@ */ #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 */ @@ -55,8 +75,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 +95,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 +126,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 +148,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 +162,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 +176,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 +194,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 +214,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 +420,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 +441,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 +510,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 +525,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 +555,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 +575,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 +724,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 +764,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 +919,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 +943,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 +952,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 +1010,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 +1072,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 +1246,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 +1262,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 +1282,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 +1367,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 +1395,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 +1446,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 +1463,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 +1565,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 +1627,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 +1635,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 +1744,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 +1787,7 @@ linenr_T lnum; /* * "dp" and "do" commands. */ -void nv_diffgetput(put) -int put; +void nv_diffgetput(int put) { exarg_T ea; @@ -1828,8 +1806,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 +2084,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 +2099,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 +2113,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 +2162,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 +2225,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/proto/diff.pro b/src/diff.h index 0093629033..5a2d32204e 100644 --- a/src/proto/diff.pro +++ b/src/diff.h @@ -1,3 +1,5 @@ +#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)); @@ -28,3 +30,4 @@ linenr_T diff_get_corresponding_line __ARGS((buf_T *buf1, linenr_T lnum1, 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 4584973526..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; @@ -1623,8 +1634,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 +1657,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 +1695,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 +1768,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 +1783,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 +1833,7 @@ char_u *str; } } -void listdigraphs() { +void listdigraphs(void) { int i; digr_T *dp; @@ -1867,8 +1872,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 +1929,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 +1971,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 +2047,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/proto/digraph.pro b/src/digraph.h index 5573b8c36d..c74e428979 100644 --- a/src/proto/digraph.pro +++ b/src/digraph.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_DIGRAPH_H +#define NEOVIM_DIGRAPH_H /* digraph.c */ int do_digraph __ARGS((int c)); int get_digraph __ARGS((int cmdline)); @@ -7,3 +9,4 @@ 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 4d245fbfaf..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 @@ -284,10 +316,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 +1298,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 +1369,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 +1409,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 +1452,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 +1467,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 +1496,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 +1511,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 +1736,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 +1756,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 +1773,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 +1800,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 +1821,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 +1847,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 +1902,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 +1934,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 +2067,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 +2178,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 +2188,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 +2255,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 +2272,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 +2297,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 +2341,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 +2355,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 +2366,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 +2382,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 +2406,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 +2532,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 +2637,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 +2728,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 +2743,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 +2765,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 +2778,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 +2809,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 +2826,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 +2836,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 +2873,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 +2886,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 +2922,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 +2934,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 +2972,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 +2983,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 +3001,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 +3037,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 +3278,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 +3312,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 +3343,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 +3412,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 +3430,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 +3457,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 +3499,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 +3876,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 +3889,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 +3913,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 +4095,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 +4146,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 +4159,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 +4171,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 +4188,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 +4209,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 +4735,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 +4789,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 +4879,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 +4938,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 +5141,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 +5464,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 +5566,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 +5601,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 +5632,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 +5649,10 @@ int c; * start_arrow() is called when an arrow key is used in insert mode. * For undo/redo it resembles hitting the <ESC> 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 +5666,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 +5679,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 +5692,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 +5724,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; /* <c-\><c-o>, don't move cursor */ +static void +stop_insert ( + pos_T *end_insert_pos, + int esc, /* called by ins_esc() */ + int nomove /* <c-\><c-o>, don't move cursor */ +) { int cc; char_u *ptr; @@ -5836,8 +5843,7 @@ int nomove; /* <c-\><c-o>, 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 +5862,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 +5876,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 +5903,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 +5930,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 +5970,7 @@ int oneright() { return OK; } -int oneleft() { +int oneleft(void) { if (virtual_active()) { int width; int v = getviscol(); @@ -6016,9 +6019,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 +6072,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 +6125,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 +6182,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 +6192,7 @@ char_u * get_last_insert() { * Get last inserted string, and remove trailing <Esc>. * 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 +6213,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 +6247,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 +6282,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 +6297,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 +6307,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 +6327,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 +6343,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 +6388,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 +6404,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 +6465,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 +6486,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 +6508,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 +6722,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 +6787,7 @@ int c; } } -static void ins_reg() { +static void ins_reg(void) { int need_redraw = FALSE; int regname; int literally = 0; @@ -6878,7 +6883,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 +6926,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 +6964,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 +7092,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 +7126,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 +7169,7 @@ int c; /* * <Insert> 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 +7196,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 +7216,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 +7246,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 +7272,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 +7290,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 +7599,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 +7630,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 +7686,7 @@ int dir; -static void ins_left() { +static void ins_left(void) { pos_T tpos; if ((fdo_flags & FDO_HOR) && KeyTyped) @@ -7716,8 +7713,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 +7729,7 @@ int c; start_arrow(&tpos); } -static void ins_end(c) -int c; +static void ins_end(int c) { pos_T tpos; @@ -7750,7 +7745,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 +7757,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 +7791,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 +7804,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 +7828,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 +7850,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 +7874,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 +7900,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 +8084,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 +8140,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 +8213,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 +8245,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 +8283,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 +8364,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 +8377,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/proto/edit.pro b/src/edit.h index 0284101df4..aa2b72d93b 100644 --- a/src/proto/edit.pro +++ b/src/edit.h @@ -1,3 +1,5 @@ +#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)); @@ -44,3 +46,4 @@ 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 bcf9c75730..4d120c82ce 100644 --- a/src/eval.c +++ b/src/eval.c @@ -12,10 +12,47 @@ */ #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 <math.h> @@ -263,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:" */ @@ -816,7 +853,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 +887,7 @@ void eval_init() { } #if defined(EXITFREE) || defined(PROTO) -void eval_clear() { +void eval_clear(void) { int i; struct vimvar *p; @@ -899,8 +936,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 +944,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 +952,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 +960,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 +975,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 +983,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 +1007,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 +1084,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 +1107,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 +1136,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 +1156,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 +1174,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 +1187,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 +1205,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 +1238,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 +1266,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 +1280,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 +1314,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 +1336,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 +1360,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 +1371,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 +1390,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 +1424,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 +1444,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 +1464,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 +1534,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 +1562,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 +1587,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 +1614,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 +1666,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 +1714,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 +1784,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 +1874,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 +1913,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 +1925,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 +1946,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 +1954,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 +1969,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 +1978,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 +1987,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 +1995,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 +2005,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 +2015,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 +2105,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 +2273,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 +2300,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 +2604,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 +2615,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 +2715,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 +2803,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 +2813,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 +2831,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 +2846,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 +2899,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 +2919,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 +2931,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 +3013,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 +3127,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 +3135,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 +3153,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 +3197,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 +3240,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 +3270,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 +3321,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 +3382,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 +3396,7 @@ typval_T *tv; /* * Delete all "menutrans_" variables. */ -void del_menutrans_vars() { +void del_menutrans_vars(void) { hashitem_T *hi; int todo; @@ -3474,9 +3426,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 +3451,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 +3558,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 +3594,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 +3659,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 +3722,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 +3794,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 +4053,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 +4197,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 +4334,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 +4589,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 +4818,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 +4885,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 +5004,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 +5060,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 +5117,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 +5136,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 +5153,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 +5163,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 +5193,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 +5209,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 +5218,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 +5228,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 +5258,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 +5267,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 +5307,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 +5375,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 +5439,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 +5460,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 +5476,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 +5494,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 +5514,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 +5529,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 +5548,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 +5569,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 +5588,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 +5599,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 +5625,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 +5642,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 +5666,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 +5711,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 +5738,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 +5760,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 +5832,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 +5879,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 +5974,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 +6021,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 +6037,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 +6048,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 +6078,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 +6103,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 +6121,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 +6131,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 +6175,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 +6190,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 +6207,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 +6222,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 +6234,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 +6287,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 +6297,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 +6323,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 +6344,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 +6356,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 +6388,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 +6406,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 +6420,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 +6474,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 +6585,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 +6659,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 +6687,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 +6726,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 +6746,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 +7075,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 +7102,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 +7124,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 +7154,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 +7179,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 +7241,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 +7443,7 @@ dict_T *selfdict; /* Dictionary for "self" */ * Give an error message with a function name. Handle <SNR> 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 +7459,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 +7478,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 +7495,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 +7517,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 +7531,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 +7548,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 +7557,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 +7612,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 +7620,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 +7628,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 +7648,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 +7662,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 +7676,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 +7691,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 +7700,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 +7711,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 +7737,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 +7745,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 +7756,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 +7769,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 +7807,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 +7825,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 +7855,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 +7876,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 +7888,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 +7915,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 +7923,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 +7963,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 +7996,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 +8010,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 +8018,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 +8037,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 +8055,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 +8063,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 +8100,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 +8129,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 +8137,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 +8150,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 +8198,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 +8206,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 +8220,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 +8234,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 +8299,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 +8323,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 +8366,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 +8383,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 +8394,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 +8402,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 +8410,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 +8459,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 +8494,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 +8506,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 +8524,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 +8532,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 +8540,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 +8602,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 +8616,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 +8680,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 +8722,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 +8794,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 +8837,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 +8861,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 +8869,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 +8931,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 +9027,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 +9066,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 +9074,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 +9082,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 +9090,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 +9107,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 +9121,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 +9136,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 +9146,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 +9177,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 +9198,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 +9206,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 +9214,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 +9226,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 +9281,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 +9308,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 +9350,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 +9363,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 +9405,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 +9441,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 +9464,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 +9517,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 +9600,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 +9608,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 +9617,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 +9625,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 +9638,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 +9660,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 +9669,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 +9695,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 +9721,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 +9737,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 +9812,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 +9833,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 +9856,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 +9864,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 +9892,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 +9911,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 +9937,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 +9976,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 +10004,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 +10012,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 +10020,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 +10028,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 +10054,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 +10062,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 +10119,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 +10162,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 +10185,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; @@ -10734,6 +10337,7 @@ typval_T *rettv; #ifdef FEAT_XTERM_SAVE "xterm_save", #endif + "neovim", NULL }; @@ -10773,9 +10377,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 +10393,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 +10401,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 +10426,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 +10451,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 +10477,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 +10501,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 +10518,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 +10526,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 +10534,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 +10546,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 +10576,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 +10590,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 +10637,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 +10729,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 +10737,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 +10745,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 +10786,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 +10802,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 +10817,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 +10829,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 +10864,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 +10872,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 +10880,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 +10932,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 +11002,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 +11010,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 +11040,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 +11048,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 +11063,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 +11085,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 +11125,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 +11133,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 +11141,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 +11156,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 +11172,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 +11190,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 +11265,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 +11279,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 +11294,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 +11302,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 +11310,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 +11318,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 +11471,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 +11479,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 +11510,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 +11532,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 +11541,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 +11549,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 +11557,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 +11618,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 +11626,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 +11637,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 +11665,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 +11697,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 +11752,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 +11770,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 +11794,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 +11803,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 +11822,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 +11837,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 +11861,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 +11892,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 +11903,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 +11939,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 +12150,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 +12183,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 +12198,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 +12207,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 +12227,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 +12236,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 +12319,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 +12333,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 +12373,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 +12558,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 +12597,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 +12641,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 +12729,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 +12737,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 +12751,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 +12770,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 +12797,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 +12805,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 +12813,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 +12823,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 +12846,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 +12917,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 +12925,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 +12948,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 +13094,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 +13118,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 +13134,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 +13181,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 +13192,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 +13260,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 +13289,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 +13303,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 +13352,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 +13385,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 +13393,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 +13454,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 +13493,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 +13501,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 +13510,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 +13562,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 +13575,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 +13585,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 +13593,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 +13606,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 +13620,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 +13645,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 +13668,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 +13704,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 +13791,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 +13803,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 +13846,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 +13892,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 +13965,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 +13979,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 +13992,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 +14017,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 +14068,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 +14101,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 +14116,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 +14125,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 +14140,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 +14154,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 +14166,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 +14206,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 +14252,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 +14261,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 +14271,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 +14292,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 +14314,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 +14391,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 +14408,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 +14457,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 +14487,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 +14571,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 +14595,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 +14620,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 +14660,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 +14677,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 +14700,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 +14717,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 +14740,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 +14748,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 +14762,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 +14776,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 +14810,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 +14819,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 +14920,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 +14935,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 +14954,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 +14976,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 +15001,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 +15009,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 +15028,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 +15045,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 +15054,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 +15068,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 +15077,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 +15091,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 +15100,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 +15111,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 +15135,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 +15170,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 +15193,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 +15207,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 +15269,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 +15280,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 +15384,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 +15431,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 +15451,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 +15477,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 +15539,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 +15611,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 +15659,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 +15668,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 +15676,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 +15684,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 +15692,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 +15701,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 +15709,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 +15726,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 +15737,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 +15760,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 +15771,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 +15790,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 +15805,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 +15820,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 +15884,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 +15937,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 +16007,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 +16016,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 +16032,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 +16063,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 +16100,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 +16114,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 +16161,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 +16181,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 +16201,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 +16258,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 +16275,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 +16319,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 +16369,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 +16383,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 +16414,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 +16431,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 +16444,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 +16452,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 +16482,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 +16494,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 +16507,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 +16553,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 +16658,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 +16675,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 +16688,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 +16716,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 +16733,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 +16755,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 +16805,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 +16864,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 +16951,7 @@ exarg_T *eap; /* * ":echohl {name}". */ -void ex_echohl(eap) -exarg_T *eap; +void ex_echohl(exarg_T *eap) { int id; @@ -17796,8 +16969,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 +17044,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 +17073,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 +17665,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 +17833,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 +17847,7 @@ char_u *p; * Return TRUE if "p" starts with "<SID>" 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 +17855,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 +17895,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 +17906,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 +17921,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 +17931,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 +17949,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 +17968,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 +17977,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 +18005,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 +18065,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 +18118,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 +18130,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 +18144,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 +18189,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 +18212,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 +18252,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, "<SNR>"); @@ -19110,8 +18264,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 +18314,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 +18339,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 +18359,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 +18375,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 +18705,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 +18715,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 +18741,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 +18754,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 +18806,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 +18874,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 +18883,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 +18907,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 +18960,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 +18981,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 +18993,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 +19015,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 +19028,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 +19041,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 +19057,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 +19114,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 +19153,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 +19214,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 +19233,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 +19269,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 +19522,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/proto/eval.pro b/src/eval.h index c0f707cab2..d63ea3dd8b 100644 --- a/src/proto/eval.pro +++ b/src/eval.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_EVAL_H +#define NEOVIM_EVAL_H /* eval.c */ void eval_init __ARGS((void)); void eval_clear __ARGS((void)); @@ -148,3 +150,4 @@ int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u * 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 d791d777dc..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, @@ -32,8 +69,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 +149,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 +239,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 +286,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 +330,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 +540,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 +672,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 +774,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 +826,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 +837,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 +972,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 +1188,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 +1295,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 +1370,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 +1397,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 +1406,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 +1425,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 +1471,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 +1699,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 +1727,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 +1780,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 +1857,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 +1881,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 +1896,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 +1959,7 @@ int convert UNUSED; /* convert the string */ * - write " CTRL-V <length> \n " in first line * - write " < <string> \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 +1995,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 +2004,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 +2019,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 +2036,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 +2082,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 +2105,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 +2114,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 +2130,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 +2287,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 +2386,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 +2403,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 +2453,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 +2465,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 +2515,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 +2599,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 +3167,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 +3180,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 +3304,7 @@ exarg_T *eap; /* * ":change" */ -void ex_change(eap) -exarg_T *eap; +void ex_change(exarg_T *eap) { linenr_T lnum; @@ -3340,8 +3331,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 +3450,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 +3463,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 +3494,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 +4405,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 +4464,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 +4561,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 +4615,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 +4624,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 +4633,7 @@ FILE *fp; } #if defined(EXITFREE) || defined(PROTO) -void free_old_sub() { +void free_old_sub(void) { vim_free(old_sub); } @@ -4657,8 +4643,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 +4684,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 +4857,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 +4880,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 +4922,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 +4938,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 +5117,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 +5313,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 +5321,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 +5332,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 +5433,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_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 209fcddd67..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)); @@ -64,8 +89,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 +271,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 +300,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 +339,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 +395,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 +479,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 +515,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 +526,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 +597,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 +621,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 +634,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 +648,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 +712,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 +924,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 +982,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 +996,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 +1022,7 @@ char_u *arg; /* * Dump the profiling info. */ -void profile_dump() { +void profile_dump(void) { FILE *fd; if (profile_fname != NULL) { @@ -1022,8 +1040,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 +1092,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 +1107,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 +1158,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 +1170,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 +1191,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 +1209,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 +1251,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 +1314,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 +1328,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 +1343,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 +1451,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 +1464,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 +1497,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 +1528,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 +1549,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 +1575,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 +1661,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 +1674,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 +1688,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 +1718,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 +1774,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 +1786,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 +1794,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 +1802,7 @@ exarg_T *eap; /* * ":argument" and ":sargument". */ -void ex_argument(eap) -exarg_T *eap; +void ex_argument(exarg_T *eap) { int i; @@ -1819,9 +1816,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 +1879,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 +1905,7 @@ exarg_T *eap; /* * ":argedit" */ -void ex_argedit(eap) -exarg_T *eap; +void ex_argedit(exarg_T *eap) { int fnum; int i; @@ -1946,8 +1939,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 +1949,7 @@ exarg_T *eap; /* * ":argdelete" */ -void ex_argdelete(eap) -exarg_T *eap; +void ex_argdelete(exarg_T *eap) { int i; int n; @@ -1991,8 +1982,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 +2110,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 +2146,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 +2207,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 +2225,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 +2325,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 +2333,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 +2388,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 +2396,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 +2404,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 +2419,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 +2446,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 +2753,7 @@ theend: /* * ":scriptnames" */ -void ex_scriptnames(eap) -exarg_T *eap UNUSED; +void ex_scriptnames(exarg_T *eap) { int i; @@ -2790,7 +2769,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 +2782,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 +2798,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 +2818,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 +2829,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 +2865,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 +2956,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 +3094,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 +3125,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 +3138,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 +3164,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 +3192,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 +3205,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 +3246,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 +3267,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 +3286,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 +3317,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 +3343,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 +3373,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 +3480,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 +3489,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 +3525,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 +3541,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 +3559,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/proto/ex_cmds2.pro b/src/ex_cmds2.h index 51efb73455..a01096cfd7 100644 --- a/src/proto/ex_cmds2.pro +++ b/src/ex_cmds2.h @@ -1,3 +1,5 @@ +#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)); @@ -91,3 +93,4 @@ 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 88fe8e1c5d..35aa970aac 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -12,6 +12,49 @@ */ #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; static int ex_pressedreturn = FALSE; @@ -222,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. @@ -303,8 +346,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 +363,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 +384,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 +464,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 +1167,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 +1198,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 +1211,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 +1225,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 +1248,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 +2186,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 +2210,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 +2239,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 +2331,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 +2460,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 +2483,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 +2521,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 +3247,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 +3286,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 +3458,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 +3474,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 +3486,7 @@ exarg_T *eap; * Function called for script command which is Not Implemented. NI! * Skips over ":perl <<EOF" constructs. */ -static void ex_script_ni(eap) -exarg_T *eap; +static void ex_script_ni(exarg_T *eap) { if (!eap->skip) ex_ni(eap); @@ -3461,8 +3499,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 +3516,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 +3532,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 +3551,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 +3623,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 +3841,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 +3891,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 +3944,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 +3969,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 +3991,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 +4071,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 +4079,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 +4096,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 +4104,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 +4112,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 +4135,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 +4150,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 +4163,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 +4179,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 +4188,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 +4199,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 +4210,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 +4219,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 +4235,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 +4250,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 +4267,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 +4306,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 +4327,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 +4461,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 +4569,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 +4582,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 +4696,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 +4756,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 +4765,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 +4779,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 +4817,7 @@ exarg_T *eap; /* * split and quote args for <f-args> */ -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 +4897,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 +5076,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 +5184,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 +5192,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 +5206,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 +5220,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 +5232,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 +5245,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 +5297,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 +5318,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 +5330,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 +5338,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 +5379,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 +5388,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 +5418,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 +5431,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 +5446,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 +5481,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 +5511,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 +5542,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 +5558,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 +5584,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 +5593,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 +5616,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 +5644,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 +5683,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 +5706,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 +5714,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 +5742,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 +5810,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 +5820,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 +5831,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 +5842,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 +5859,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 +5894,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 +5928,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 +5951,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 +5971,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 +5980,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 +5998,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 +6016,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 +6078,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 +6091,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 +6114,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 +6150,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 +6192,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 +6204,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 +6234,7 @@ exarg_T *eap; /* * ":find [+command] <file>" command. */ -static void ex_find(eap) -exarg_T *eap; +static void ex_find(exarg_T *eap) { char_u *fname; int count; @@ -6330,8 +6262,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 +6296,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 +6304,11 @@ exarg_T *eap; /* * ":edit <file>" 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 +6438,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 +6458,7 @@ exarg_T *eap UNUSED; * offset. * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) */ -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 +6521,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 +6572,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 +6586,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 +6612,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 +6674,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 +6688,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 +6717,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 +6729,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 +6749,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 +6765,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 +6828,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 +6876,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 +6891,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 +6923,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 +6935,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 +6947,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 +6967,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 +7006,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 +7014,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 +7022,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 +7030,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 +7041,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 +7049,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 +7079,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 +7161,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 +7190,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 +7209,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 +7229,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 +7391,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 +7405,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 +7435,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 +7456,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 +7467,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 +7576,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 +7606,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 +7616,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 +7634,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 +7644,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 +7707,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 +7716,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 +7737,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 +7750,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 +7799,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 +7856,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 +8073,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 +8129,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 +8195,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 +8467,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 +8508,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 +8552,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 +8566,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 +8581,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 +8597,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 +8775,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 +8818,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 +8846,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 +8880,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 +8894,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 +8953,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 +8972,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 +8982,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 +9002,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 +9012,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 +9033,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 +9055,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 +9122,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 +9136,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 +9150,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 +9161,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 +9219,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/proto/ex_docmd.pro b/src/ex_docmd.h index ff83cad83f..f3f9ca16ec 100644 --- a/src/proto/ex_docmd.pro +++ b/src/ex_docmd.h @@ -1,3 +1,5 @@ +#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)); @@ -67,3 +69,4 @@ 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 5f845c3f33..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)); @@ -84,7 +92,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 +102,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 +113,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 +124,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 +139,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 +279,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 +296,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 +306,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 +338,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 +384,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 +453,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 +534,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 +580,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 +590,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 +633,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 +676,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 +751,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 +766,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 +781,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 +796,7 @@ void *value; /* * ":if". */ -void ex_if(eap) -exarg_T *eap; +void ex_if(exarg_T *eap) { int error; int skip; @@ -854,8 +833,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 +861,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 +942,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 +1031,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 +1064,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 +1087,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 +1163,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 +1190,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 +1250,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 +1317,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 +1458,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 +1576,7 @@ exarg_T *eap; /* * ":endtry" */ -void ex_endtry(eap) -exarg_T *eap; +void ex_endtry(exarg_T *eap) { int idx; int skip; @@ -1797,8 +1764,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 +1820,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 +1900,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 +2008,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 +2025,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 +2039,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 +2047,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/proto/ex_eval.pro b/src/ex_eval.h index 7fc87410e0..3685899063 100644 --- a/src/proto/ex_eval.pro +++ b/src/ex_eval.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_EX_EVAL_H +#define NEOVIM_EX_EVAL_H /* ex_eval.c */ int aborting __ARGS((void)); void update_force_abort __ARGS((void)); @@ -36,3 +38,4 @@ void rewind_conditionals __ARGS((struct condstack *cstack, int idx, 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 dbef0a9449..c3f389e279 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -12,6 +12,38 @@ */ #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" /* * Variables shared between getcmdline(), redrawcmdline() and others. @@ -125,10 +157,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 +1579,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 +1615,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 +1625,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 +1636,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 +1648,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 +1656,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 +1667,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 +1677,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 +1707,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 +1718,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 +1737,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 +1969,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 +1989,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 +2007,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 +2044,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 +2054,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 +2153,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 +2168,7 @@ int shift; /* * Undo a putcmdline(c, FALSE). */ -void unputcmdline() { +void unputcmdline(void) { if (cmd_silent) return; msg_no_more = TRUE; @@ -2160,10 +2191,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 +2326,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 +2342,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 +2353,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 +2365,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 +2381,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 +2460,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 +2490,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 +2502,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 +2511,7 @@ void redrawcmdline() { cursorcmd(); } -static void redrawcmdprompt() { +static void redrawcmdprompt(void) { int i; if (cmd_silent) @@ -2508,7 +2532,7 @@ static void redrawcmdprompt() { /* * Redraw what is currently on the command line. */ -void redrawcmd() { +void redrawcmd(void) { if (cmd_silent) return; @@ -2541,7 +2565,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 +2573,7 @@ void compute_cmdrow() { + W_STATUS_HEIGHT(lastwin); } -static void cursorcmd() { +static void cursorcmd(void) { if (cmd_silent) return; @@ -2568,8 +2592,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 +2610,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 +2618,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 +2634,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 +2775,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 +2961,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 +2978,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 +2986,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 +3065,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 +3102,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 +3119,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 +3140,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 +3294,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 +3321,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 +3354,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 +3514,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 +3527,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 +3577,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 +3622,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 +3646,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 +3912,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 +4065,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 +4111,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 +4146,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 +4210,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 +4273,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 +4306,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 +4328,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 +4391,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 +4402,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 +4458,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 +4484,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 +4542,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 +4557,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 +4573,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 +4587,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 +4600,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 +4622,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 +4638,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 +4673,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 +4686,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 +4708,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 +4757,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 +4790,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 +4818,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 +4848,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 +4940,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 +4963,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 +5001,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 +5043,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 +5096,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 +5182,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 +5192,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 +5209,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 +5425,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/proto/ex_getln.pro b/src/ex_getln.h index e3a642283f..bf04476e2f 100644 --- a/src/proto/ex_getln.pro +++ b/src/ex_getln.h @@ -1,3 +1,5 @@ +#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, @@ -64,3 +66,4 @@ 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 a76f37fd26..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 * @@ -37,8 +41,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 +130,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 +207,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 +256,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 +277,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 +299,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 +320,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 +350,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 +360,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 +477,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 +525,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 +552,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 +618,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 +684,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 +706,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 +1382,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 +1434,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 +1488,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 +1560,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 +1586,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 +1611,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 +1686,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 +1728,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 +1757,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 +1777,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 +1787,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 +1815,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 +1853,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 +2106,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 +2116,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 +2124,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/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 d05181e654..482c47e17d 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -12,6 +12,38 @@ */ #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" #if defined(HAVE_UTIME) && defined(HAVE_UTIME_H) @@ -121,11 +153,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 +208,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 +2050,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 +2066,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 +2088,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 +2110,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 +2132,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 +2151,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 +2188,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 +2235,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 +2250,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 +2274,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 +2352,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 +2388,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 +2420,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 +2451,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 +2491,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 +4122,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 +4161,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 +4174,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 +4200,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 +4240,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 +4250,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 +4267,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 +4285,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 +4495,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 +4562,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 +4594,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 +4634,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 +4675,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 +4704,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 +4728,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 +4758,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 +4798,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 +4831,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 +4847,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 +5019,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 +5053,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 +5089,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 +5257,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 +5318,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 +5360,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 +5586,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 +5714,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 +5729,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 +5741,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 +5770,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 +5793,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 +5944,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 +6181,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 +6237,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 +6248,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 +6263,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 +6307,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 +6340,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 +6363,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 +6380,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 +6393,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 +6401,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 +6430,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 +6444,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 +6469,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 +6482,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 +6514,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 +6531,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 +6551,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 +6572,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 +6613,7 @@ char_u *old_ei; * * Mostly a {group} argument can optionally appear before <event>. */ -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 +6721,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 +6750,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 +6965,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 +7014,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 +7061,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, "<nomodeline>", 12) == 0) { *argp = skipwhite(*argp + 12); @@ -7103,9 +7077,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 +7163,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 +7248,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 <afile> on cmdline */ -int force; /* when TRUE, ignore autocmd_busy */ -buf_T *buf; /* buffer for <abuf> */ +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 <afile> on cmdline */ + int force, /* when TRUE, ignore autocmd_busy */ + buf_T *buf /* buffer for <abuf> */ +) { return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf, NULL); @@ -7285,13 +7265,7 @@ buf_T *buf; /* buffer for <abuf> */ * 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 +7277,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 <afile> on cmdline */ -int force; /* when TRUE, ignore autocmd_busy */ -buf_T *buf; /* buffer for <abuf> */ -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 <afile> on cmdline */ + int force, /* when TRUE, ignore autocmd_busy */ + buf_T *buf, /* buffer for <abuf> */ + int *retval /* pointer to caller's retval */ +) { int did_cmd; @@ -7328,7 +7304,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 +7312,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 +7331,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 <afile> 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 <afile> 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 <abuf> */ -exarg_T *eap; /* command arguments */ + int force, /* when TRUE, ignore autocmd_busy */ + int group, /* group ID, or AUGROUP_ALL */ + buf_T *buf, /* buffer for <abuf> */ + exarg_T *eap /* command arguments */ +) { char_u *sfname = NULL; /* short file name */ char_u *tail; @@ -7716,14 +7694,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 +7712,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 +7781,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 +7837,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 +7882,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 +7895,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 +7946,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 +7960,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 +7979,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 +8068,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 +8157,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 +8196,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/proto/fileio.pro b/src/fileio.h index ec83342e4d..add97d37d6 100644 --- a/src/proto/fileio.pro +++ b/src/fileio.h @@ -1,3 +1,5 @@ +#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, @@ -80,3 +82,4 @@ char_u *file_pat_to_reg_pat __ARGS((char_u *pat, char_u *pat_end, 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 b3a3d84a2b..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 */ @@ -104,9 +118,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 +129,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 +143,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 +252,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 +277,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 +291,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 +304,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 +313,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 +322,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 +331,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 +340,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 +349,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 +359,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 +368,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 +378,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 +415,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 +424,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 +433,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 +450,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 +469,7 @@ void newFoldLevel() { } } -static void newFoldLevelWin(wp) -win_T *wp; +static void newFoldLevelWin(win_T *wp) { fold_T *fp; int i; @@ -498,7 +491,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 +501,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 +528,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 +544,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 +658,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 +746,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 +759,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 +792,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 +804,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 +922,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 +934,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 +952,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 +983,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 +994,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 +1026,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 +1062,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 +1087,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 +1100,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 +1122,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 +1161,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 +1262,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 +1280,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 +1328,7 @@ int recursive; /* * Delete nested folds in a fold. */ -void deleteFoldRecurse(gap) -garray_T *gap; +void deleteFoldRecurse(garray_T *gap) { int i; @@ -1370,12 +1341,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 +1355,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 +1448,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 +1474,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 +1512,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 +1546,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 +1561,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 +1581,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 +1614,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 +1639,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 +1684,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 +1780,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 +1895,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 +2499,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 +2521,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 +2578,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 +2632,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 +2667,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 +2698,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 +2712,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 +2803,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 +2820,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 +2890,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 +2918,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 +2938,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 +2962,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 +3008,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/proto/fold.pro b/src/fold.h index 6f498872e7..3ad08b01e5 100644 --- a/src/proto/fold.pro +++ b/src/fold.h @@ -1,3 +1,5 @@ +#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)); @@ -48,3 +50,4 @@ char_u *get_foldtext __ARGS((win_T *wp, linenr_T lnum, linenr_T lnume, 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 92e1ece639..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: @@ -134,8 +155,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 +170,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 +201,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 +232,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 +240,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 +293,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 +305,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 +339,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 +363,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 +373,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 +390,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 +423,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 +435,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 +452,7 @@ void CancelRedo() { */ static int save_level = 0; -void saveRedobuff() { +void saveRedobuff(void) { char_u *s; if (save_level++ == 0) { @@ -457,7 +474,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 +487,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 +497,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 +550,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 +559,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 +569,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 +584,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 +606,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 +614,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 +627,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 +683,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 +700,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 +749,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 +771,7 @@ int start_redo_ins() { return OK; } -void stop_redo_ins() { +void stop_redo_ins(void) { block_redo = FALSE; } @@ -775,7 +780,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 +810,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 +931,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 +954,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 +968,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 +1052,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 +1092,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 +1102,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 +1123,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 +1140,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 +1160,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 +1182,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 +1202,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 +1269,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 +1280,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 +1290,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 +1298,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 +1311,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 +1332,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 +1477,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 +1490,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 +1504,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 +1514,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 +1530,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 +1543,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 +1552,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 +1586,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 +2360,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 +2463,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 +2506,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 +2552,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 +3023,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 +3038,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 +3048,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 +3088,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 +3108,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 +3169,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 +3205,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 +3273,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 +3309,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 +3356,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 +3419,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 +3542,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 +3690,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 +3749,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 +3787,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 +3809,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 +4008,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 +4104,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 +4173,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 +4243,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/proto/getchar.pro b/src/getchar.h index df3c9836cd..131286ee50 100644 --- a/src/proto/getchar.pro +++ b/src/getchar.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_GETCHAR_H +#define NEOVIM_GETCHAR_H /* getchar.c */ void free_buff __ARGS((struct buffheader *buf)); char_u *get_recorded __ARGS((void)); @@ -72,3 +74,4 @@ char_u *check_map __ARGS((char_u *keys, int mode, int exact, int ign_mod, 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 7f41509e83..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 @@ -96,9 +102,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 +121,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 +158,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 +212,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 +234,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 +257,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 +279,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 +300,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 +353,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 +388,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 +419,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 +559,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 +652,7 @@ int_u *c; return AUTOMATA_SPECIAL; } -void hangul_keyboard_set() { +void hangul_keyboard_set(void) { int keyboard; char *s; @@ -683,9 +670,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 +731,7 @@ int len; return len; } -void hangul_input_clear() { +void hangul_input_clear(void) { sp = 0; f = F_NULL; m = M_NULL; @@ -1416,11 +1401,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 +1428,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/proto/hangulin.pro b/src/hangulin.h index adfde142ff..1023955c0d 100644 --- a/src/proto/hangulin.pro +++ b/src/hangulin.h @@ -1,3 +1,5 @@ +#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)); @@ -7,3 +9,4 @@ 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 5869b55a49..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 @@ -151,7 +168,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 +176,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 +189,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 +248,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 +263,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 +299,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 +307,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 +315,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 +330,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 +361,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 +370,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 +379,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 +397,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 +478,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 +721,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 +1329,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 +1339,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 +1352,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 +1361,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 +1370,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 +1379,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 +1396,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 +1409,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 +1421,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 +1443,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 +1470,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 +1483,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 +1551,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 +1561,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 +1600,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 +1622,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 +1632,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 +1645,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 +1660,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 +1705,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 +1821,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 +1834,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 +1862,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 +1878,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 +1898,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 +1909,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 +1939,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 +1959,7 @@ char *type; prt_write_string("\n"); } -void mch_print_cleanup() { +void mch_print_cleanup(void) { if (prt_out_mbyte) { int i; @@ -2055,10 +1989,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 +2024,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 +2032,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 +2054,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 +2070,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 +2098,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 +2118,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 +2139,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 +2422,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 +2464,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 +2835,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 +2869,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 +2879,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 +2916,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 +2937,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 +3118,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 +3139,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/proto/hardcopy.pro b/src/hardcopy.h index 3744181371..84cbe02be8 100644 --- a/src/proto/hardcopy.pro +++ b/src/hardcopy.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_HARDCOPY_H +#define NEOVIM_HARDCOPY_H /* hardcopy.c */ char_u *parse_printoptions __ARGS((void)); char_u *parse_printmbfont __ARGS((void)); @@ -19,3 +21,4 @@ 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 4bab277f78..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 @@ -40,8 +41,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 +53,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 +64,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 +87,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 +95,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 +155,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 +169,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 +188,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 +210,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 +222,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 +233,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 +244,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 +379,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/proto/hashtab.pro b/src/hashtab.h index c90f44898e..a1dfa63162 100644 --- a/src/proto/hashtab.pro +++ b/src/hashtab.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_HASHTAB_H +#define NEOVIM_HASHTAB_H /* hashtab.c */ void hash_init __ARGS((hashtab_T *ht)); void hash_clear __ARGS((hashtab_T *ht)); @@ -13,3 +15,4 @@ 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 2ef1d61cba..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 <sys/types.h> #include <sys/stat.h> #if defined(UNIX) # include <sys/wait.h> #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)); @@ -83,8 +94,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 +111,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 +168,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 +204,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 +237,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 +247,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 +256,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 +323,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 +340,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 +349,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 +380,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 +438,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 +452,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 +473,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; @@ -554,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 { @@ -595,11 +594,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 +607,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 +618,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 +632,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 +689,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 +748,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 +961,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 +1000,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 +1181,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 +1216,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 +1237,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 +1257,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 +1409,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 +1456,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 +1491,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 +1544,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 +1603,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 +1656,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 +1709,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 +1779,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 +1803,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 +1929,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 +2020,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 +2138,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 +2204,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 +2257,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 +2289,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/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 <kahn@zk3.dec.com> - * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> - * - * 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 <sys/types.h> /* pid_t */ -# include <sys/stat.h> /* 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 <kahn@zk3.dec.com> + * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> + * + * 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 <sys/types.h> /* pid_t */ +# include <sys/stat.h> /* 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 02da51fb59..c5d7d528cf 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 @@ -70,7 +102,18 @@ 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)); +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)); @@ -82,7 +125,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 */ /* @@ -105,18 +148,11 @@ 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 * 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 +162,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 +184,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 +193,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 +239,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 +246,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 +338,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 +389,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 +447,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 +511,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) @@ -605,9 +568,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 */ @@ -814,8 +779,7 @@ void main_loop(cmdwin, noexmode) /* Exit properly */ -void getout(exitval) - int exitval; +void getout(int exitval) { buf_T *buf; win_T *wp; @@ -901,10 +865,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])); @@ -918,7 +884,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) @@ -942,6 +908,7 @@ static void init_locale() { vim_free(p); textdomain(VIMPACKAGE); } + TIME_MSG("locale set"); } #endif @@ -956,8 +923,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; @@ -966,39 +932,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; @@ -1006,11 +966,31 @@ static void parse_command_name(parmp) } } +static bool parse_char_i(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. */ -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; @@ -1500,14 +1480,158 @@ 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(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(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(void) +{ + 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(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(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(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(void) +{ + 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(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(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 + } } /* * 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? */ @@ -1531,7 +1655,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) @@ -1561,8 +1685,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; @@ -1677,8 +1800,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; @@ -1780,8 +1902,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; @@ -1802,8 +1923,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; @@ -1839,8 +1959,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; @@ -1969,21 +2088,23 @@ 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); } -#endif /* NO_VIM_MAIN */ +#endif /* NO_VIM_MAIN */ /* * 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; @@ -2014,8 +2135,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 @@ -2035,9 +2155,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 */ @@ -2056,8 +2178,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); } @@ -2066,8 +2187,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); @@ -2077,7 +2197,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[]) = { @@ -2166,7 +2286,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); @@ -2186,8 +2306,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); @@ -2208,8 +2327,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; @@ -2219,9 +2340,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; @@ -2232,10 +2351,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/proto/main.pro b/src/main.h index a93b8de2ae..1e407ae154 100644 --- a/src/proto/main.pro +++ b/src/main.h @@ -1,3 +1,5 @@ +#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)); @@ -25,3 +27,4 @@ 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 67d962dc9e..db274cda50 100644 --- a/src/mark.c +++ b/src/mark.c @@ -12,6 +12,25 @@ */ #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" /* * This file contains routines to maintain and manipulate marks. @@ -38,8 +57,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 +67,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 +135,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 +187,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 +199,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 +252,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 +285,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 +408,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 +452,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 +488,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 +513,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 +528,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 +553,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 +580,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 +591,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 +615,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 +650,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 +702,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 +773,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 +816,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 +889,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 +1032,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 +1103,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 +1131,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 +1147,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 +1155,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 +1172,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 +1218,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 +1273,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 +1297,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 +1327,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 +1381,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 +1393,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/proto/mark.pro b/src/mark.h index 47623f4847..f78a41bbc4 100644 --- a/src/proto/mark.pro +++ b/src/mark.h @@ -1,3 +1,5 @@ +#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)); @@ -32,3 +34,4 @@ 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 8b7abe15ee..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 @@ -380,8 +391,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 +407,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 +454,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 +493,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 +660,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 +671,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 +692,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 +717,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 +861,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 +878,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 +905,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 +927,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 +958,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 +988,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 +1254,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 +1277,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 +1291,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 +1316,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 +1330,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 +1349,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 +1364,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 +1382,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 +1391,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 +1409,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 +1423,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 +1461,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 +1503,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 +1516,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 +1532,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 +1546,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 +1561,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 +1577,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 +1615,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 +1659,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 +1679,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 +1698,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 +1711,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 +1734,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 +1773,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 +1823,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 +1843,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 +1890,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 +2093,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 +2120,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 +2413,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 +2441,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 +2752,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 +2772,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 +2782,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 +2802,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 +2880,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 +2961,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 +2987,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 +3015,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 +3067,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 +3081,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 +3113,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 +3177,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 +3221,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 +3243,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 +3257,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 +3274,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 +3292,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 +3309,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 +3340,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 +3371,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 +3386,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 +3453,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 +3481,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 +3527,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 +3535,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 +3584,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 +3635,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 +3705,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 +3717,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 +3728,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 +3801,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 +3813,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 +3890,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 +3904,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 +3943,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 +3956,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 +3976,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/proto/mbyte.pro b/src/mbyte.h index c440d62a4e..b9b5aa05d7 100644 --- a/src/proto/mbyte.pro +++ b/src/mbyte.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_MBYTE_H +#define NEOVIM_MBYTE_H /* mbyte.c */ int enc_canon_props __ARGS((char_u *name)); char_u *mb_init __ARGS((void)); @@ -98,3 +100,4 @@ 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 2969a19795..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 @@ -109,9 +117,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 +209,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 +223,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 +253,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 +292,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 +305,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 +383,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 +436,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 +457,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 +492,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 +591,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 +604,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 +612,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 +620,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 +628,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 +644,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 +665,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 +743,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 +779,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 +797,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 +806,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 +816,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 +830,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 +863,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 +934,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 +960,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 +1016,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 +1042,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 +1051,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 +1063,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 +1073,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 +1147,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 +1158,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 +1167,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 +1186,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 +1201,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 +1231,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 +1252,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/proto/memfile.pro b/src/memfile.h index 3983b4799c..0ea6b9fd17 100644 --- a/src/proto/memfile.pro +++ b/src/memfile.h @@ -1,3 +1,5 @@ +#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)); @@ -16,3 +18,4 @@ 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 15d5416829..292d09a37a 100644 --- a/src/memline.c +++ b/src/memline.c @@ -43,8 +43,30 @@ */ #include "vim.h" - -#ifndef UNIX /* it's in os_unix.h for Unix */ +#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_defs.h for Unix */ # include <time.h> #endif @@ -255,8 +277,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 +410,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 +434,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 +549,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 +630,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 +643,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 +710,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 +723,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 +746,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 +763,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 +775,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 +783,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 +797,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 +825,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 +885,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 +896,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 +922,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 +1493,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 +1699,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 "" (<currentdir>/"") */ -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 +1730,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 +1819,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 +1908,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 +1953,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 +2031,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 +2039,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 +2047,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 +2065,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 +2138,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 +2154,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 +2175,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 +2192,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 +2657,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 +2687,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 +2835,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 +2863,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 +2903,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 +2941,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 +3037,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 +3057,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 +3089,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 +3270,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 +3306,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 +3338,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 +3406,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 +3469,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 +3511,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 +3570,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 +3606,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 +4009,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 +4067,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 +4121,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 +4132,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 +4153,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 +4179,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 +4216,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 +4243,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 +4288,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 +4494,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 +4610,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/proto/memline.pro b/src/memline.h index 97806d38a2..7a18633d25 100644 --- a/src/proto/memline.pro +++ b/src/memline.h @@ -1,3 +1,5 @@ +#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)); @@ -39,3 +41,4 @@ void ml_decrypt_data __ARGS((memfile_T *mfp, char_u *data, off_t offset, 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 12e91b0ae6..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 */ @@ -53,8 +62,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 +273,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 +519,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 +568,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 +677,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 +702,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 +718,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 +771,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 +847,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 +951,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 +996,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 +1060,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 +1080,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 +1089,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 +1108,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 +1171,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 +1192,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 +1238,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 +1248,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 +1257,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 +1266,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 +1274,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 +1284,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 +1296,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 +1410,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 +1478,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 +1540,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 +1554,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 +1584,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 +1597,7 @@ char_u *name; * Isolate the menu name. * Skip the menu name, and translate <Tab> 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/proto/menu.pro b/src/menu.h index 80460d2de2..0d76b523bd 100644 --- a/src/proto/menu.pro +++ b/src/menu.h @@ -1,3 +1,5 @@ +#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, @@ -21,3 +23,4 @@ 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 9a9fd87f72..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 <math.h> @@ -100,8 +114,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 +124,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 +136,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 +201,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 +243,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 +341,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 +389,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 +398,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 +412,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 +430,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 +452,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 +486,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 +503,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 +601,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 +619,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 +642,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 +669,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 +713,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 +731,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 +755,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 +770,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 +973,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 +991,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 +1006,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 +1015,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 +1056,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 +1081,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 +1089,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 +1115,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 +1134,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 +1146,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 +1219,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 +1249,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 +1283,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 +1304,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 +1371,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 +1386,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 +1484,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 +1519,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 +1534,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 +1556,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 +1566,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 +1612,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 +1798,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 +1819,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 +1868,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 +1912,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 +1920,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 +1933,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 +1950,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 +1962,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 +1971,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 +1993,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 +2018,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 +2027,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 +2076,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 +2281,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 +2334,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 +2358,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 +2375,7 @@ int attr; } } -void msg_moremsg(full) -int full; +void msg_moremsg(int full) { int attr; char_u *s = (char_u *)_("-- More --"); @@ -2448,7 +2392,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 +2421,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 +2436,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 +2446,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 +2469,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 +2480,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 +2499,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 +2510,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 +2565,7 @@ int maxlen; } } -int redirecting() { +int redirecting(void) { return redir_fd != NULL || *p_vfile != NUL || redir_reg || redir_vname ; @@ -2633,7 +2575,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 +2584,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 +2593,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 +2604,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 +2615,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 +2627,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 +2645,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 +2673,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 +2707,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 +2803,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 +2840,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 +2972,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 +2980,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 +2990,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 +3002,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 +3029,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 +3050,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 +3067,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 +3152,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/proto/message.pro b/src/message.h index ece1985213..bd1ef4242c 100644 --- a/src/proto/message.pro +++ b/src/message.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_MESSAGE_H +#define NEOVIM_MESSAGE_H /* message.c */ int msg __ARGS((char_u *s)); int verb_msg __ARGS((char_u *s)); @@ -78,3 +80,4 @@ 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 92fc47189b..2d59948e60 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -12,7 +12,37 @@ */ #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)); static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name)); @@ -25,15 +55,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 +71,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 +80,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 +105,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 +318,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 +410,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 +451,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 +496,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 +1373,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 +1507,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 +1637,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 +1689,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 +1724,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 +1772,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 +1800,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 +1811,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 +1838,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 +1853,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 +1987,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 +2021,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 +2036,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 +2059,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 +2158,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 +2193,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 +2230,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 +2239,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 +2249,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 +2261,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 +2277,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 +2294,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 +2329,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 +2350,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 +2370,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 +2392,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 +2400,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 +2411,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 +2421,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 +2439,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 +2469,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 +2504,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 +2665,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 +2687,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 +2707,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 +2756,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 +2796,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 +2829,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 +2929,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 +2989,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 +3023,7 @@ int *mouse_used; return i; } -void msgmore(n) -long n; +void msgmore(long n) { long pn; @@ -3076,7 +3070,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 +3080,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 +3109,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 +3141,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 +3156,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 +3165,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 +3181,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 +3434,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 +3574,7 @@ int *mustfree; * Check if the directory "vimdir/<version>" 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 +3595,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 +3610,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 +3644,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 +3679,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 +3712,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 +3726,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 +3747,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 +3860,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 +3887,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 +3960,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 +3982,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 +4010,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 +4025,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 +4039,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 +4055,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 +4071,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 +4083,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 +4098,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 +4133,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 +4153,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 +4164,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 +4198,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 +4216,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 +4233,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 +4243,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 +4275,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 +4316,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 +4358,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 +4413,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 +4448,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 +4456,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 +4478,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 +4496,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 +4591,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 +4630,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 +4640,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 +4662,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 +4695,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 +4718,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 +4745,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 +4777,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 +4824,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 +4863,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 +4875,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 +4902,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 +4910,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 +4924,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 +4975,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 +5060,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 +5082,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 +5119,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 +5161,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 +5204,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 +5222,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 +5348,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 +5376,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 +5400,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 +5411,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 +5437,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 +5464,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 +5496,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 +5509,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 +5538,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 +5746,7 @@ buf_T *buf; } } -int get_c_indent() { +int get_c_indent(void) { pos_T cur_curpos; int amount; int scope_amount; @@ -7483,9 +7432,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 +7537,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 +7580,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 +7611,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 +7770,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 +7797,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 +7832,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 +7854,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 +7864,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 +7876,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 +7915,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 +7983,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 +8027,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 +8040,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 +8240,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 +8260,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 +8295,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 +8363,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 +8395,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 +8546,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 +8605,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 +8627,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 +8647,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 +8670,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 +8807,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 +8817,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 +8875,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 +8938,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 +9019,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 +9033,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/proto/misc1.pro b/src/misc1.h index 0497096791..ea7cb1b7e7 100644 --- a/src/proto/misc1.pro +++ b/src/misc1.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_MISC1_H +#define NEOVIM_MISC1_H /* misc1.c */ int get_indent __ARGS((void)); int get_indent_lnum __ARGS((linenr_T lnum)); @@ -115,3 +117,4 @@ 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 e18de18258..544a45a315 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -11,6 +11,29 @@ * 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() */ @@ -22,7 +45,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 +59,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 +69,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 +86,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 +109,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 +127,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 +305,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 +316,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 +343,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 +358,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 +389,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 +403,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 +444,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 +459,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 +511,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 +520,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 +531,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 +595,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 +622,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 +639,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 +684,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 +692,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 +705,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 +721,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 +735,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 +821,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 +840,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 +865,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 +1009,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 +1027,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 +1043,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 +1053,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 +1098,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 +1111,7 @@ int csh_like_shell() { * with "<" like "<cfile>". * 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 +1188,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 +1201,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 +1213,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 +1230,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 +1280,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 +1293,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 +1305,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 +1318,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 +1328,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 +1347,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 +1380,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 +1458,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 +1481,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 +1504,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 +1550,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 +1567,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 +1588,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 +1603,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 +1615,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 +1624,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 +1637,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 +1655,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 +1682,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 +1707,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 +1720,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 +1732,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 +2060,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 +2075,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 +2104,7 @@ int *modifiers; /* * Change <xHome> to <Home>, <xUp> to <Up>, etc. */ -int handle_x_keys(key) -int key; +int handle_x_keys(int key) { switch (key) { case K_XUP: return K_UP; @@ -2195,9 +2131,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 +2227,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 +2268,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 +2391,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 +2423,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 +2442,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 +2469,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 +2480,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 +2498,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 +2519,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 +2534,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 +2562,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 +2597,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 +2608,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 +2677,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 +2694,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 +2704,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 +2731,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 +2747,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 +2795,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 +2971,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 +3031,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 +3079,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 +3087,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 +3096,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 +3107,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 +3127,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 +3144,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 +3163,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 +3184,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 +3209,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 +3227,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 +3518,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 +3829,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 +3853,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 +3875,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 +4259,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 +4271,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 +4286,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 +4303,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 +4366,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 +4403,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 +4480,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 +4518,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 +4532,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 +4546,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 +4561,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 +4597,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 +4651,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 +4669,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 +4686,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 +4867,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 +4888,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 +4944,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 +4960,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 +5059,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 +5092,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 +5110,7 @@ char *name; return found ? i - 1 : -1; } -static int newenv() { +static int newenv(void) { char **env, *elem; int i, esize; @@ -5252,7 +5135,7 @@ static int newenv() { return 0; } -static int moreenv() { +static int moreenv(void) { int esize; char **env; @@ -5266,8 +5149,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 +5173,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 +5200,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 +5216,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 +5227,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 +5239,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 +5252,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 +5268,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 +5282,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 +5308,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 +5322,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 +5358,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/proto/misc2.pro b/src/misc2.h index c0fd06ff77..7beb681661 100644 --- a/src/proto/misc2.pro +++ b/src/misc2.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_MISC2_H +#define NEOVIM_MISC2_H /* misc2.c */ int virtual_active __ARGS((void)); int getviscol __ARGS((void)); @@ -131,3 +133,4 @@ 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 ed63dd212b..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)); @@ -42,8 +53,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 +109,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 +118,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 +306,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 +316,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 +342,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 +353,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 +376,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 +391,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 +410,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 +426,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 +440,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 +448,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 +457,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 +474,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 +484,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 +496,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 +588,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 +611,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 +627,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 +659,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 +667,7 @@ win_T *wp; ; } -int curwin_col_off() { +int curwin_col_off(void) { return win_col_off(curwin); } @@ -675,15 +676,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 +692,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 +922,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 +1003,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 +1061,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 +1088,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 +1105,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 +1153,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 +1194,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 +1220,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 +1245,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 +1258,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 +1271,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 +1385,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 +1410,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 +1584,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 +1642,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 +1745,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 +1931,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 +1984,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 +2144,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/proto/move.pro b/src/move.h index 595e3b8dd7..bf3371fa2d 100644 --- a/src/proto/move.pro +++ b/src/move.h @@ -1,3 +1,5 @@ +#ifndef NEOVIM_MOVE_H +#define NEOVIM_MOVE_H /* move.c */ void update_topline_redraw __ARGS((void)); void update_topline __ARGS((void)); @@ -39,3 +41,4 @@ 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 c141f468b2..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. @@ -384,9 +417,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 +434,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 +455,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 +500,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 +1172,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 +1186,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 +1809,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 +1856,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 +1924,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 +2601,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 +2623,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 +2653,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 +2682,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 +2697,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 +2723,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 +2734,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 +2763,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 +2773,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 +2887,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 +2897,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 +2924,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 +2937,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 +2947,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 +2955,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 +2964,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 +2989,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 +3070,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 +3122,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 +3131,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 +3151,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 +3165,7 @@ void pop_showcmd() { display_showcmd(); } -static void display_showcmd() { +static void display_showcmd(void) { int len; cursor_off(); @@ -3191,8 +3192,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 +3248,7 @@ int check; * number of rows by which the current window has changed * (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) */ -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 +3325,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 +3334,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 +3349,7 @@ cmdarg_T *cap; /* * <Help> and <F1> 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 +3358,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 +3368,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 +3385,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 +3409,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 +3528,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 +3653,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 +3687,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 +3696,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 +3705,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 +3752,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 +4178,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 +4192,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 +4249,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 +4262,7 @@ cmdarg_T *cap; /* * Handle CTRL-H <Backspace> 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 +4274,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 +4287,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 +4302,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 +4312,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 +4332,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 +4353,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 +4557,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 +4593,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 +4602,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 +4676,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 +4764,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 +4824,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) { /* <S-Up> is page up */ @@ -4870,8 +4843,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) { /* <S-Down> is page down */ @@ -4901,8 +4873,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 +4910,7 @@ cmdarg_T *cap; /* * <End> 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 +4923,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 +4944,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 +4971,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 +4980,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 +5018,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 +5051,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 +5309,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 +5357,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 +5379,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 +5391,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 +5409,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 +5425,7 @@ cmdarg_T *cap; /* * <Undo> 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 +5436,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 +5606,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 +5650,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 +5672,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 +5696,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 +5750,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 +5776,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 +5796,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 +5812,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 +5827,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 +5860,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 +5895,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 +5931,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 +5951,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 +6040,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 +6049,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 +6059,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 +6097,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 +6106,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 +6117,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 +6632,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 +6666,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 +6682,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 +6693,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 +6713,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 +6727,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 +6745,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 +6768,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 +6786,7 @@ cmdarg_T *cap; /* * <Home> 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 +6802,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 +6821,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 +6836,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 +6915,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 +6938,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 +6952,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 +6969,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 +6994,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 +7010,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 +7037,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 +7061,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 +7109,7 @@ cmdarg_T *cap; /* * Handle "A", "a", "I", "i" and <Insert> commands. */ -static void nv_edit(cap) -cmdarg_T *cap; +static void nv_edit(cmdarg_T *cap) { /* <Insert> is equal to "i" */ if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS) @@ -7262,11 +7182,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 +7213,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 +7284,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 +7306,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 +7326,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 +7339,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 +7360,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 +7471,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 +7491,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/proto/normal.pro b/src/normal.h index a178751474..171c4c928d 100644 --- a/src/proto/normal.pro +++ b/src/normal.h @@ -1,3 +1,5 @@ +#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)); @@ -27,3 +29,4 @@ 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 */ @@ -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. @@ -130,9 +155,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 +172,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 +181,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 +189,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 +197,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 +274,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 +320,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 +483,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 +656,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 +673,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 +683,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 +712,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 +722,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 +748,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 +779,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 +813,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 +822,7 @@ void *reg; } -void free_register(reg) -void *reg; +void free_register(void *reg) { struct yankreg tmp; @@ -825,8 +836,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 +851,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 +905,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 +953,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 +1061,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 +1085,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 +1124,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 +1181,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 +1216,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 +1299,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 +1339,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 +1680,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 +1693,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 +1895,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 +1970,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 +1997,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 +2054,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 +2200,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 +2319,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 +2327,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 +2343,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 +2356,7 @@ long n; } } -static void free_yank_all() { +static void free_yank_all(void) { free_yank(y_current->y_size); } @@ -2368,10 +2368,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 +2601,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 +2627,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 +3194,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 +3215,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 +3224,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 +3240,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 +3369,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 +3403,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 +3463,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 +3641,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 +3702,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 +3772,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 +3784,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 +3823,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 +4044,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 +4065,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 +4094,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 +4147,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 +4259,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 +4281,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 +4505,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 +4595,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 +4682,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 +4718,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 +4807,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 +4872,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 +4974,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 +4997,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 +5034,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/proto/ops.pro b/src/ops.h index f69f71ae25..f9fcbb2656 100644 --- a/src/proto/ops.pro +++ b/src/ops.h @@ -1,3 +1,5 @@ +#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)); @@ -64,3 +66,4 @@ void write_reg_contents_ex __ARGS((int name, char_u *str, int maxlen, 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 9dc432a1d4..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) @@ -1921,7 +1952,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 +2243,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 +2308,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 +2330,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 +2351,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 +2364,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 +2388,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 +2442,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 +2460,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 +2551,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 +2584,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 +2622,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 +3371,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 +3396,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 +3409,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 +3422,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 +3442,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 +3463,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 +3526,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 +3541,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 +3563,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 +3597,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 +3621,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 +3632,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 +3686,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 +3708,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 +3725,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 +3742,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 +3763,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 +3775,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 +3829,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 +3855,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 +3890,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 +4845,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 +4854,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 +4918,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 +5015,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 +5078,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 +5106,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 +5127,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 +5517,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 +5889,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 +5912,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 +5976,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 +6029,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 +6091,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 +6108,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 +6117,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 +6129,7 @@ char_u * get_encoding_default() { /* * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" 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 +6155,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 +6255,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 +6276,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 +6332,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 +6434,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 +6453,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 +6487,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 +6504,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 +6519,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 +6532,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 +6553,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 +6571,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 +6592,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 +6606,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 +6633,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 +6695,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 +6728,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 +6871,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 +6881,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 +6895,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 +6941,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 +6950,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 +6967,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 +6990,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 +7166,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 +7179,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 +7194,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 +7366,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 +7506,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 +7563,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 +7604,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 +7642,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 +7678,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 +7698,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 +7710,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 +7788,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 +7799,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 +7810,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 +7906,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 +7937,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 +7954,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 +7969,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 +7985,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 +7998,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 +8016,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 +8033,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 +8068,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 +8115,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 +8132,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 +8154,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 +8178,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 +8187,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 +8196,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 +8206,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/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 new file mode 100644 index 0000000000..bc9a495984 --- /dev/null +++ b/src/os/fs.c @@ -0,0 +1,129 @@ +/* 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 <uv.h> + +#include "os.h" +#include "../message.h" +#include "../misc2.h" + +int mch_chdir(char *path) { + if (p_verbose >= 5) { + verbose_enter(); + smsg((char_u *)"chdir(%s)", path); + verbose_leave(); + } + 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; +} + +/* + * 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/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 <uv.h> + +#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..9cf2116091 --- /dev/null +++ b/src/os/os.h @@ -0,0 +1,12 @@ +#ifndef NEOVIM_OS_H +#define NEOVIM_OS_H + +#include "../vim.h" + +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 344be7b0df..856191ea95 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -28,11 +28,27 @@ # 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 # include <selinux/selinux.h> static int selinux_enabled = -1; @@ -221,23 +237,10 @@ static struct signalinfo { {-1, "Unknown!", FALSE} }; -int mch_chdir(path) -char *path; -{ - if (p_verbose >= 5) { - verbose_enter(); - smsg((char_u *)"chdir(%s)", path); - verbose_leave(); - } - return chdir(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 +255,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() { @@ -334,105 +338,7 @@ int mch_char_avail() { return WaitForChar(0L); } -#if defined(HAVE_TOTAL_MEM) || defined(PROTO) -# ifdef HAVE_SYS_RESOURCE_H -# include <sys/resource.h> -# endif -# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL) -# include <sys/sysctl.h> -# endif -# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO) -# include <sys/sysinfo.h> -# endif - -/* - * 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 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; -} -#endif - -void mch_delay(msec, ignoreinput) -long msec; -int ignoreinput; +void mch_delay(long msec, int ignoreinput) { int old_tmode; @@ -508,8 +414,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 +482,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 +909,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 +961,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 +992,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 +1008,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 +1036,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 +1093,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 +1106,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 +1123,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 +1148,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 +1156,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 +1170,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 +1186,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 +1195,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 +1215,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 +1230,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 */ @@ -1361,172 +1244,16 @@ long mch_get_pid() { return (long)getpid(); } -#if !defined(HAVE_STRERROR) && defined(USE_GETCWD) -static char *strerror __ARGS((int)); - -static char * strerror(err) -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 - -/* - * 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; -{ -#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]". - * - * 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 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(fname) -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 * 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 +1305,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 +1326,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 +1346,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 +1394,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 +1403,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 +1419,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 +1429,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 +1449,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 +1462,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 +1515,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 +1589,7 @@ static void exit_scroll() { } } -void mch_exit(r) -int r; +void mch_exit(int r) { exiting = TRUE; @@ -1934,8 +1646,7 @@ static void may_core_dump() { } } -void mch_settmode(tmode) -int tmode; +void mch_settmode(int tmode) { static int first = TRUE; @@ -2196,7 +1907,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 +2864,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..3a20c49252 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -1,372 +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 <stdio.h> -#include <ctype.h> - -# include <sys/types.h> -# include <sys/stat.h> - -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#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 <unistd.h> -#endif - -#ifdef HAVE_LIBC_H -# include <libc.h> /* for NeXT */ -#endif - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> /* defines BSD, if it's a BSD system */ -#endif - -/* - * 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. */ -# 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 UNUSED; -# define SIGDUMMYARG 0 -# endif -#else -# define SIGPROTOARG (void) -# define SIGDEFARG(s) () -# define SIGDUMMYARG -#endif - -#ifdef HAVE_DIRENT_H -# include <dirent.h> -# 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 <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -#endif - -#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME) -# include <time.h> /* on some systems time.h should not be - included together with sys/time.h */ -#endif -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif - -#include <signal.h> - -#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 <pwd.h> -#endif - -#ifdef __COHERENT__ -# 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 - */ -#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/.vimrc" -#endif - - -#if !defined(USR_EXRC_FILE2) -# define USR_VIMRC_FILE2 "~/.vim/vimrc" -#endif - - -#ifndef USR_GVIMRC_FILE -# define USR_GVIMRC_FILE "$HOME/.gvimrc" -#endif - -#ifndef USR_GVIMRC_FILE2 -# define USR_GVIMRC_FILE2 "~/.vim/gvimrc" -#endif - - -#ifndef EVIM_FILE -# define EVIM_FILE "$VIMRUNTIME/evim.vim" -#endif - -# ifndef VIMINFO_FILE -# define VIMINFO_FILE "$HOME/.viminfo" -# endif - -#ifndef EXRC_FILE -# define EXRC_FILE ".exrc" -#endif - -#ifndef VIMRC_FILE -# define VIMRC_FILE ".vimrc" -#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/.vim/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" -# else -# define DFLT_RUNTIMEPATH \ - "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/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 <string.h> -#endif -#if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H) -# include <strings.h> -#endif - -#if defined(HAVE_SETJMP_H) -# include <setjmp.h> -# 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 <stdio.h> +#include <ctype.h> + +# include <sys/types.h> +# include <sys/stat.h> + +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#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 <unistd.h> +#endif + +#ifdef HAVE_LIBC_H +# include <libc.h> /* for NeXT */ +#endif + +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> /* 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 <dirent.h> +# 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 <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME) +# include <time.h> /* on some systems time.h should not be + included together with sys/time.h */ +#endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#include <signal.h> + +#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 <pwd.h> +#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 <string.h> +#endif +#if defined(HAVE_STRINGS_H) && !defined(NO_STRINGS_WITH_STRING_H) +# include <strings.h> +#endif + +#if defined(HAVE_SETJMP_H) +# include <setjmp.h> +# 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/po/Makefile b/src/po/Makefile index 8674031d84..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/src/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/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 <stdio.h> -#include <string.h> - - 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..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" */ @@ -40,11 +49,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 +242,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 +426,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 +593,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 +604,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 +612,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 +620,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/proto/popupmnu.pro b/src/popupmnu.h index 74a53e2f0e..8a619fdb36 100644 --- a/src/proto/popupmnu.pro +++ b/src/popupmnu.h @@ -1,3 +1,5 @@ +#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)); @@ -6,3 +8,4 @@ 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/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/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/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 3c97345d00..0000000000 --- a/src/proto/os_unix.pro +++ /dev/null @@ -1,80 +0,0 @@ -/* 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)); -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)); -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)); -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/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/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/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/quickfix.c b/src/quickfix.c index 28f3a469f6..af134d19f9 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -12,6 +12,35 @@ */ #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" struct dir_stack_T { @@ -152,12 +181,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 +215,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 +834,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 +870,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 +889,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 +908,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 +978,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 +994,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 +1014,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 +1110,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 +1152,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 +1217,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 +1239,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 +1270,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 +1318,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 +1746,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 +1842,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 +1865,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 +1900,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 +1911,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 +1939,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 +1982,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 +2016,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 +2048,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 +2069,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 +2173,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 +2188,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 +2231,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 +2251,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 +2266,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 +2281,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 +2312,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 +2322,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 +2412,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 +2421,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 +2430,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 +2448,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 +2463,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 +2476,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 +2573,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 +2625,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 +2656,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 +2688,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 +2744,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 +3081,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 +3124,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 +3155,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 +3234,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 +3259,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 +3272,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 +3327,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 +3439,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 +3492,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 +3526,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/proto/quickfix.pro b/src/quickfix.h index 98d64a7a3f..949d60bd73 100644 --- a/src/proto/quickfix.pro +++ b/src/quickfix.h @@ -1,3 +1,5 @@ +#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)); @@ -31,3 +33,4 @@ 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 d1852f7ba9..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: * @@ -255,16 +264,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 +383,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 +440,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 +456,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 +522,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 +691,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 +700,7 @@ regprog_T *prog; * Return TRUE if compiled regular expression "prog" looks before the start * position (pattern contains "\@<=" or "\@<!"). */ -int re_lookbehind(prog) -regprog_T *prog; +int re_lookbehind(regprog_T *prog) { return prog->regflags & RF_LOOKBH; } @@ -708,8 +710,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 +737,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 +1044,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 +1069,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 +1079,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 +1120,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 +1186,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 +1306,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 +1314,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 +1344,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 +1357,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 +1455,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 +1495,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 +1574,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 +1720,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 +2418,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 +2429,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 +2447,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 +2458,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 +2473,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 +2499,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 +2528,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 +2556,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 +2568,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 +2604,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 +2624,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 +2637,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 +2653,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 +2670,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 +2813,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 +2841,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 +2856,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 +2866,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 +2887,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 +2911,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 +2939,7 @@ static int getdecchrs() { * blahblah\%o210asdf * before-^ ^-after */ -static int getoctchrs() { +static int getoctchrs(void) { int nr = 0; int c; int i; @@ -2994,7 +2962,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 +2987,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 +3248,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 +3260,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 +3291,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 +3318,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 +3383,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 +3571,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 +3583,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 +3594,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 +3609,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 +3672,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 +3684,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 +3767,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 +5070,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 +5092,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 +5106,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 +5452,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 +5473,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 +5493,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 +5507,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 +5525,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 +5548,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 +5570,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 +5579,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 +5592,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 +5610,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 +5625,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 +5641,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 +5658,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 +5721,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 +5802,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 +6209,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 +6236,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 +6256,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 +6304,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 +6414,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 +6494,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 +6503,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 +6513,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 +6821,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 +6842,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 +6971,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 +7037,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 +7050,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 +7065,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.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 96d6a01a90..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. * @@ -327,9 +329,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 +368,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 +425,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 +504,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 +542,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 +570,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 +692,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 +1056,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 +1735,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 +1926,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 +1998,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 +2042,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 +2098,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 +2326,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 +2354,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 +2364,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 +2422,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 +2447,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 +2468,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 +2521,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 +2533,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 +2545,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 +2559,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 +2575,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 +2618,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 +2631,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 +2646,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 +2856,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 +3340,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 +3453,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 +3483,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 +3524,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 +3534,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 +3548,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 +3567,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 +3587,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 +3603,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 +3673,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 +3700,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 +3724,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 +3813,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 +3832,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 +4178,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 +4244,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 +4324,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 +4382,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 +4410,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 +4427,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 +4439,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 +4459,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 +4609,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 +4762,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 +4784,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 +4840,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 +6048,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 +6151,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 +6251,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 +6365,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 +6383,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 +6410,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 +6462,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..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. */ @@ -163,15 +194,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 +214,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 +223,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 +236,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 +257,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 +383,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 +410,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 +423,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 +614,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 +636,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 +645,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 +700,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 +1652,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 +1708,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 +1718,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 +2024,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 +2039,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 +2091,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 +4062,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 +4082,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 +4117,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 +4371,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 +4386,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 +4399,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 +4412,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 +4425,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 +4443,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 +4463,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 +4487,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 +4510,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 +4691,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 +4811,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 +4841,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 +4863,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 +4907,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 +5069,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 +5086,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 +5117,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 +5136,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 +5145,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 +5356,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 +5368,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 +5378,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 +5407,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 +5465,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 +5558,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 +5612,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 +5687,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 +5705,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 +5767,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 +5791,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 +5823,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 +5844,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 +5995,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 +6014,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 +6030,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 +6277,7 @@ give_up: } } -void free_screenlines() { +void free_screenlines(void) { int i; vim_free(ScreenLinesUC); @@ -6341,13 +6291,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 +6344,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 +6357,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 +6365,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 +6392,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 +6403,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 +6412,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 +6625,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 +6648,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 +6717,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 +6760,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 +6825,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 +6866,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 +7039,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 +7220,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 +7371,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 +7381,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 +7399,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 +7549,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 +7561,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 +7587,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 +7599,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 +7607,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 +7615,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 +7639,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 +7807,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 +7841,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 +7849,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/proto/screen.pro b/src/screen.h index 53a909e242..2f25798757 100644 --- a/src/proto/screen.pro +++ b/src/screen.h @@ -1,3 +1,5 @@ +#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)); @@ -64,3 +66,4 @@ 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 6007b53375..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)); @@ -113,12 +138,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 +217,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 +225,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 +255,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 +276,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 +289,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 +302,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 +319,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 +335,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 +363,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 +379,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 +415,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 +456,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 +843,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 +1222,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 +1285,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 +1397,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 +1409,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 +1436,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 +1943,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 +1990,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 +2084,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 +2198,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 +2266,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 +2293,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 +2331,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 +2369,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 +2435,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 +2492,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 +2548,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 +2593,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 +2604,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 +2619,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 +2635,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 +2655,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 +2807,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 +2962,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 +3097,7 @@ static int in_html_tag __ARGS((int)); * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>". */ -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 +3159,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 +3336,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 +3503,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 +3535,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 +3565,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 +3779,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 +3911,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 +3952,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 +3965,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 +4555,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 +4603,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 +4676,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 +4686,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/proto/search.pro b/src/search.h index 9c3c520c9f..b24d2aa69a 100644 --- a/src/proto/search.pro +++ b/src/search.h @@ -1,3 +1,5 @@ +#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)); @@ -47,3 +49,4 @@ void find_pattern_in_path __ARGS((char_u *ptr, int dir, int len, int whole, 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 0761987ebe..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])); @@ -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/proto/sha256.pro b/src/sha256.h index dca9e37998..03e8aa6bea 100644 --- a/src/proto/sha256.pro +++ b/src/sha256.h @@ -1,3 +1,5 @@ +#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, @@ -10,3 +12,4 @@ 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 05c6543ef6..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 <time.h> /* for time_t */ #endif @@ -996,12 +1021,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 +1218,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 +1668,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 +1697,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 +1734,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 +1765,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 +1813,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 +1868,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 +1978,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 +2004,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 +2019,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 +2037,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 +2260,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 +2293,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 +2348,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 +2359,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 +2369,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 +2390,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 +2401,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 +2497,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 +2513,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 +2544,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 +2784,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 +2811,7 @@ int *cntp; * Read SN_REGION: <regionname> ... * 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 +2828,7 @@ int len; * <folcharslen> <folchars> * 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 +2863,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 +2906,7 @@ slang_T *lp; * Read REP or REPSAL items section from "fd": <repcount> <rep> ... * 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 +2951,7 @@ short *first; * Read SN_SAL section: <salflags> <salcount> <sal> ... * 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 +3087,7 @@ slang_T *slang; * Read SN_WORDS: <word> ... * 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 +3118,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 +3158,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 +3195,7 @@ int split; /* word was split, less bonus */ * SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto> * 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 +3233,7 @@ slang_T *slang; * <compmax> <compminlen> <compsylmax> <compoptions> <compflags> * 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 +3409,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 +3429,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 +3465,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 +3516,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 +3594,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 +3649,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 +3670,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 +3720,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 <prefcondnr> */ +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 <prefcondnr> */ +) { int len; int i; @@ -3839,8 +3825,7 @@ int maxprefcondnr; /* maximum for <prefcondnr> */ * 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 +4105,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 +4116,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 +4155,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 +4175,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 +4227,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 +4267,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 +4282,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 +4308,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 +4333,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 +4738,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 +5516,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 +5527,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 +5557,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 +5571,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 +5597,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 +5625,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 +5699,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 +5710,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 +5747,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 +5757,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 +5768,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 +5779,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 +5797,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 +5805,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 +5839,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 +6035,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 +6066,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 +6101,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 +6134,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 +6378,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 +6560,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 +6606,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 +6620,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 +6635,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 +6649,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 +6694,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 +6857,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 +6896,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 +6921,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 +6942,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 +6952,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 +6991,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 +7091,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 +7115,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 +7127,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 +7506,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 +7533,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 +7645,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 +7669,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 +7754,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 +7851,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 +7879,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 +7942,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 +7983,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 +8013,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 +8105,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 +8122,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 +8138,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 +8376,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 +8393,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 +8403,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 +8553,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 +8626,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 +8660,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 +8701,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 +8762,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 +8795,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 +8825,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 +8863,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 +8882,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 +8894,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 +8920,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 +8956,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 +9002,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 +9051,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 +9265,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 +9324,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 +9391,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 +9435,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 +9556,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 +9588,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 +9639,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 +9725,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 +9853,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 +9905,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 +9926,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 +9959,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 +9998,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 +10029,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 +10093,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 +11363,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 +11376,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 +11394,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 +11527,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 +11575,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 +11677,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 +11744,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 +11764,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 +11791,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 +11823,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 +12012,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 +12081,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 +12097,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 +12165,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 +12201,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 +12324,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 +12360,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 +12379,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 +12391,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 +12422,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 +12442,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 +12469,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 +12502,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 +12536,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 +12594,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 +12838,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 +13120,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 +13337,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 +13443,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 +13596,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 +13758,7 @@ pop: /* * ":spellinfo" */ -void ex_spellinfo(eap) -exarg_T *eap UNUSED; +void ex_spellinfo(exarg_T *eap) { int lpi; langp_T *lp; @@ -13952,8 +13791,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 +13826,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 +14001,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 +14075,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 +14180,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 +14196,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 +14231,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 +14242,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/proto/spell.pro b/src/spell.h index cba277509e..8a349300a3 100644 --- a/src/proto/spell.pro +++ b/src/spell.h @@ -1,3 +1,5 @@ +#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)); @@ -28,3 +30,4 @@ 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 375f16cd0d..4b22137fda 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -12,6 +12,26 @@ */ #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" /* * Structure that stores information about a highlight group. @@ -448,9 +468,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 +628,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 +647,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 +666,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 +915,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 +931,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 +953,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 +1047,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 +1063,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 +1084,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 +1154,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 +1167,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 +1214,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 +1270,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 +1282,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 +1300,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 +1404,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 +1446,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 +1512,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 +1528,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 +1545,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 +1590,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 +1638,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 +1686,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 +2209,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 +2231,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 +2310,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 +2403,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 +2452,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 +2507,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 +2568,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 +2581,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 +2603,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 +2810,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 +2821,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 +2832,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 +2878,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 +2924,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 +2932,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 +2966,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 +3047,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 +3068,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 +3089,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 +3112,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 +3159,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 +3171,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 +3195,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 +3212,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 +3227,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 +3237,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 +3308,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 +3331,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 +3339,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 +3349,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 +3362,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 +3370,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 +3390,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 +3469,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 +3487,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 +3507,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 +3609,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 +3623,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 +3646,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 +3675,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 +3738,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 +3826,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 +3867,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 +3893,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 +3951,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 +3979,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 +4130,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 +4152,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 +4221,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 +4328,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 +4427,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 +4666,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 +4678,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 +4794,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 +4814,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 +4833,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 +4855,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 +4900,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 +4964,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 +4974,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 +5060,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 +5189,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 +5361,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 +5387,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 +5507,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 +5540,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 +5579,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 +5597,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 +5605,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 +5615,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 +5652,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 +5663,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 +5691,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 +5700,7 @@ int *seqnrp; /* * Return conceal substitution character */ -int syn_get_sub_char() { +int syn_get_sub_char(void) { return current_sub_char; } @@ -5764,8 +5709,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 +5724,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 +5748,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 +5762,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 +5773,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 +5791,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 +5812,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 +5823,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 +6087,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 +6165,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 +6195,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 +6810,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 +6827,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 +6837,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 +6847,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 +6894,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 +6985,7 @@ attrentry_T *aep; /* * Clear all highlight tables. */ -void clear_hl_tables() { +void clear_hl_tables(void) { int i; attrentry_T *taep; @@ -7073,9 +7007,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 +7074,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 +7089,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 +7097,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 +7109,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 +7153,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 +7197,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 +7224,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 +7275,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 +7302,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 +7347,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 +7390,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 +7410,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 +7419,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 +7429,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 +7448,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 +7470,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 +7523,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 +7532,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 +7552,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 +7583,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 +7749,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 +7792,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 +7801,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 +7816,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/proto/syntax.pro b/src/syntax.h index 0d5f23910f..e05d342927 100644 --- a/src/proto/syntax.pro +++ b/src/syntax.h @@ -1,3 +1,5 @@ +#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)); @@ -56,3 +58,4 @@ 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 */ @@ -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. @@ -107,12 +134,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 +939,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 +956,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 +1005,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 +1038,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 +1092,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 +2044,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 +2052,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 +2071,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 +2176,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 +2192,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 +2256,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 +2297,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 +2355,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 +2376,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 +2673,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 +2719,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 +2888,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 +2914,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 +2943,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 +2997,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 +3042,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/proto/tag.pro b/src/tag.h index fedbc93745..829d48ff7b 100644 --- a/src/proto/tag.pro +++ b/src/tag.h @@ -1,3 +1,5 @@ +#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)); @@ -13,3 +15,4 @@ 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 7525244ca1..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 @@ -1143,8 +1162,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 +1189,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 +1239,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 +1275,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 +1670,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 +1700,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 +1733,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 +1766,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 +1785,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 +1810,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 +1903,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 +1913,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 +1924,7 @@ char_u *name; * <Esc>] -> <M-C-]> * <Esc>O -> <M-C-O> */ -static int term_7to8bit(p) -char_u *p; +static int term_7to8bit(char_u *p) { if (*p == ESC) { if (p[1] == '[') @@ -1928,8 +1940,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 +1964,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 +2010,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 +2045,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 +2060,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 +2071,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 +2090,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 +2114,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 +2133,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 +2155,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 +2186,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 +2201,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 +2210,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 <Esc>[ or CSI */ @@ -2252,8 +2243,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 +2257,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 +2349,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 +2370,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 +2398,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 +2431,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 +2440,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 +2452,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 +2475,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 +2483,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 +2503,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 +2596,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 +2631,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 +2648,7 @@ void starttermcap() { } } -void stoptermcap() { +void stoptermcap(void) { screen_stop_highlight(); reset_cterm_colors(); if (termcap_active) { @@ -2714,7 +2693,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 +2723,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 +2778,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 +2825,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 +2845,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 +2854,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 +2867,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 +2877,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 +2889,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 +2914,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 +2927,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 +2950,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 +2975,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 +3080,7 @@ int flags; * The "X" can be any character. * Return 0 if not found, 2 for ;*X and 1 for O*X and <M-O>*X. */ -static int termcode_star(code, len) -char_u *code; -int len; +static int termcode_star(char_u *code, int len) { /* Shortest is <M-O>*X. With ; shortest is <CSI>1;*X */ if (len >= 3 && code[len - 2] == '*') { @@ -3121,8 +3092,7 @@ int len; return 0; } -char_u * find_termcode(name) -char_u *name; +char_u *find_termcode(char_u *name) { int i; @@ -3132,16 +3102,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 +3126,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 +3140,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 +3173,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 +3193,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 +4158,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 <lt> */ -int special; /* always accept <key> notation */ +char_u * +replace_termcodes ( + char_u *from, + char_u **bufp, + int from_part, + int do_lt, /* also translate <lt> */ + int special /* always accept <key> notation */ +) { int i; int slen; @@ -4374,8 +4338,7 @@ int special; /* always accept <key> 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 +4355,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 +4377,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 +4455,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 +4506,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 +4547,7 @@ static void req_more_codes_from_term() { * Both <name> and <string> 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 +4626,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 +4672,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/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/testdir/Makefile b/src/testdir/Makefile index 5238fda86a..16db2846c2 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/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 eaf0cba00b..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/src/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 . @@ -17,11 +17,23 @@ */ #include "vim.h" - - -void ui_write(s, len) -char_u *s; -int len; +#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) { #ifndef NO_CONSOLE /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */ @@ -53,9 +65,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 +101,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 +171,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 +187,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 +197,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 +206,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 +222,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 +242,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 +254,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 +317,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 +337,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 +357,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 +381,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 +422,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 +431,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 +442,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 +455,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 +571,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 +582,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 +596,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 +608,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 +628,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 +694,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 +988,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 +1054,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 +1086,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 +1124,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 +1146,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/proto/ui.pro b/src/ui.h index 2f37fb9dfe..bcd6afd426 100644 --- a/src/proto/ui.pro +++ b/src/ui.h @@ -1,3 +1,5 @@ +#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)); @@ -65,3 +67,4 @@ 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 9dfdcbe74c..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)); @@ -98,9 +113,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 +225,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 +236,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 +258,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 +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_inssub(lnum) -linenr_T lnum; +int u_inssub(linenr_T lnum) { if (undo_off) return OK; @@ -275,9 +287,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 +300,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 +328,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 +343,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 +654,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 +675,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 +742,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 +765,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 +791,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 +801,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 +863,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 +902,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 +981,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 +1000,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 +1050,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 +1060,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 +1076,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 +1087,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 +1099,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 +1113,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 +1344,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 +1647,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 +1670,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 +1680,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 +1748,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 +2055,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 +2299,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 +2374,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 +2393,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 +2486,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 +2508,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 +2531,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 +2541,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 +2573,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 +2588,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 +2603,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 +2615,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 +2649,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 +2685,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 +2719,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 +2751,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 +2765,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 +2777,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 +2797,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 +2811,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 +2849,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 +2860,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 +2870,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 +2887,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/proto/undo.pro b/src/undo.h index dfbb07ac26..aecab36875 100644 --- a/src/proto/undo.pro +++ b/src/undo.h @@ -1,3 +1,5 @@ +#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)); @@ -29,3 +31,4 @@ 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 62a7aa8bc8..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; @@ -568,7 +573,7 @@ static char *(extra_patches[]) = NULL }; -int highest_patch() { +int highest_patch(void) { int i; int h = 0; @@ -581,8 +586,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 +596,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 +610,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 +665,7 @@ static void list_features() { } } -void list_version() { +void list_version(void) { int i; int first; char *s = ""; @@ -792,8 +795,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 +812,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 +825,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 +908,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 +969,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/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 " @@ -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 <stdbool.h> @@ -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) @@ -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 <locale.h> # endif @@ -162,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 <errno.h> @@ -1268,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 */ @@ -1420,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 @@ -1602,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 336f9dbcca..fb95ec1239 100644 --- a/src/window.c +++ b/src/window.c @@ -8,6 +8,39 @@ */ #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)); static void win_init __ARGS((win_T *newp, win_T *oldp, int flags)); @@ -86,10 +119,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 +545,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 +574,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 +965,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 +1015,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 +1030,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 +1045,7 @@ win_T *win; /* * Return the number of windows. */ -int win_count() { +int win_count(void) { win_T *wp; int count = 0; @@ -1037,9 +1060,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 +1119,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 +1209,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 +1282,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 +1312,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 +1365,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 +1386,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 +1668,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 +1721,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 +1729,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 +1748,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 +1791,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 +1960,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 +2014,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 +2039,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 +2060,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 +2201,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 +2227,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 +2243,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 +2253,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 +2270,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 +2359,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 +2386,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 +2413,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 +2440,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 +2536,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 +2563,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 +2571,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 +2583,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 +2623,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 +2668,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 +2721,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 +2751,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 +2768,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 +2784,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 +2833,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 +2844,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 +2866,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 +2889,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 +2948,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 +2963,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 +2991,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 +3004,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 +3018,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 +3034,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 +3074,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 +3123,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 +3184,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 +3204,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 +3215,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 +3258,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 +3290,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 +3307,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 +3366,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 +3425,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 +3435,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 +3531,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 +3548,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 +3578,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 +3637,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 +3705,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 +3729,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 +3752,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 +3764,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 +3778,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 +3793,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 +3805,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 +3815,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 +3838,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 +3854,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 +3872,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 +3893,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 +3907,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 +3945,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 +3954,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 +3999,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 +4147,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 +4178,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 +4302,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 +4326,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 +4440,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 +4532,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 +4543,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 +4655,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 +4669,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 +4679,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 +4746,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 +4761,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 +4823,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 +4836,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 +4865,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 +4876,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 +4955,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 +4970,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 +5035,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 +5049,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 +5061,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 +5071,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 +5100,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 +5124,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 +5148,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 +5179,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 +5204,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 +5224,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 +5249,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 +5267,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 +5303,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 +5332,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 +5355,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 +5368,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 +5389,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 +5464,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 +5498,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 +5516,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 +5529,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 +5547,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; diff --git a/src/proto/window.pro b/src/window.h index bf82ca1982..1fa7c302fd 100644 --- a/src/proto/window.pro +++ b/src/window.h @@ -1,3 +1,5 @@ +#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)); @@ -91,3 +93,4 @@ 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 */ 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. diff --git a/third-party/libuv/.gitignore b/third-party/libuv/.gitignore new file mode 100644 index 0000000000..d11c90bbf0 --- /dev/null +++ b/third-party/libuv/.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/third-party/libuv/.mailmap b/third-party/libuv/.mailmap new file mode 100644 index 0000000000..0f1d843ce8 --- /dev/null +++ b/third-party/libuv/.mailmap @@ -0,0 +1,24 @@ +Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com> +Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com> +Bert Belder <bertbelder@gmail.com> <info@2bs.nl> +Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)> +Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org> +Brian White <mscdex@mscdex.net> +Brian White <mscdex@mscdex.net> <mscdex@gmail.com> +Christoph Iserlohn <christoph.iserlohn@innoq.com> +Frank Denis <github@pureftpd.org> +Isaac Z. Schlueter <i@izs.me> +Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu> +Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu> +Maciej MaÅ‚ecki <maciej.malecki@notimplemented.org> <me@mmalecki.com> +Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com> +Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org> +Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org> +Ryan Emery <seebees@gmail.com> +San-Tai Hsu <vanilla@fatpipi.com> +Saúl Ibarra Corretgé <saghul@gmail.com> +Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org> +Timothy J. Fontaine <tjfontaine@gmail.com> +Yasuhiro Matsumoto <mattn.jp@gmail.com> +Yazhong Liu <yorkiefixer@gmail.com> +Yuki Okumura <mjt@cltn.org> diff --git a/third-party/libuv/AUTHORS b/third-party/libuv/AUTHORS new file mode 100644 index 0000000000..6633f0651e --- /dev/null +++ b/third-party/libuv/AUTHORS @@ -0,0 +1,114 @@ +# Authors ordered by first contribution. +Ryan Dahl <ryan@joyent.com> +Bert Belder <bertbelder@gmail.com> +Josh Roesslein <jroesslein@gmail.com> +Alan Gutierrez <alan@prettyrobots.com> +Joshua Peek <josh@joshpeek.com> +Igor Zinkovsky <igorzi@microsoft.com> +San-Tai Hsu <vanilla@fatpipi.com> +Ben Noordhuis <info@bnoordhuis.nl> +Henry Rawas <henryr@schakra.com> +Robert Mustacchi <rm@joyent.com> +Matt Stevens <matt@alloysoft.com> +Paul Querna <pquerna@apache.org> +Shigeki Ohtsu <ohtsu@iij.ad.jp> +Tom Hughes <tom.hughes@palm.com> +Peter Bright <drpizza@quiscalusmexicanus.org> +Jeroen Janssen <jeroen.janssen@gmail.com> +Andrea Lattuada <ndr.lattuada@gmail.com> +Augusto Henrique Hentz <ahhentz@gmail.com> +Clifford Heath <clifford.heath@gmail.com> +Jorge Chamorro Bieling <jorge@jorgechamorro.com> +Luis Lavena <luislavena@gmail.com> +Matthew Sporleder <msporleder@gmail.com> +Erick Tryzelaar <erick.tryzelaar@gmail.com> +Isaac Z. Schlueter <i@izs.me> +Pieter Noordhuis <pcnoordhuis@gmail.com> +Marek Jelen <marek@jelen.biz> +Fedor Indutny <fedor.indutny@gmail.com> +Saúl Ibarra Corretgé <saghul@gmail.com> +Felix Geisendörfer <felix@debuggable.com> +Yuki Okumura <mjt@cltn.org> +Roman Shtylman <shtylman@gmail.com> +Frank Denis <github@pureftpd.org> +Carter Allen <CarterA@opt-6.com> +Tj Holowaychuk <tj@vision-media.ca> +Shimon Doodkin <helpmepro1@gmail.com> +Ryan Emery <seebees@gmail.com> +Bruce Mitchener <bruce.mitchener@gmail.com> +Maciej MaÅ‚ecki <maciej.malecki@notimplemented.org> +Yasuhiro Matsumoto <mattn.jp@gmail.com> +Daisuke Murase <typester@cpan.org> +Paddy Byers <paddy.byers@gmail.com> +Dan VerWeire <dverweire@gmail.com> +Brandon Benvie <brandon@bbenvie.com> +Brandon Philips <brandon.philips@rackspace.com> +Nathan Rajlich <nathan@tootallnate.net> +Charlie McConnell <charlie@charlieistheman.com> +Vladimir Dronnikov <dronnikov@gmail.com> +Aaron Bieber <qbit@deftly.net> +Bulat Shakirzyanov <mallluhuct@gmail.com> +Brian White <mscdex@mscdex.net> +Erik Dubbelboer <erik@dubbelboer.com> +Keno Fischer <kenof@stanford.edu> +Ira Cooper <Ira.Cooper@mathworks.com> +Andrius Bentkus <andrius.bentkus@gmail.com> +Iñaki Baz Castillo <ibc@aliax.net> +Mark Cavage <mark.cavage@joyent.com> +George Yohng <georgegh@oss3d.com> +Xidorn Quan <quanxunzhen@gmail.com> +Roman Neuhauser <rneuhauser@suse.cz> +Shuhei Tanuma <shuhei.tanuma@gmail.com> +Bryan Cantrill <bcantrill@acm.org> +Trond Norbye <trond.norbye@gmail.com> +Tim Holy <holy@wustl.edu> +Prancesco Pertugio <meh@schizofreni.co> +Leonard Hecker <leonard.hecker91@gmail.com> +Andrew Paprocki <andrew@ishiboo.com> +Luigi Grilli <luigi.grilli@gmail.com> +Shannen Saez <shannenlaptop@gmail.com> +Artur Adib <arturadib@gmail.com> +Hiroaki Nakamura <hnakamur@gmail.com> +Ting-Yu Lin <ph.minamo@cytisan.com> +Stephen Gallagher <sgallagh@redhat.com> +Shane Holloway <shane.holloway@ieee.org> +Andrew Shaffer <darawk@gmail.com> +Vlad Tudose <vlad.tudose@intel.com> +Ben Leslie <benno@benno.id.au> +Tim Bradshaw <tfb@cley.com> +Timothy J. Fontaine <tjfontaine@gmail.com> +Marc Schlaich <marc.schlaich@googlemail.com> +Brian Mazza <louseman@gmail.com> +Elliot Saba <staticfloat@gmail.com> +Ben Kelly <ben@wanderview.com> +Kristian Evensen <kristian.evensen@gmail.com> +Nils Maier <maierman@web.de> +Nicholas Vavilov <vvnicholas@gmail.com> +Miroslav BajtoÅ¡ <miro.bajtos@gmail.com> +Sean Silva <chisophugis@gmail.com> +Wynn Wilkes <wynnw@movenetworks.com> +Linus MÃ¥rtensson <linus.martensson@sonymobile.com> +Andrei Sedoi <bsnote@gmail.com> +Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com> +Alex Crichton <alex@alexcrichton.com> +Brent Cook <brent@boundary.com> +Brian Kaisner <bkize1@gmail.com> +Luca Bruno <lucab@debian.org> +Reini Urban <rurban@cpanel.net> +Maks Naumov <maksqwe1@ukr.net> +Sean Farrell <sean.farrell@rioki.org> +Chris Bank <cbank@adobe.com> +Geert Jansen <geertj@gmail.com> +Christoph Iserlohn <christoph.iserlohn@innoq.com> +Steven Kabbes <stevenkabbes@gmail.com> +Alex Gaynor <alex.gaynor@gmail.com> +huxingyi <huxingyi@msn.com> +Tenor Biel <tenorbiel@gmail.com> +Andrej Manduch <AManduch@gmail.com> +Joshua Neuheisel <joshua@neuheisel.us> +Alexis Campailla <alexis@janeasystems.com> +Yazhong Liu <yorkiefixer@gmail.com> +Sam Roberts <vieuxtech@gmail.com> +River Tarnell <river@loreley.flyingparchment.org.uk> +Nathan Sweet <nathanjsweet@gmail.com> +Trevor Norris <trev.norris@gmail.com> diff --git a/third-party/libuv/CONTRIBUTING.md b/third-party/libuv/CONTRIBUTING.md new file mode 100644 index 0000000000..960a9450ae --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/ChangeLog b/third-party/libuv/ChangeLog new file mode 100644 index 0000000000..ad3cbb504c --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/LICENSE b/third-party/libuv/LICENSE new file mode 100644 index 0000000000..8db13acf2c --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/Makefile.am b/third-party/libuv/Makefile.am new file mode 100644 index 0000000000..c1eae8cea0 --- /dev/null +++ b/third-party/libuv/Makefile.am @@ -0,0 +1,302 @@ +# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +# +# 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/third-party/libuv/Makefile.mingw b/third-party/libuv/Makefile.mingw new file mode 100644 index 0000000000..28a1e274d5 --- /dev/null +++ b/third-party/libuv/Makefile.mingw @@ -0,0 +1,77 @@ +# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +# +# 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/third-party/libuv/README.md b/third-party/libuv/README.md new file mode 100644 index 0000000000..5704c39e27 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/android-configure b/third-party/libuv/android-configure new file mode 100755 index 0000000000..56625761fd --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/autogen.sh b/third-party/libuv/autogen.sh new file mode 100755 index 0000000000..751b4f5562 --- /dev/null +++ b/third-party/libuv/autogen.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +# +# 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/third-party/libuv/checksparse.sh b/third-party/libuv/checksparse.sh new file mode 100755 index 0000000000..54cd5805a8 --- /dev/null +++ b/third-party/libuv/checksparse.sh @@ -0,0 +1,231 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +# +# 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/third-party/libuv/common.gypi b/third-party/libuv/common.gypi new file mode 100644 index 0000000000..7adbbbdcc9 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/configure.ac b/third-party/libuv/configure.ac new file mode 100644 index 0000000000..ffa09b45c2 --- /dev/null +++ b/third-party/libuv/configure.ac @@ -0,0 +1,55 @@ +# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> +# +# 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/third-party/libuv/gyp_uv.py b/third-party/libuv/gyp_uv.py new file mode 100755 index 0000000000..4ba69167d9 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/include/pthread-fixes.h b/third-party/libuv/include/pthread-fixes.h new file mode 100644 index 0000000000..230ce3178d --- /dev/null +++ b/third-party/libuv/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 <pthread.h> + + +/*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/third-party/libuv/include/stdint-msvc2008.h b/third-party/libuv/include/stdint-msvc2008.h new file mode 100644 index 0000000000..d02608a597 --- /dev/null +++ b/third-party/libuv/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 <limits.h> + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap <wchar.h> 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 <wchar.h> +#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 <wchar.h> +#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/third-party/libuv/include/tree.h b/third-party/libuv/include/tree.h new file mode 100644 index 0000000000..f936416e3d --- /dev/null +++ b/third-party/libuv/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * 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/third-party/libuv/include/uv-bsd.h b/third-party/libuv/include/uv-bsd.h new file mode 100644 index 0000000000..2d72b3d771 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/include/uv-darwin.h b/third-party/libuv/include/uv-darwin.h new file mode 100644 index 0000000000..24bc35b581 --- /dev/null +++ b/third-party/libuv/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 <mach/mach.h> +# include <mach/task.h> +# include <mach/semaphore.h> +# include <TargetConditionals.h> +# 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/third-party/libuv/include/uv-errno.h b/third-party/libuv/include/uv-errno.h new file mode 100644 index 0000000000..797bcab93b --- /dev/null +++ b/third-party/libuv/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 <errno.h> + +#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/third-party/libuv/include/uv-linux.h b/third-party/libuv/include/uv-linux.h new file mode 100644 index 0000000000..62ebfe2a02 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/include/uv-sunos.h b/third-party/libuv/include/uv-sunos.h new file mode 100644 index 0000000000..042166424e --- /dev/null +++ b/third-party/libuv/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 <sys/port.h> +#include <port.h> + +/* 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/third-party/libuv/include/uv-unix.h b/third-party/libuv/include/uv-unix.h new file mode 100644 index 0000000000..45006092be --- /dev/null +++ b/third-party/libuv/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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <termios.h> +#include <pwd.h> + +#include <semaphore.h> +#include <pthread.h> +#ifdef __ANDROID__ +#include "pthread-fixes.h" +#endif +#include <signal.h> + +#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/third-party/libuv/include/uv-win.h b/third-party/libuv/include/uv-win.h new file mode 100644 index 0000000000..e4e1f839f0 --- /dev/null +++ b/third-party/libuv/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 <winsock2.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <windows.h> + +#include <process.h> +#include <signal.h> +#include <sys/stat.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#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/third-party/libuv/include/uv.h b/third-party/libuv/include/uv.h new file mode 100644 index 0000000000..4eeade74c4 --- /dev/null +++ b/third-party/libuv/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 <stddef.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#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/third-party/libuv/libuv.pc.in b/third-party/libuv/libuv.pc.in new file mode 100644 index 0000000000..86c1a126cd --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/m4/.gitignore b/third-party/libuv/m4/.gitignore new file mode 100644 index 0000000000..bde78f43f9 --- /dev/null +++ b/third-party/libuv/m4/.gitignore @@ -0,0 +1,2 @@ +# Ignore libtoolize-generated files. +*.m4 diff --git a/third-party/libuv/m4/dtrace.m4 b/third-party/libuv/m4/dtrace.m4 new file mode 100644 index 0000000000..4060af3181 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/.gitignore b/third-party/libuv/samples/.gitignore new file mode 100644 index 0000000000..f868091ba3 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/socks5-proxy/.gitignore b/third-party/libuv/samples/socks5-proxy/.gitignore new file mode 100644 index 0000000000..c177f37451 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/socks5-proxy/LICENSE b/third-party/libuv/samples/socks5-proxy/LICENSE new file mode 100644 index 0000000000..63c1447fc5 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/socks5-proxy/Makefile b/third-party/libuv/samples/socks5-proxy/Makefile new file mode 100644 index 0000000000..268dc55b1a --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/socks5-proxy/build.gyp b/third-party/libuv/samples/socks5-proxy/build.gyp new file mode 100644 index 0000000000..771a1e146d --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/samples/socks5-proxy/client.c b/third-party/libuv/samples/socks5-proxy/client.c new file mode 100644 index 0000000000..ae9913a1c6 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stdlib.h> +#include <string.h> + +/* 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/third-party/libuv/samples/socks5-proxy/defs.h b/third-party/libuv/samples/socks5-proxy/defs.h new file mode 100644 index 0000000000..99ee8160c8 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */ +#include <stddef.h> /* size_t, ssize_t */ +#include <stdint.h> +#include <sys/socket.h> /* 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/third-party/libuv/samples/socks5-proxy/getopt.c b/third-party/libuv/samples/socks5-proxy/getopt.c new file mode 100644 index 0000000000..8481b2264f --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +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/third-party/libuv/samples/socks5-proxy/main.c b/third-party/libuv/samples/socks5-proxy/main.c new file mode 100644 index 0000000000..04020cbd3a --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if HAVE_UNISTD_H +#include <unistd.h> /* 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 <address> [-h] [-p <port>]\n" + "\n" + "Options:\n" + "\n" + " -b <hostname|address> Bind to this address or hostname.\n" + " Default: \"127.0.0.1\"\n" + " -h Show this help message.\n" + " -p <port> Bind to this port number. Default: 1080\n" + "", + progname); + exit(1); +} diff --git a/third-party/libuv/samples/socks5-proxy/s5.c b/third-party/libuv/samples/socks5-proxy/s5.c new file mode 100644 index 0000000000..4f08e34524 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stdint.h> +#include <stdlib.h> /* abort() */ +#include <string.h> /* 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/third-party/libuv/samples/socks5-proxy/s5.h b/third-party/libuv/samples/socks5-proxy/s5.h new file mode 100644 index 0000000000..715f322287 --- /dev/null +++ b/third-party/libuv/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 <stddef.h> +#include <stdint.h> + +#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/third-party/libuv/samples/socks5-proxy/server.c b/third-party/libuv/samples/socks5-proxy/server.c new file mode 100644 index 0000000000..3f1ba42c9e --- /dev/null +++ b/third-party/libuv/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 <netinet/in.h> /* INET6_ADDRSTRLEN */ +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/samples/socks5-proxy/util.c b/third-party/libuv/samples/socks5-proxy/util.c new file mode 100644 index 0000000000..af34f05593 --- /dev/null +++ b/third-party/libuv/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 <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/src/fs-poll.c b/third-party/libuv/src/fs-poll.c new file mode 100644 index 0000000000..7fdaaeb17a --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> +#include <string.h> + +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/third-party/libuv/src/inet.c b/third-party/libuv/src/inet.c new file mode 100644 index 0000000000..a30c0d1512 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#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/third-party/libuv/src/queue.h b/third-party/libuv/src/queue.h new file mode 100644 index 0000000000..fe02b454ea --- /dev/null +++ b/third-party/libuv/src/queue.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> + * + * 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/third-party/libuv/src/unix/aix.c b/third-party/libuv/src/unix/aix.c new file mode 100644 index 0000000000..2521681305 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> + +#include <sys/protosw.h> +#include <libperfstat.h> +#include <sys/proc.h> +#include <sys/procfs.h> + +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/third-party/libuv/src/unix/async.c b/third-party/libuv/src/unix/async.c new file mode 100644 index 0000000000..3c23e1d7fd --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +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/third-party/libuv/src/unix/atomic-ops.h b/third-party/libuv/src/unix/atomic-ops.h new file mode 100644 index 0000000000..7e4e64beda --- /dev/null +++ b/third-party/libuv/src/unix/atomic-ops.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> + * + * 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/third-party/libuv/src/unix/core.c b/third-party/libuv/src/unix/core.c new file mode 100644 index 0000000000..df2a5f8042 --- /dev/null +++ b/third-party/libuv/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 <stddef.h> /* NULL */ +#include <stdio.h> /* printf */ +#include <stdlib.h> +#include <string.h> /* strerror */ +#include <errno.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <limits.h> /* INT_MAX, PATH_MAX */ +#include <sys/uio.h> /* writev */ + +#ifdef __linux__ +# include <sys/ioctl.h> +#endif + +#ifdef __sun +# include <sys/types.h> +# include <sys/wait.h> +#endif + +#ifdef __APPLE__ +# include <mach-o/dyld.h> /* _NSGetExecutablePath */ +# include <sys/filio.h> +# include <sys/ioctl.h> +#endif + +#ifdef __FreeBSD__ +# include <sys/sysctl.h> +# include <sys/filio.h> +# include <sys/ioctl.h> +# include <sys/wait.h> +#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/third-party/libuv/src/unix/darwin-proctitle.c b/third-party/libuv/src/unix/darwin-proctitle.c new file mode 100644 index 0000000000..8cd358bcf0 --- /dev/null +++ b/third-party/libuv/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 <dlfcn.h> +#include <errno.h> +#include <stdlib.h> + +#include <TargetConditionals.h> + +#if !TARGET_OS_IPHONE +# include <CoreFoundation/CoreFoundation.h> +# include <ApplicationServices/ApplicationServices.h> +#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/third-party/libuv/src/unix/darwin.c b/third-party/libuv/src/unix/darwin.c new file mode 100644 index 0000000000..bc282e7912 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdint.h> +#include <errno.h> + +#include <ifaddrs.h> +#include <net/if.h> +#include <net/if_dl.h> + +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <mach-o/dyld.h> /* _NSGetExecutablePath */ +#include <sys/resource.h> +#include <sys/sysctl.h> +#include <unistd.h> /* 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/third-party/libuv/src/unix/dl.c b/third-party/libuv/src/unix/dl.c new file mode 100644 index 0000000000..cbffe4aa26 --- /dev/null +++ b/third-party/libuv/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 <dlfcn.h> +#include <errno.h> +#include <string.h> +#include <locale.h> + +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/third-party/libuv/src/unix/freebsd.c b/third-party/libuv/src/unix/freebsd.c new file mode 100644 index 0000000000..dcae244bb1 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <string.h> +#include <errno.h> + +#include <ifaddrs.h> +#include <net/if.h> +#include <net/if_dl.h> + +#include <kvm.h> +#include <paths.h> +#include <sys/user.h> +#include <sys/types.h> +#include <sys/resource.h> +#include <sys/sysctl.h> +#include <vm/vm_param.h> /* VM_LOADAVG */ +#include <time.h> +#include <stdlib.h> +#include <unistd.h> /* sysconf */ +#include <fcntl.h> + +#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/third-party/libuv/src/unix/fs.c b/third-party/libuv/src/unix/fs.c new file mode 100644 index 0000000000..1aa6539cb4 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <pthread.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#include <utime.h> +#include <poll.h> + +#if defined(__linux__) || defined(__sun) +# include <sys/sendfile.h> +#elif defined(__APPLE__) || defined(__FreeBSD__) +# include <sys/socket.h> +# include <sys/uio.h> +#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/third-party/libuv/src/unix/fsevents.c b/third-party/libuv/src/unix/fsevents.c new file mode 100644 index 0000000000..7faa1562a6 --- /dev/null +++ b/third-party/libuv/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 <dlfcn.h> +#include <assert.h> +#include <stdlib.h> +#include <pthread.h> + +#include <CoreFoundation/CFRunLoop.h> +#include <CoreServices/CoreServices.h> + +/* 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/third-party/libuv/src/unix/getaddrinfo.c b/third-party/libuv/src/unix/getaddrinfo.c new file mode 100644 index 0000000000..1db00680d1 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stddef.h> /* NULL */ +#include <stdlib.h> +#include <string.h> + + +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/third-party/libuv/src/unix/internal.h b/third-party/libuv/src/unix/internal.h new file mode 100644 index 0000000000..0ea82b51a0 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> /* abort */ +#include <string.h> /* strrchr */ + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__sun) +# include <sys/port.h> +# include <port.h> +#endif /* __sun */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include <CoreServices/CoreServices.h> +#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/third-party/libuv/src/unix/kqueue.c b/third-party/libuv/src/unix/kqueue.c new file mode 100644 index 0000000000..f86f291fc0 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +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/third-party/libuv/src/unix/linux-core.c b/third-party/libuv/src/unix/linux-core.c new file mode 100644 index 0000000000..f71dd2d6b9 --- /dev/null +++ b/third-party/libuv/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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <net/if.h> +#include <sys/param.h> +#include <sys/prctl.h> +#include <sys/sysinfo.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +#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 <ifaddrs.h> +# include <sys/socket.h> +# include <net/ethernet.h> +# include <linux/if_packet.h> +#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 <linux/time.h> but we can't + * include that file because it conflicts with <time.h>. 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<num> " 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/third-party/libuv/src/unix/linux-inotify.c b/third-party/libuv/src/unix/linux-inotify.c new file mode 100644 index 0000000000..7641f383c4 --- /dev/null +++ b/third-party/libuv/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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <unistd.h> + +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/third-party/libuv/src/unix/linux-syscalls.c b/third-party/libuv/src/unix/linux-syscalls.c new file mode 100644 index 0000000000..06cc5943cf --- /dev/null +++ b/third-party/libuv/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 <unistd.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <errno.h> + +#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/third-party/libuv/src/unix/linux-syscalls.h b/third-party/libuv/src/unix/linux-syscalls.h new file mode 100644 index 0000000000..1ad9518548 --- /dev/null +++ b/third-party/libuv/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 <stdint.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#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/third-party/libuv/src/unix/loop-watcher.c b/third-party/libuv/src/unix/loop-watcher.c new file mode 100644 index 0000000000..dc03c206d2 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/unix/loop.c b/third-party/libuv/src/unix/loop.c new file mode 100644 index 0000000000..94a5c03819 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <string.h> +#include <unistd.h> + +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/third-party/libuv/src/unix/netbsd.c b/third-party/libuv/src/unix/netbsd.c new file mode 100644 index 0000000000..7423a71078 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <string.h> +#include <errno.h> + +#include <kvm.h> +#include <paths.h> +#include <ifaddrs.h> +#include <unistd.h> +#include <time.h> +#include <stdlib.h> +#include <fcntl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <sys/resource.h> +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <unistd.h> +#include <time.h> + +#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/third-party/libuv/src/unix/openbsd.c b/third-party/libuv/src/unix/openbsd.c new file mode 100644 index 0000000000..f052d80c57 --- /dev/null +++ b/third-party/libuv/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 <sys/types.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <sys/sched.h> +#include <sys/time.h> +#include <sys/sysctl.h> + +#include <ifaddrs.h> +#include <net/if.h> +#include <net/if_dl.h> + +#include <errno.h> +#include <fcntl.h> +#include <kvm.h> +#include <paths.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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/third-party/libuv/src/unix/pipe.c b/third-party/libuv/src/unix/pipe.c new file mode 100644 index 0000000000..fd4afb6370 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <errno.h> +#include <string.h> +#include <sys/un.h> +#include <unistd.h> +#include <stdlib.h> + + +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/third-party/libuv/src/unix/poll.c b/third-party/libuv/src/unix/poll.c new file mode 100644 index 0000000000..a34a8d1e14 --- /dev/null +++ b/third-party/libuv/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 <unistd.h> +#include <assert.h> +#include <errno.h> + + +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/third-party/libuv/src/unix/process.c b/third-party/libuv/src/unix/process.c new file mode 100644 index 0000000000..6f96b754d8 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include <crt_externs.h> +# 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/third-party/libuv/src/unix/proctitle.c b/third-party/libuv/src/unix/proctitle.c new file mode 100644 index 0000000000..16b0523731 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <string.h> + +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/third-party/libuv/src/unix/pthread-fixes.c b/third-party/libuv/src/unix/pthread-fixes.c new file mode 100644 index 0000000000..2e4c542bc2 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/unix/signal.c b/third-party/libuv/src/unix/signal.c new file mode 100644 index 0000000000..0b7a405c15 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +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/third-party/libuv/src/unix/spinlock.h b/third-party/libuv/src/unix/spinlock.h new file mode 100644 index 0000000000..a20c83cc60 --- /dev/null +++ b/third-party/libuv/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl> + * + * 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/third-party/libuv/src/unix/stream.c b/third-party/libuv/src/unix/stream.c new file mode 100644 index 0000000000..9f5d40cf4b --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/un.h> +#include <unistd.h> +#include <limits.h> /* IOV_MAX */ + +#if defined(__APPLE__) +# include <sys/event.h> +# include <sys/time.h> +# include <sys/select.h> + +/* 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/third-party/libuv/src/unix/sunos.c b/third-party/libuv/src/unix/sunos.c new file mode 100644 index 0000000000..f31a23fb3c --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#ifndef SUNOS_NO_IFADDRS +# include <ifaddrs.h> +#endif +#include <net/if.h> +#include <net/if_dl.h> + +#include <sys/loadavg.h> +#include <sys/time.h> +#include <unistd.h> +#include <kstat.h> +#include <fcntl.h> + +#include <sys/port.h> +#include <port.h> + +#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 <procfs.h> + +#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/third-party/libuv/src/unix/tcp.c b/third-party/libuv/src/unix/tcp.c new file mode 100644 index 0000000000..2c36dc3ffc --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> + + +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/third-party/libuv/src/unix/thread.c b/third-party/libuv/src/unix/thread.c new file mode 100644 index 0000000000..f2ce082842 --- /dev/null +++ b/third-party/libuv/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 <pthread.h> +#include <assert.h> +#include <errno.h> + +#include <sys/time.h> + +#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/third-party/libuv/src/unix/threadpool.c b/third-party/libuv/src/unix/threadpool.c new file mode 100644 index 0000000000..7923250a09 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> + +#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/third-party/libuv/src/unix/timer.c b/third-party/libuv/src/unix/timer.c new file mode 100644 index 0000000000..240efad503 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <limits.h> + + +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/third-party/libuv/src/unix/tty.c b/third-party/libuv/src/unix/tty.c new file mode 100644 index 0000000000..ca9459dd0d --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <unistd.h> +#include <termios.h> +#include <errno.h> +#include <sys/ioctl.h> + +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/third-party/libuv/src/unix/udp.c b/third-party/libuv/src/unix/udp.c new file mode 100644 index 0000000000..a2b3dc3298 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> + + +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/third-party/libuv/src/unix/uv-dtrace.d b/third-party/libuv/src/unix/uv-dtrace.d new file mode 100644 index 0000000000..7848450c94 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/uv-common.c b/third-party/libuv/src/uv-common.c new file mode 100644 index 0000000000..e5fc507756 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <assert.h> +#include <stddef.h> /* NULL */ +#include <stdlib.h> /* malloc */ +#include <string.h> /* memset */ + +#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) && !defined(_WIN32) +# include <net/if.h> /* if_nametoindex */ +#endif + +/* EAI_* constants. */ +#if !defined(_WIN32) +# include <sys/types.h> +# include <sys/socket.h> +# include <netdb.h> +#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 = "<unknown>"; + } + + 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/third-party/libuv/src/uv-common.h b/third-party/libuv/src/uv-common.h new file mode 100644 index 0000000000..3bcdcef3d4 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stddef.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#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/third-party/libuv/src/version.c b/third-party/libuv/src/version.c new file mode 100644 index 0000000000..0636348dae --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/win/async.c b/third-party/libuv/src/win/async.c new file mode 100644 index 0000000000..e192ead90d --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/atomicops-inl.h b/third-party/libuv/src/win/atomicops-inl.h new file mode 100644 index 0000000000..61e006026c --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/win/core.c b/third-party/libuv/src/win/core.c new file mode 100644 index 0000000000..e1a77655ac --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <errno.h> +#include <limits.h> +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <crtdbg.h> + +#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/third-party/libuv/src/win/dl.c b/third-party/libuv/src/win/dl.c new file mode 100644 index 0000000000..d5b8f7c7d3 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/win/error.c b/third-party/libuv/src/win/error.c new file mode 100644 index 0000000000..3162bc787f --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <errno.h> +#include <malloc.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/fs-event.c b/third-party/libuv/src/win/fs-event.c new file mode 100644 index 0000000000..6132b79c82 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <malloc.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#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/third-party/libuv/src/win/fs.c b/third-party/libuv/src/win/fs.c new file mode 100644 index 0000000000..c4182758c7 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> +#include <malloc.h> +#include <direct.h> +#include <errno.h> +#include <fcntl.h> +#include <io.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/utime.h> +#include <stdio.h> + +#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/third-party/libuv/src/win/getaddrinfo.c b/third-party/libuv/src/win/getaddrinfo.c new file mode 100644 index 0000000000..fb4ab0a602 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <malloc.h> + +#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/third-party/libuv/src/win/handle-inl.h b/third-party/libuv/src/win/handle-inl.h new file mode 100644 index 0000000000..5776eb7f76 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> + +#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/third-party/libuv/src/win/handle.c b/third-party/libuv/src/win/handle.c new file mode 100644 index 0000000000..72b49d9790 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/internal.h b/third-party/libuv/src/win/internal.h new file mode 100644 index 0000000000..cf6c85846c --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/src/win/loop-watcher.c b/third-party/libuv/src/win/loop-watcher.c new file mode 100644 index 0000000000..6dbc861edd --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/pipe.c b/third-party/libuv/src/win/pipe.c new file mode 100644 index 0000000000..f3d3110d31 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/poll.c b/third-party/libuv/src/win/poll.c new file mode 100644 index 0000000000..75351afd75 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> + +#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/third-party/libuv/src/win/process-stdio.c b/third-party/libuv/src/win/process-stdio.c new file mode 100644 index 0000000000..5757764bfd --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> +#include <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/process.c b/third-party/libuv/src/win/process.c new file mode 100644 index 0000000000..813e522f75 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> + +#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/third-party/libuv/src/win/req-inl.h b/third-party/libuv/src/win/req-inl.h new file mode 100644 index 0000000000..353fe90b6d --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/req.c b/third-party/libuv/src/win/req.c new file mode 100644 index 0000000000..111cc5e289 --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#include "uv.h" +#include "internal.h" diff --git a/third-party/libuv/src/win/signal.c b/third-party/libuv/src/win/signal.c new file mode 100644 index 0000000000..9dc5fccc29 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <signal.h> + +#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/third-party/libuv/src/win/stream-inl.h b/third-party/libuv/src/win/stream-inl.h new file mode 100644 index 0000000000..e4bf086368 --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/stream.c b/third-party/libuv/src/win/stream.c new file mode 100644 index 0000000000..2eaa74e766 --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/tcp.c b/third-party/libuv/src/win/tcp.c new file mode 100644 index 0000000000..8fa2146a06 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/thread.c b/third-party/libuv/src/win/thread.c new file mode 100644 index 0000000000..5178f8f9ab --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <limits.h> +#include <stdlib.h> + +#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 <mutex> here since Win32 manual-reset events */ + /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to <uv_cond_signal> being */ + /* called or <uv_cond_broadcast> 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 <pthread_cond_broadcast>. */ + 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 <mutex>. */ + 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/third-party/libuv/src/win/threadpool.c b/third-party/libuv/src/win/threadpool.c new file mode 100644 index 0000000000..9539844c66 --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/timer.c b/third-party/libuv/src/win/timer.c new file mode 100644 index 0000000000..6c53ea37e0 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <limits.h> + +#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/third-party/libuv/src/win/tty.c b/third-party/libuv/src/win/tty.c new file mode 100644 index 0000000000..8855af350e --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <io.h> +#include <string.h> +#include <stdlib.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#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/third-party/libuv/src/win/udp.c b/third-party/libuv/src/win/udp.c new file mode 100644 index 0000000000..31812e4642 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/util.c b/third-party/libuv/src/win/util.c new file mode 100644 index 0000000000..266b881640 --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <direct.h> +#include <limits.h> +#include <malloc.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <wchar.h> + +#include "uv.h" +#include "internal.h" + +#include <winsock2.h> +#include <winperf.h> +#include <iphlpapi.h> +#include <psapi.h> +#include <tlhelp32.h> + + +/* + * 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/third-party/libuv/src/win/winapi.c b/third-party/libuv/src/win/winapi.c new file mode 100644 index 0000000000..3e439ea5b2 --- /dev/null +++ b/third-party/libuv/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 <assert.h> + +#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/third-party/libuv/src/win/winapi.h b/third-party/libuv/src/win/winapi.h new file mode 100644 index 0000000000..21d7fe4ac3 --- /dev/null +++ b/third-party/libuv/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 <windows.h> + + +/* + * 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/third-party/libuv/src/win/winsock.c b/third-party/libuv/src/win/winsock.c new file mode 100644 index 0000000000..938b6d031a --- /dev/null +++ b/third-party/libuv/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 <assert.h> +#include <stdlib.h> + +#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/third-party/libuv/src/win/winsock.h b/third-party/libuv/src/win/winsock.h new file mode 100644 index 0000000000..957d08ec19 --- /dev/null +++ b/third-party/libuv/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 <winsock2.h> +#include <iptypes.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <windows.h> + +#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/third-party/libuv/test/benchmark-async-pummel.c b/third-party/libuv/test/benchmark-async-pummel.c new file mode 100644 index 0000000000..4761c1928e --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-async.c b/third-party/libuv/test/benchmark-async.c new file mode 100644 index 0000000000..33d9ab446a --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-fs-stat.c b/third-party/libuv/test/benchmark-fs-stat.c new file mode 100644 index 0000000000..5c87de0043 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-getaddrinfo.c b/third-party/libuv/test/benchmark-getaddrinfo.c new file mode 100644 index 0000000000..c7f99a2fcb --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> + +#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/third-party/libuv/test/benchmark-list.h b/third-party/libuv/test/benchmark-list.h new file mode 100644 index 0000000000..1e843071c0 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-loop-count.c b/third-party/libuv/test/benchmark-loop-count.c new file mode 100644 index 0000000000..b4ee0ed5ff --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-million-async.c b/third-party/libuv/test/benchmark-million-async.c new file mode 100644 index 0000000000..69cc803436 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-million-timers.c b/third-party/libuv/test/benchmark-million-timers.c new file mode 100644 index 0000000000..64f4a1038e --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-multi-accept.c b/third-party/libuv/test/benchmark-multi-accept.c new file mode 100644 index 0000000000..d71235ef3b --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-ping-pongs.c b/third-party/libuv/test/benchmark-ping-pongs.c new file mode 100644 index 0000000000..bb560d7d21 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <stdio.h> + +/* 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/third-party/libuv/test/benchmark-pound.c b/third-party/libuv/test/benchmark-pound.c new file mode 100644 index 0000000000..587928549e --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-pump.c b/third-party/libuv/test/benchmark-pump.c new file mode 100644 index 0000000000..678634ff71 --- /dev/null +++ b/third-party/libuv/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 <math.h> +#include <stdio.h> + + +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/third-party/libuv/test/benchmark-sizes.c b/third-party/libuv/test/benchmark-sizes.c new file mode 100644 index 0000000000..8ccf10ee47 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-spawn.c b/third-party/libuv/test/benchmark-spawn.c new file mode 100644 index 0000000000..9cae41a83a --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/benchmark-tcp-write-batch.c b/third-party/libuv/test/benchmark-tcp-write-batch.c new file mode 100644 index 0000000000..96921b70db --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-thread.c b/third-party/libuv/test/benchmark-thread.c new file mode 100644 index 0000000000..b37a7fd6d0 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +#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/third-party/libuv/test/benchmark-udp-pummel.c b/third-party/libuv/test/benchmark-udp-pummel.c new file mode 100644 index 0000000000..d99250affc --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/blackhole-server.c b/third-party/libuv/test/blackhole-server.c new file mode 100644 index 0000000000..ad878b35c6 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/dns-server.c b/third-party/libuv/test/dns-server.c new file mode 100644 index 0000000000..80052c7039 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + + +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/third-party/libuv/test/echo-server.c b/third-party/libuv/test/echo-server.c new file mode 100644 index 0000000000..e5201b9f4c --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/fixtures/empty_file b/third-party/libuv/test/fixtures/empty_file new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/third-party/libuv/test/fixtures/empty_file diff --git a/third-party/libuv/test/fixtures/load_error.node b/third-party/libuv/test/fixtures/load_error.node new file mode 100644 index 0000000000..323fae03f4 --- /dev/null +++ b/third-party/libuv/test/fixtures/load_error.node @@ -0,0 +1 @@ +foobar diff --git a/third-party/libuv/test/run-benchmarks.c b/third-party/libuv/test/run-benchmarks.c new file mode 100644 index 0000000000..06732b71d3 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +#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/third-party/libuv/test/run-tests.c b/third-party/libuv/test/run-tests.c new file mode 100644 index 0000000000..d84be6a1a5 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stdio.h> +#include <string.h> + +#ifdef _WIN32 +# include <io.h> +#else +# include <unistd.h> +#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/third-party/libuv/test/runner-unix.c b/third-party/libuv/test/runner-unix.c new file mode 100644 index 0000000000..9afcd1e488 --- /dev/null +++ b/third-party/libuv/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 <stdint.h> /* uintptr_t */ + +#include <errno.h> +#include <unistd.h> /* usleep */ +#include <string.h> /* strdup */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <assert.h> + +#include <sys/select.h> +#include <pthread.h> + + +/* 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/third-party/libuv/test/runner-unix.h b/third-party/libuv/test/runner-unix.h new file mode 100644 index 0000000000..e21847f92c --- /dev/null +++ b/third-party/libuv/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 <sys/types.h> +#include <stdio.h> /* 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/third-party/libuv/test/runner-win.c b/third-party/libuv/test/runner-win.c new file mode 100644 index 0000000000..83d76783f6 --- /dev/null +++ b/third-party/libuv/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 <fcntl.h> +#include <io.h> +#include <malloc.h> +#include <stdio.h> +#include <process.h> +#if !defined(__MINGW32__) +# include <crtdbg.h> +#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/third-party/libuv/test/runner-win.h b/third-party/libuv/test/runner-win.h new file mode 100644 index 0000000000..c94b89bd5e --- /dev/null +++ b/third-party/libuv/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 <winsock2.h> +#include <windows.h> +#include <stdio.h> + + +/* 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/third-party/libuv/test/runner.c b/third-party/libuv/test/runner.c new file mode 100644 index 0000000000..f4d982c5b6 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +#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 "<buffer too small>"; + + 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/third-party/libuv/test/runner.h b/third-party/libuv/test/runner.h new file mode 100644 index 0000000000..aa7f205407 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> /* 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-<platform>.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/third-party/libuv/test/task.h b/third-party/libuv/test/task.h new file mode 100644 index 0000000000..b736c375c7 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stddef.h> +#include <stdlib.h> + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include <stdint.h> +#endif + +#if !defined(_WIN32) +# include <sys/time.h> +# include <sys/resource.h> /* 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 <io.h> +# 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 <stdarg.h> + +/* 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/third-party/libuv/test/test-active.c b/third-party/libuv/test/test-active.c new file mode 100644 index 0000000000..0fae23cdb1 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-async-null-cb.c b/third-party/libuv/test/test-async-null-cb.c new file mode 100644 index 0000000000..d654884268 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-async.c b/third-party/libuv/test/test-async.c new file mode 100644 index 0000000000..d4d94d5fa0 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/test-barrier.c b/third-party/libuv/test/test-barrier.c new file mode 100644 index 0000000000..97df704c0e --- /dev/null +++ b/third-party/libuv/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 <string.h> +#include <errno.h> + +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/third-party/libuv/test/test-callback-order.c b/third-party/libuv/test/test-callback-order.c new file mode 100644 index 0000000000..84231e1b6b --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-callback-stack.c b/third-party/libuv/test/test-callback-stack.c new file mode 100644 index 0000000000..accd549697 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-close-fd.c b/third-party/libuv/test/test-close-fd.c new file mode 100644 index 0000000000..0d17f07661 --- /dev/null +++ b/third-party/libuv/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 <fcntl.h> +#include <unistd.h> + +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/third-party/libuv/test/test-close-order.c b/third-party/libuv/test/test-close-order.c new file mode 100644 index 0000000000..e2f25f987d --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-condvar.c b/third-party/libuv/test/test-condvar.c new file mode 100644 index 0000000000..dbacdba384 --- /dev/null +++ b/third-party/libuv/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 <string.h> +#include <errno.h> + +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/third-party/libuv/test/test-connection-fail.c b/third-party/libuv/test/test-connection-fail.c new file mode 100644 index 0000000000..5700140130 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <stdio.h> + + +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/third-party/libuv/test/test-cwd-and-chdir.c b/third-party/libuv/test/test-cwd-and-chdir.c new file mode 100644 index 0000000000..f1082ac47f --- /dev/null +++ b/third-party/libuv/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 <string.h> + +#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/third-party/libuv/test/test-delayed-accept.c b/third-party/libuv/test/test-delayed-accept.c new file mode 100644 index 0000000000..b45100d625 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/test-dlerror.c b/third-party/libuv/test/test-dlerror.c new file mode 100644 index 0000000000..877ebf3712 --- /dev/null +++ b/third-party/libuv/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 <string.h> + + +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/third-party/libuv/test/test-embed.c b/third-party/libuv/test/test-embed.c new file mode 100644 index 0000000000..ac1b3b6750 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#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 <sys/types.h> +# include <sys/event.h> +# include <sys/time.h> +#endif + +#if defined(HAVE_EPOLL) +# include <sys/epoll.h> +#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/third-party/libuv/test/test-emfile.c b/third-party/libuv/test/test-emfile.c new file mode 100644 index 0000000000..453bfe4cf5 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <stdio.h> +#include <sys/resource.h> +#include <unistd.h> + +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/third-party/libuv/test/test-error.c b/third-party/libuv/test/test-error.c new file mode 100644 index 0000000000..eb337e66f3 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* + * 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/third-party/libuv/test/test-fail-always.c b/third-party/libuv/test/test-fail-always.c new file mode 100644 index 0000000000..0008459eac --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-fs-event.c b/third-party/libuv/test/test-fs-event.c new file mode 100644 index 0000000000..3286de51f9 --- /dev/null +++ b/third-party/libuv/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 <string.h> +#include <fcntl.h> + +#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/third-party/libuv/test/test-fs-poll.c b/third-party/libuv/test/test-fs-poll.c new file mode 100644 index 0000000000..9213f04b34 --- /dev/null +++ b/third-party/libuv/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 <string.h> + +#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/third-party/libuv/test/test-fs.c b/third-party/libuv/test/test-fs.c new file mode 100644 index 0000000000..f0ff824f40 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <string.h> /* memset */ +#include <fcntl.h> +#include <sys/stat.h> + +/* FIXME we shouldn't need to branch in this file */ +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) +#include <unistd.h> /* unlink, rmdir, etc. */ +#else +# include <direct.h> +# include <io.h> +# 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/third-party/libuv/test/test-get-currentexe.c b/third-party/libuv/test/test-get-currentexe.c new file mode 100644 index 0000000000..be578db75d --- /dev/null +++ b/third-party/libuv/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 <string.h> + +#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/third-party/libuv/test/test-get-loadavg.c b/third-party/libuv/test/test-get-loadavg.c new file mode 100644 index 0000000000..7465e18b91 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-get-memory.c b/third-party/libuv/test/test-get-memory.c new file mode 100644 index 0000000000..2396939bcb --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-getaddrinfo.c b/third-party/libuv/test/test-getaddrinfo.c new file mode 100644 index 0000000000..bca2a6bd70 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> + +#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/third-party/libuv/test/test-getsockname.c b/third-party/libuv/test/test-getsockname.c new file mode 100644 index 0000000000..a67d967f0b --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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/third-party/libuv/test/test-hrtime.c b/third-party/libuv/test/test-hrtime.c new file mode 100644 index 0000000000..72a4d4b181 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-idle.c b/third-party/libuv/test/test-idle.c new file mode 100644 index 0000000000..7eea1b83b1 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-ip4-addr.c b/third-party/libuv/test/test-ip4-addr.c new file mode 100644 index 0000000000..3d6e0cf286 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + + +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/third-party/libuv/test/test-ip6-addr.c b/third-party/libuv/test/test-ip6-addr.c new file mode 100644 index 0000000000..ddd0812285 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +#ifdef __linux__ +# include <sys/socket.h> +# include <net/if.h> +#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/third-party/libuv/test/test-ipc-send-recv.c b/third-party/libuv/test/test-ipc-send-recv.c new file mode 100644 index 0000000000..b2b5aa0e92 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +/* 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/third-party/libuv/test/test-ipc.c b/third-party/libuv/test/test-ipc.c new file mode 100644 index 0000000000..cc44d32e28 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +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/third-party/libuv/test/test-list.h b/third-party/libuv/test/test-list.h new file mode 100644 index 0000000000..c3e15783b5 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-loop-alive.c b/third-party/libuv/test/test-loop-alive.c new file mode 100644 index 0000000000..89243357c3 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-loop-handles.c b/third-party/libuv/test/test-loop-handles.c new file mode 100644 index 0000000000..fdf9281478 --- /dev/null +++ b/third-party/libuv/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 <math.h> + + +#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/third-party/libuv/test/test-loop-stop.c b/third-party/libuv/test/test-loop-stop.c new file mode 100644 index 0000000000..c519644ed2 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-loop-time.c b/third-party/libuv/test/test-loop-time.c new file mode 100644 index 0000000000..49dc79b2c3 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-multiple-listen.c b/third-party/libuv/test/test-multiple-listen.c new file mode 100644 index 0000000000..4ae5fa67b3 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/test-mutexes.c b/third-party/libuv/test/test-mutexes.c new file mode 100644 index 0000000000..896f46bbed --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +/* 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/third-party/libuv/test/test-osx-select.c b/third-party/libuv/test/test-osx-select.c new file mode 100644 index 0000000000..e5e1bf8b46 --- /dev/null +++ b/third-party/libuv/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 <sys/ioctl.h> +#include <string.h> + +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/third-party/libuv/test/test-pass-always.c b/third-party/libuv/test/test-pass-always.c new file mode 100644 index 0000000000..4fb58ff94b --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-ping-pong.c b/third-party/libuv/test/test-ping-pong.c new file mode 100644 index 0000000000..c579fdd668 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <stdio.h> + +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/third-party/libuv/test/test-pipe-bind-error.c b/third-party/libuv/test/test-pipe-bind-error.c new file mode 100644 index 0000000000..38b57db699 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +#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/third-party/libuv/test/test-pipe-connect-error.c b/third-party/libuv/test/test-pipe-connect-error.c new file mode 100644 index 0000000000..ebb2a6ca82 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +#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/third-party/libuv/test/test-pipe-server-close.c b/third-party/libuv/test/test-pipe-server-close.c new file mode 100644 index 0000000000..1dcdfffaf7 --- /dev/null +++ b/third-party/libuv/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 <string.h> +#include <errno.h> + + +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/third-party/libuv/test/test-platform-output.c b/third-party/libuv/test/test-platform-output.c new file mode 100644 index 0000000000..d2104f40a1 --- /dev/null +++ b/third-party/libuv/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 <string.h> + + +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/third-party/libuv/test/test-poll-close.c b/third-party/libuv/test/test-poll-close.c new file mode 100644 index 0000000000..2eccddf5b0 --- /dev/null +++ b/third-party/libuv/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 <errno.h> + +#ifndef _WIN32 +# include <fcntl.h> +# include <sys/socket.h> +# include <unistd.h> +#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/third-party/libuv/test/test-poll.c b/third-party/libuv/test/test-poll.c new file mode 100644 index 0000000000..0736b9b0bf --- /dev/null +++ b/third-party/libuv/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 <errno.h> + +#ifndef _WIN32 +# include <fcntl.h> +# include <sys/socket.h> +# include <unistd.h> +#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/third-party/libuv/test/test-process-title.c b/third-party/libuv/test/test-process-title.c new file mode 100644 index 0000000000..29be20749b --- /dev/null +++ b/third-party/libuv/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 <string.h> + + +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/third-party/libuv/test/test-ref.c b/third-party/libuv/test/test-ref.c new file mode 100644 index 0000000000..7ff2e84e38 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <string.h> + + +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/third-party/libuv/test/test-run-nowait.c b/third-party/libuv/test/test-run-nowait.c new file mode 100644 index 0000000000..ee4b36ff3b --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-run-once.c b/third-party/libuv/test/test-run-once.c new file mode 100644 index 0000000000..e243de0ade --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-semaphore.c b/third-party/libuv/test/test-semaphore.c new file mode 100644 index 0000000000..ac03bb08f1 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <string.h> + +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/third-party/libuv/test/test-shutdown-close.c b/third-party/libuv/test/test-shutdown-close.c new file mode 100644 index 0000000000..78c369be2d --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-shutdown-eof.c b/third-party/libuv/test/test-shutdown-eof.c new file mode 100644 index 0000000000..58346361c7 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/test-signal-multiple-loops.c b/third-party/libuv/test/test-signal-multiple-loops.c new file mode 100644 index 0000000000..e80154e3e8 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* 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/third-party/libuv/test/test-signal.c b/third-party/libuv/test/test-signal.c new file mode 100644 index 0000000000..9fb1c7f916 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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/third-party/libuv/test/test-spawn.c b/third-party/libuv/test/test-spawn.c new file mode 100644 index 0000000000..5f71fce2c0 --- /dev/null +++ b/third-party/libuv/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 <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef _WIN32 +#include <unistd.h> +#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/third-party/libuv/test/test-stdio-over-pipes.c b/third-party/libuv/test/test-stdio-over-pipes.c new file mode 100644 index 0000000000..1574476104 --- /dev/null +++ b/third-party/libuv/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 <stdlib.h> +#include <string.h> + + +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/third-party/libuv/test/test-tcp-bind-error.c b/third-party/libuv/test/test-tcp-bind-error.c new file mode 100644 index 0000000000..96bfe11601 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-bind6-error.c b/third-party/libuv/test/test-tcp-bind6-error.c new file mode 100644 index 0000000000..1d65f3de3e --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-close-accept.c b/third-party/libuv/test/test-tcp-close-accept.c new file mode 100644 index 0000000000..10f9d91964 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <string.h> + +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/third-party/libuv/test/test-tcp-close-while-connecting.c b/third-party/libuv/test/test-tcp-close-while-connecting.c new file mode 100644 index 0000000000..b9f7f9661c --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-tcp-close.c b/third-party/libuv/test/test-tcp-close.c new file mode 100644 index 0000000000..e65885aa55 --- /dev/null +++ b/third-party/libuv/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 <errno.h> +#include <string.h> /* 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/third-party/libuv/test/test-tcp-connect-error-after-write.c b/third-party/libuv/test/test-tcp-connect-error-after-write.c new file mode 100644 index 0000000000..3f2e3572da --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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/third-party/libuv/test/test-tcp-connect-error.c b/third-party/libuv/test/test-tcp-connect-error.c new file mode 100644 index 0000000000..eab1eeb254 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-connect-timeout.c b/third-party/libuv/test/test-tcp-connect-timeout.c new file mode 100644 index 0000000000..cc583cafb2 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-connect6-error.c b/third-party/libuv/test/test-tcp-connect6-error.c new file mode 100644 index 0000000000..91ac0a3a10 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-flags.c b/third-party/libuv/test/test-tcp-flags.c new file mode 100644 index 0000000000..68afb39f45 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +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/third-party/libuv/test/test-tcp-open.c b/third-party/libuv/test/test-tcp-open.c new file mode 100644 index 0000000000..edeacc70e4 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef _WIN32 +# include <unistd.h> +#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/third-party/libuv/test/test-tcp-read-stop.c b/third-party/libuv/test/test-tcp-read-stop.c new file mode 100644 index 0000000000..c8d9c0407e --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-tcp-shutdown-after-write.c b/third-party/libuv/test/test-tcp-shutdown-after-write.c new file mode 100644 index 0000000000..c59acc4020 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-tcp-try-write.c b/third-party/libuv/test/test-tcp-try-write.c new file mode 100644 index 0000000000..00341e4169 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-tcp-unexpected-read.c b/third-party/libuv/test/test-tcp-unexpected-read.c new file mode 100644 index 0000000000..11fee8ba8e --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-tcp-write-to-half-open-connection.c b/third-party/libuv/test/test-tcp-write-to-half-open-connection.c new file mode 100644 index 0000000000..2fa2ae7225 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +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/third-party/libuv/test/test-tcp-writealot.c b/third-party/libuv/test/test-tcp-writealot.c new file mode 100644 index 0000000000..6cfe2ebb18 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + + +#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/third-party/libuv/test/test-thread.c b/third-party/libuv/test/test-thread.c new file mode 100644 index 0000000000..c396baa100 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> /* 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/third-party/libuv/test/test-threadpool-cancel.c b/third-party/libuv/test/test-threadpool-cancel.c new file mode 100644 index 0000000000..1443773cc2 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-threadpool.c b/third-party/libuv/test/test-threadpool.c new file mode 100644 index 0000000000..e3d17d7546 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-timer-again.c b/third-party/libuv/test/test-timer-again.c new file mode 100644 index 0000000000..1638da2dfc --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-timer-from-check.c b/third-party/libuv/test/test-timer-from-check.c new file mode 100644 index 0000000000..2aa3fe4119 --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-timer.c b/third-party/libuv/test/test-timer.c new file mode 100644 index 0000000000..bbe69f68be --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/test/test-tty.c b/third-party/libuv/test/test-tty.c new file mode 100644 index 0000000000..fb69910732 --- /dev/null +++ b/third-party/libuv/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 <io.h> +# include <windows.h> +#else /* Unix */ +# include <fcntl.h> +# include <unistd.h> +#endif + +#include <string.h> +#include <errno.h> + + +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/third-party/libuv/test/test-udp-dgram-too-big.c b/third-party/libuv/test/test-udp-dgram-too-big.c new file mode 100644 index 0000000000..bd44c42528 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-udp-ipv6.c b/third-party/libuv/test/test-udp-ipv6.c new file mode 100644 index 0000000000..32cabf097c --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-udp-multicast-join.c b/third-party/libuv/test/test-udp-multicast-join.c new file mode 100644 index 0000000000..686edf3d22 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-udp-multicast-ttl.c b/third-party/libuv/test/test-udp-multicast-ttl.c new file mode 100644 index 0000000000..bed0ea1342 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-udp-open.c b/third-party/libuv/test/test-udp-open.c new file mode 100644 index 0000000000..9a97303f12 --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef _WIN32 +# include <unistd.h> +#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/third-party/libuv/test/test-udp-options.c b/third-party/libuv/test/test-udp-options.c new file mode 100644 index 0000000000..5cc369878a --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + + +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/third-party/libuv/test/test-udp-send-and-recv.c b/third-party/libuv/test/test-udp-send-and-recv.c new file mode 100644 index 0000000000..3020ded7bf --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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/third-party/libuv/test/test-walk-handles.c b/third-party/libuv/test/test-walk-handles.c new file mode 100644 index 0000000000..f2ae41564f --- /dev/null +++ b/third-party/libuv/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 <stdio.h> +#include <stdlib.h> + +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/third-party/libuv/test/test-watcher-cross-stop.c b/third-party/libuv/test/test-watcher-cross-stop.c new file mode 100644 index 0000000000..c701dd2f91 --- /dev/null +++ b/third-party/libuv/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 <string.h> +#include <errno.h> + +/* 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/third-party/libuv/uv.gyp b/third-party/libuv/uv.gyp new file mode 100644 index 0000000000..50e19357de --- /dev/null +++ b/third-party/libuv/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/third-party/libuv/vcbuild.bat b/third-party/libuv/vcbuild.bat new file mode 100644 index 0000000000..8545b2635b --- /dev/null +++ b/third-party/libuv/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 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 <Bram@vim.org>. 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 + <maintainer@vim.org> + +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. |