diff --git a/autoload/SpaceVim/layers/core.vim b/autoload/SpaceVim/layers/core.vim index 7e1bf52a8..12b765ffa 100644 --- a/autoload/SpaceVim/layers/core.vim +++ b/autoload/SpaceVim/layers/core.vim @@ -24,7 +24,7 @@ function! SpaceVim#layers#core#plugins() abort \ 'merged' : 0, \ 'loadconf' : 1 \ }]) - call add(plugins, ['Shougo/vimproc.vim', {'build' : [(executable('gmake') ? 'gmake' : 'make')]}]) + call add(plugins, [g:_spacevim_root_dir . 'bundle/vimproc.vim', {'build' : [(executable('gmake') ? 'gmake' : 'make')]}]) elseif g:spacevim_filemanager ==# 'defx' call add(plugins, [g:_spacevim_root_dir . 'bundle/defx.nvim',{'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}]) call add(plugins, [g:_spacevim_root_dir . 'bundle/defx-git',{'merged' : 0, 'loadconf' : 1}]) diff --git a/bundle/vimproc.vim/.gitattributes b/bundle/vimproc.vim/.gitattributes new file mode 100644 index 000000000..cd41d1a02 --- /dev/null +++ b/bundle/vimproc.vim/.gitattributes @@ -0,0 +1 @@ +*.bat text eol=crlf diff --git a/bundle/vimproc.vim/.gitignore b/bundle/vimproc.vim/.gitignore new file mode 100644 index 000000000..6f609e9f5 --- /dev/null +++ b/bundle/vimproc.vim/.gitignore @@ -0,0 +1,8 @@ +lib/* +doc/tags +*.obj +*.o +*.so +*.dll +*.swp +*~ diff --git a/bundle/vimproc.vim/.travis.yml b/bundle/vimproc.vim/.travis.yml new file mode 100644 index 000000000..4d5aa1f64 --- /dev/null +++ b/bundle/vimproc.vim/.travis.yml @@ -0,0 +1,40 @@ +matrix: + include: + - os: linux + env: + - VIM_VERSION=7.4 + - os: linux + env: + - VIM_VERSION=8.0.0000 + - os: linux + env: + - VIM_VERSION=8.1.0000 + - os: linux + env: + - VIM_VERSION=8.2.0000 + - os: osx + +sudo: false + +before_script: + - git clone https://github.com/thinca/vim-themis /tmp/vim-themis + - | + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + (if ! test -d $HOME/vim-$VIM_VERSION/bin; then + git clone https://github.com/vim/vim $HOME/vim && + cd $HOME/vim && + git checkout v$VIM_VERSION && + ./configure --prefix=$HOME/vim-$VIM_VERSION && + make && + make install; + fi) + fi + export PATH=$HOME/vim-$VIM_VERSION/bin:$PATH +cache: + directories: + - $HOME/vim-$VIM_VERSION + +script: + - make + - vim --version + - /tmp/vim-themis/bin/themis diff --git a/bundle/vimproc.vim/Makefile b/bundle/vimproc.vim/Makefile new file mode 100644 index 000000000..445ca3488 --- /dev/null +++ b/bundle/vimproc.vim/Makefile @@ -0,0 +1,70 @@ +ifeq ($(OS),Windows_NT) + # Need to figure out if Cygwin/Mingw is installed + SYS := $(shell gcc -dumpmachine) + ifeq ($(findstring cygwin, $(SYS)),cygwin) + ifeq ($(findstring x86_64, $(SYS)),x86_64) + PLATFORM = cygwin64 + else + PLATFORM = cygwin + endif + endif + ifeq ($(findstring msys, $(SYS)),msys) + ifeq ($(findstring x86_64, $(SYS)),x86_64) + PLATFORM = cygwin64 + else + PLATFORM = cygwin + endif + endif + ifeq ($(findstring mingw, $(SYS)),mingw) + ifeq ($(findstring x86_64, $(SYS)),x86_64) + PLATFORM = mingw64 + else + PLATFORM = mingw32 + endif + endif +else + # Grab the output of `uname -s` and switch to set the platform + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + PLATFORM = unix + endif + ifeq ($(UNAME_S),GNU) + # GNU/Hurd + PLATFORM = unix + endif + ifeq ($(UNAME_S),FreeBSD) + MAKE = make # BSD Make + PLATFORM = bsd + endif + ifeq ($(UNAME_S),DragonFly) + MAKE = make # BSD Make + PLATFORM = bsd + endif + ifeq ($(UNAME_S),NetBSD) + MAKE = make # BSD Make + PLATFORM = bsd + endif + ifeq ($(UNAME_S),OpenBSD) + MAKE = make # BSD Make + PLATFORM = bsd + endif + ifeq ($(UNAME_S),Darwin) + PLATFORM = mac + endif + ifeq ($(UNAME_S),SunOS) + PLATFORM = sunos + endif +endif + +# Verify that the PLATFORM was detected +ifndef PLATFORM + $(error Autodetection of platform failed, please use appropriate .mak file) +endif + +# Invoke the platform specific make files +all: + $(MAKE) -f make_$(PLATFORM).mak + +clean: + $(MAKE) -f make_$(PLATFORM).mak clean + diff --git a/bundle/vimproc.vim/README.mkd b/bundle/vimproc.vim/README.mkd new file mode 100644 index 000000000..8fac9bacb --- /dev/null +++ b/bundle/vimproc.vim/README.mkd @@ -0,0 +1,171 @@ +# vimproc + +[![Travis Build Status](https://travis-ci.org/Shougo/vimproc.vim.svg?branch=master)](https://travis-ci.org/Shougo/vimproc.vim) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/nutwxuj2poauar2b/branch/master?svg=true)](https://ci.appveyor.com/project/Shougo/vimproc-vim/branch/master) +[![GitHub release](https://img.shields.io/github/release/Shougo/vimproc.vim.svg)](https://github.com/Shougo/vimproc.vim/releases) + +vimproc is a great asynchronous execution library for Vim. It is a fork of +proc.vim by Yukihiro Nakadaira. I added some features and fixed some bugs and +I'm maintaining it now. Instead of an external shell (example: 'shell'), +vimproc uses an external DLL file. + +Supported platforms: +* Windows 32/64bit (Compiled by MinGW or Visual Studio) +* macOS (10.5 or later) +* Linux +* Cygwin +* Solaris +* BSD (but cannot check) +* Android (experimental) + +Not supported platforms: +* Other UNIX platforms + +## Install + +### Manual Install + +* Clone this repo +* Build vimproc's native extensions (see Building for details) +* Copy `autoload/*`, `lib/*` and `plugin/*` files to your 'runtimepath' + directory (see `:help runtimepath`). + +### dein.vim + +If you use [dein.vim](http://github.com/Shougo/dein.vim), you can +update and build vimproc automatically. This is the recommended package manager. + +```vim +call dein#add('Shougo/vimproc.vim', {'build' : 'make'}) +``` + +### Vim-Plug + +If you use [vim-plug](https://github.com/junegunn/vim-plug), you can update and build vimproc automatically. + +```vim +Plug 'Shougo/vimproc.vim', {'do' : 'make'} +``` +### Vundle + +If you use [Vundle](https://github.com/VundleVim/Vundle.vim), add the following to your `.vimrc`. + +```vim +Plugin 'Shougo/vimproc.vim' +``` +Then compile the plugin manually where it was installed. + +i.e. on Linux & Mac +```bash +$ cd ~/.vim/bundle/vimproc.vim && make +``` + +See [building](https://github.com/Shougo/vimproc.vim#building) + +### NeoBundle + +If you use [neobundle.vim](http://github.com/Shougo/neobundle.vim), you can +update and build vimproc automatically. + +```vim +NeoBundle 'Shougo/vimproc.vim', { +\ 'build' : { +\ 'windows' : 'tools\\update-dll-mingw', +\ 'cygwin' : 'make -f make_cygwin.mak', +\ 'mac' : 'make', +\ 'linux' : 'make', +\ 'unix' : 'gmake', +\ }, +\ } +``` + +### Pathogen + +vimproc uses a pathogen compatible structure, so it can be managed with +[pathogen](https://github.com/tpope/vim-pathogen), however you must remember to +compile after cloning the repo. + +```sh +git clone https://github.com/Shougo/vimproc.vim.git ~/.vim/bundle/vimproc.vim +cd ~/.vim/bundle/vimproc.vim +make +``` + +## Building + +Note: You must use GNU make to build vimproc. + +You can install the dll using |VimProcInstall|. If you are having any trouble +or want to build manually then read on. + +### Linux + + $ make + +### macOS + +Note: Users of macOS 10.15 (Catalina) cannot directly use this library with the system-provided vi. (SIP prevents binaries in the write-only `/usr/bin` directory from calling `dlopen` on unsigned libraries like `vimproc_mac.so`.) The simplest solution is to build or install another version of vi in a non-SIP protected location. For example, using homebrew, `brew install vim` (or `nvim`) will install an unrestricted executable in `/usr/local/bin`. (Don't forget to set up aliases or `$PATH` so that you don't accidentally invoke the system `vi`.) + + $ make + +Note: If you want to build for multiple architectures, you can use `ARCHS` and `CC` variables. + +Build for i386 and x86-64: + + $ make ARCHS='i386 x86_64' + +### FreeBSD + + $ gmake + +If you want to use BSD make, use the platform specific makefile: + + $ make -f make_bsd.mak + +### Solaris + + $ gmake + +Note: If you want to use Sun Compiler, you can use `SUNCC` variable. + + $ gmake SUNCC=cc + +### Windows + +Note: In Windows, using MinGW is recommended. +Note: If you have not "gcc" binary, you must change $CC value. + +Windows using MinGW (32bit Vim): + + $ mingw32-make -f make_mingw32.mak + +Windows using MinGW (If you want to use MinGW compiler in Cygwin): + + $ mingw32-make -f make_mingw32.mak CC=mingw32-gcc + +Windows using MinGW (64bit Vim): + + $ mingw32-make -f make_mingw64.mak + +Windows using Visual Studio (32bit/64bit Vim): + + $ nmake -f make_msvc.mak + +You should run this from VS command prompt. +The architecture will be automatically detected, but you can also specify the +architecture explicitly. E.g.: + + 32bit: nmake -f make_msvc.mak CPU=i386 + 64bit: nmake -f make_msvc.mak CPU=AMD64 + +Cygwin: + + $ make + +Note: The `vimproc_cygwin.dll` compiled in Cygwin won't work with Windows Vim. + +### Windows Binaries + +* [Kaoriya Vim](http://www.kaoriya.net/software/vim/) comes bundled with a precompiled version +for vimproc in Windows environment +* https://github.com/Shougo/vimproc.vim/releases diff --git a/bundle/vimproc.vim/appveyor.yml b/bundle/vimproc.vim/appveyor.yml new file mode 100644 index 000000000..25fe9ad5e --- /dev/null +++ b/bundle/vimproc.vim/appveyor.yml @@ -0,0 +1,45 @@ +--- +version: '{build}' +shallow_clone: true +environment: + global: + AUTH_TOKEN: + secure: rKd6JLXUIl3vcA8d0S9w14bl+uvUlZLt0d1M8bmlOh+owQqr5c40+/4ITCNBpHG3 + matrix: + - COMPILER: msvc + CPU: i386 + ENV: /x86 + BIT: 32 + - COMPILER: msvc + CPU: AMD64 + ENV: /x64 + BIT: 64 + - COMPILER: cygwin + BIT: 32 + - COMPILER: cygwin + BIT: 64 + - COMPILER: msys2 + MSYS2_ARCH: i686 + MSYS2_DIR: msys64 + MSYSTEM: MINGW32 + BIT: 32 + - COMPILER: msys2 + MSYS2_ARCH: x86_64 + MSYS2_DIR: msys64 + MSYSTEM: MINGW64 + BIT: 64 +build_script: + - '%APPVEYOR_BUILD_FOLDER%\tools\appveyor.bat' +test_script: + - '%APPVEYOR_BUILD_FOLDER%\tools\appveyor.bat test' +artifacts: + - path: lib/vimproc_*.dll + name: vimproc.dll +deploy: + provider: GitHub + description: vimproc + auth_token: + secure: rKd6JLXUIl3vcA8d0S9w14bl+uvUlZLt0d1M8bmlOh+owQqr5c40+/4ITCNBpHG3 + on: + appveyor_repo_tag: true + COMPILER: msvc diff --git a/bundle/vimproc.vim/autoload/vimproc.vim b/bundle/vimproc.vim/autoload/vimproc.vim new file mode 100644 index 000000000..21f60dd67 --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc.vim @@ -0,0 +1,1797 @@ +"============================================================================= +" FILE: vimproc.vim +" AUTHOR: Shougo Matsushita (Modified) +" Yukihiro Nakadaira (Original) +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 exists('g:vimproc#disable') + finish +endif + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +function! s:print_error(string) abort + echohl Error | echomsg '[vimproc] ' . a:string | echohl None +endfunction + +" Check 'encoding' "{{{ +if &encoding =~# '^euc-jp' + call s:print_error('Sorry, vimproc does not support this encoding environment.') + call s:print_error('You should set ''encoding'' option to "utf-8" ' + \ .'and set ''termencoding'' option to "euc-jp".') + finish +endif +"}}} + +" Version info "{{{ +let s:MAJOR_VERSION = 9 +let s:MINOR_VERSION = 3 +let s:VERSION_NUMBER = str2nr(printf('%2d%02d', s:MAJOR_VERSION, s:MINOR_VERSION)) +let s:VERSION_STRING = printf('%d.%d', s:MAJOR_VERSION, s:MINOR_VERSION) +"}}} + +" Global options definition. "{{{ +" Set the default of g:vimproc_dll_path by judging OS "{{{ +if vimproc#util#is_windows() + let s:vimproc_dll_basename = has('win64') ? + \ 'vimproc_win64.dll' : 'vimproc_win32.dll' +elseif vimproc#util#is_cygwin() + let s:vimproc_dll_basename = 'vimproc_cygwin.dll' + if system('uname -m') =~? '^x86_64$' + let s:vimproc_dll_basename = 'vimproc_cygwin64.dll' + endif +elseif vimproc#util#is_mac() + let s:vimproc_dll_basename = 'vimproc_mac.so' +elseif glob('/lib*/ld-linux*64.so.2',1) != '' + let s:vimproc_dll_basename = 'vimproc_linux64.so' +elseif glob('/lib*/ld-linux*.so.2',1) != '' + let s:vimproc_dll_basename = 'vimproc_linux32.so' +elseif system('uname -s') =~? '^.\+BSD\n$' + let s:vimproc_dll_basename = system( + \ 'uname -sm | tr "[:upper:]" "[:lower:]"' + \ .' | sed -e "s/ /_/" | xargs -I "{}" echo "vimproc_{}.so"')[0 : -2] +else + let s:vimproc_dll_basename = 'vimproc_unix.so' +endif +"}}} + +call vimproc#util#set_default( + \ 'g:vimproc#dll_path', + \ expand(':p:h:h') . '/lib/' . s:vimproc_dll_basename, + \ 'g:vimproc_dll_path') +unlet s:vimproc_dll_basename + +call vimproc#util#set_default( + \'g:vimproc#download_windows_dll', 0) +call vimproc#util#set_default( + \ 'g:vimproc#password_pattern', + \ '\%(Enter \|Repeat \|[Oo]ld \|[Nn]ew \|login ' . + \'\|Kerberos \|EncFS \|CVS \|UNIX \| SMB \|LDAP \|\[sudo] ' . + \'\|^\|\n\|''s \)\%([Pp]assword\|[Pp]assphrase\)\>', + \ 'g:vimproc_password_pattern') +call vimproc#util#set_default( + \ 'g:vimproc#popen2_commands', { + \ 'sh' : 1, 'bash' : 1, 'zsh' : 1, 'csh' : 1, 'tcsh' : 1, + \ 'tmux' : 1, 'screen' : 1, 'su' : 1, + \ 'python' : 1, 'rhino' : 1, 'ipython' : 1, 'ipython3' : 1, 'yaourt' : 1, + \ }, 'g:vimproc_popen2_commands') +call vimproc#util#set_default( + \ 'g:stdinencoding', 'char') +call vimproc#util#set_default( + \ 'g:stdoutencoding', 'char') +call vimproc#util#set_default( + \ 'g:stderrencoding', 'char') +"}}} + +" Constants {{{ +function! s:define_signals() abort + let s:signames = {} + let xs = s:libcall('vp_get_signals', []) + for x in xs + let [name, val] = split(x, ':') + let nr = str2nr(val) + let g:vimproc#{name} = nr + let s:signames[nr] = name + endfor +endfunction +" }}} + +let g:vimproc#dll_path = + \ vimproc#util#iconv( + \ vimproc#util#expand(g:vimproc#dll_path), + \ &encoding, vimproc#util#termencoding()) + +" Backward compatibility. +let g:vimproc_password_pattern = g:vimproc#password_pattern + +if g:vimproc#download_windows_dll && !filereadable(g:vimproc#dll_path) + \ && vimproc#util#is_windows() + call vimproc#util#try_download_windows_dll(s:VERSION_STRING) +endif + +if !filereadable(g:vimproc#dll_path) || !has('libcall') "{{{ + function! vimproc#get_last_status() abort + return v:shell_error + endfunction + + function! vimproc#get_last_errmsg() abort + return '' + endfunction + + function! vimproc#system(...) abort + return call('system', a:000) + endfunction + + if !filereadable(g:vimproc#dll_path) + call s:print_error(printf('vimproc''s DLL: "%s" is not found. + \ Please read :help vimproc and make it.', g:vimproc#dll_path)) + else + call s:print_error('libcall feature is disabled in this Vim. + \ To use vimproc, you must enable libcall feature.') + endif + + finish +endif"}}} + +function! vimproc#version() abort "{{{ + return s:VERSION_NUMBER +endfunction"}}} +function! vimproc#dll_version() abort "{{{ + let [dll_version] = s:libcall('vp_dlversion', []) + return str2nr(dll_version) +endfunction"}}} + +"----------------------------------------------------------- +" API + +function! vimproc#open(filename) abort "{{{ + let filename = vimproc#util#iconv(fnamemodify(a:filename, ':p'), + \ &encoding, vimproc#util#systemencoding()) + + if filename =~ '^\%(https\?\|ftp\)://' + \ && !vimproc#host_exists(filename) + " URI is invalid. + call s:print_error('vimproc#open: URI "' . filename . '" is invalid.') + return + endif + + " Detect desktop environment. + if vimproc#util#is_windows() + " For URI only. + "execute '!start rundll32 url.dll,FileProtocolHandler' filename + + call s:libcall('vp_open', [filename]) + elseif has('win32unix') + " Cygwin. + call vimproc#system(['cygstart', filename]) + elseif executable('xdg-open') + " Linux. + call vimproc#system_bg(['xdg-open', filename]) + elseif exists('$KDE_FULL_SESSION') && $KDE_FULL_SESSION ==# 'true' + " KDE. + call vimproc#system_bg(['kioclient', 'exec', filename]) + elseif exists('$GNOME_DESKTOP_SESSION_ID') + " GNOME. + call vimproc#system_bg(['gnome-open', filename]) + elseif executable('exo-open') + " Xfce. + call vimproc#system_bg(['exo-open', filename]) + elseif vimproc#util#is_mac() && executable('open') + " Mac OS. + call vimproc#system_bg(['open', filename]) + else + " Give up. + call s:print_error('vimproc#open: Not supported.') + endif +endfunction"}}} + +function! vimproc#get_command_name(command, ...) abort "{{{ + let path = get(a:000, 0, $PATH) + + let cnt = a:0 < 2 ? 1 : a:2 + + let files = split(substitute(vimproc#util#substitute_path_separator( + \ vimproc#filepath#which(a:command, path, cnt)), '//', '/', 'g'), '\n') + + if cnt < 0 + return files + endif + + let file = get(files, cnt-1, '') + + if file == '' + throw printf( + \ 'vimproc#get_command_name: File "%s" is not found.', a:command) + endif + + return file +endfunction"}}} + +function! s:system(cmdline, is_passwd, input, timeout, is_pty) abort "{{{ + let s:last_status = 0 + let s:last_errmsg = '' + + if empty(a:cmdline) + return '' + endif + + " Open pipe. + try + let subproc = (type(a:cmdline[0]) == type('')) ? vimproc#popen3(a:cmdline) : + \ a:is_pty ? vimproc#ptyopen(a:cmdline): + \ vimproc#pgroup_open(a:cmdline) + catch + call s:print_error(v:exception) + let s:last_status = 1 + let s:last_errmsg = v:exception + return '' + endtry + + let outbuf = [] + let errbuf = [] + + try + if a:input != '' + " Write input. + call subproc.stdin.write(a:input) + endif + + if a:timeout > 0 && has('reltime') && v:version >= 702 + let start = reltime() + let deadline = a:timeout + let timeout = a:timeout / 2 + else + let start = 0 + let deadline = 0 + let timeout = s:read_timeout + endif + + if !a:is_passwd + call subproc.stdin.close() + endif + + while !subproc.stdout.eof || !subproc.stderr.eof + if deadline "{{{ + " Check timeout. + let tick = reltimestr(reltime(start)) + let elapse = str2nr(tick[:-8] . tick[-6:-4], 10) + if deadline <= elapse && !subproc.stdout.eof + " Kill process. + throw 'vimproc: vimproc#system(): Timeout.' + endif + let timeout = (deadline - elapse) / 2 + endif"}}} + + if !subproc.stdout.eof "{{{ + let out = subproc.stdout.read(-1, timeout) + + if a:is_passwd && out =~# g:vimproc_password_pattern + redraw + echo out + + " Password input. + set imsearch=0 + let in = vimproc#util#iconv(inputsecret('Input Secret : ')."\", + \ &encoding, vimproc#util#termencoding()) + + call subproc.stdin.write(in) + else + let outbuf += [out] + endif + endif"}}} + + if !subproc.stderr.eof "{{{ + let out = subproc.stderr.read(-1, timeout) + + if a:is_passwd && out =~# g:vimproc_password_pattern + redraw + echo out + + " Password input. + set imsearch=0 + let in = vimproc#util#iconv(inputsecret('Input Secret : ') . "\", + \ &encoding, vimproc#util#termencoding()) + + call subproc.stdin.write(in) + else + let outbuf += [out] + let errbuf += [out] + endif + endif"}}} + endwhile + catch + call subproc.kill(g:vimproc#SIGTERM) + + if v:exception !~ '^Vim:Interrupt' + call s:print_error(v:throwpoint) + call s:print_error(v:exception) + endif + finally + let output = join(outbuf, '') + let s:last_errmsg = join(errbuf, '') + + call subproc.waitpid() + endtry + + " Newline convert. + if vimproc#util#is_mac() + let output = substitute(output, '\r\n\@!', '\n', 'g') + elseif has('win32') || has('win64') + let output = substitute(output, '\r\n', '\n', 'g') + endif + + return output +endfunction"}}} +function! vimproc#system(cmdline, ...) abort "{{{ + if type(a:cmdline) == type('') + if a:cmdline =~ '&\s*$' + let cmdline = substitute(a:cmdline, '&\s*$', '', '') + return vimproc#system_bg(cmdline) + endif + + let args = vimproc#parser#parse_statements(a:cmdline) + for arg in args + let arg.statement = vimproc#parser#parse_pipe(arg.statement) + endfor + else + let args = [{ + \ 'statement' : [ { + \ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' }, + \ 'args' : a:cmdline + \ }], + \ 'condition' : 'always', + \ 'cwd' : getcwd(), + \ }] + endif + + let timeout = get(a:000, 1, 0) + let input = get(a:000, 0, '') + + return s:system(args, 0, input, timeout, 0) +endfunction"}}} +function! vimproc#system2(...) abort "{{{ + if empty(a:000) + return '' + endif + + if len(a:0) > 1 + let args = deepcopy(a:000) + let args[1] = vimproc#util#iconv( + \ args[1], &encoding, vimproc#util#stdinencoding()) + else + let args = a:000 + endif + let output = call('vimproc#system', args) + + " This function converts application encoding to &encoding. + let output = vimproc#util#iconv( + \ output, vimproc#util#stdoutencoding(), &encoding) + let s:last_errmsg = vimproc#util#iconv( + \ s:last_errmsg, vimproc#util#stderrencoding(), &encoding) + + return output +endfunction"}}} +function! vimproc#system_passwd(cmdline, ...) abort "{{{ + if type(a:cmdline) == type('') + let args = vimproc#parser#parse_pipe(a:cmdline) + else + let args = [{ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' }, + \ 'args' : a:cmdline }] + endif + + let timeout = a:0 >= 2 ? a:2 : 0 + let input = a:0 >= 1 ? a:1 : '' + + let lang_save = $LANG + try + let $LANG = 'C' + + return s:system(args, 1, input, timeout, 1) + finally + let $LANG = lang_save + endtry +endfunction"}}} +function! vimproc#system_bg(cmdline) abort "{{{ + " Open pipe. + if type(a:cmdline) == type('') + if a:cmdline =~ '&\s*$' + let cmdline = substitute(a:cmdline, '&\s*$', '', '') + return vimproc#system_bg(cmdline) + endif + + let args = vimproc#parser#parse_statements(a:cmdline) + for arg in args + let arg.statement = vimproc#parser#parse_pipe(arg.statement) + endfor + else + let args = [{ + \ 'statement' : [ { + \ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' }, + \ 'args' : a:cmdline + \ }], + \ 'condition' : 'always', + \ 'cwd' : getcwd(), + \ }] + endif + + let subproc = vimproc#pgroup_open(args) + if empty(subproc) + " Not supported path error. + return '' + endif + + " Close handles. + call s:close_all(subproc) + + let s:bg_processes[subproc.pid] = subproc.pid + + return '' +endfunction"}}} +function! vimproc#system_gui(cmdline) abort "{{{ + return vimproc#system_bg(a:cmdline) +endfunction"}}} + +function! vimproc#get_last_status() abort "{{{ + return s:last_status +endfunction"}}} +function! vimproc#get_last_errmsg() abort "{{{ + return substitute(vimproc#util#iconv(s:last_errmsg, + \ vimproc#util#stderrencoding(), &encoding), '\n$', '', '') +endfunction"}}} + +function! vimproc#shellescape(string) abort "{{{ + return string(a:string) +endfunction"}}} + +function! vimproc#fopen(path, ...) abort "{{{ + let flags = get(a:000, 0, 'r') + let mode = get(a:000, 1, 0644) + let fd = s:vp_file_open((s:is_null_device(a:path) + \ ? s:null_device : a:path), flags, mode) + let proc = s:fdopen(fd, 'vp_file_close', 'vp_file_read', 'vp_file_write') + return proc +endfunction"}}} + +function! vimproc#popen2(args, ...) abort "{{{ + let args = type(a:args) == type('') ? + \ vimproc#parser#split_args(a:args) : + \ a:args + let is_pty = get(a:000, 0, 0) + + return s:plineopen(2, [{ + \ 'args' : args, + \ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' }, + \ }], is_pty) +endfunction"}}} +function! vimproc#popen3(args, ...) abort "{{{ + let args = type(a:args) == type('') ? + \ vimproc#parser#split_args(a:args) : + \ a:args + let is_pty = get(a:000, 0, 0) + + return s:plineopen(3, [{ + \ 'args' : args, + \ 'fd' : { 'stdin' : '', 'stdout' : '', 'stderr' : '' }, + \ }], is_pty) +endfunction"}}} + +function! vimproc#plineopen2(commands, ...) abort "{{{ + let commands = type(a:commands) == type('') ? + \ vimproc#parser#parse_pipe(a:commands) : + \ a:commands + let is_pty = get(a:000, 0, 0) + + return s:plineopen(2, commands, is_pty) +endfunction"}}} +function! vimproc#plineopen3(commands, ...) abort "{{{ + let commands = type(a:commands) == type('') ? + \ vimproc#parser#parse_pipe(a:commands) : + \ a:commands + let is_pty = get(a:000, 0, 0) + + return s:plineopen(3, commands, is_pty) +endfunction"}}} +function! s:plineopen(npipe, commands, is_pty) abort "{{{ + let pid_list = [] + let stdin_list = [] + let stdout_list = [] + let stderr_list = [] + let npipe = a:npipe + + " Open input. + let hstdin = (empty(a:commands) || a:commands[0].fd.stdin == '')? + \ 0 : vimproc#fopen(a:commands[0].fd.stdin, 'r').fd + + let is_pty = !vimproc#util#is_windows() && a:is_pty + + let cnt = 0 + for command in a:commands + if is_pty && command.fd.stdout == '' && cnt == 0 + \ && len(a:commands) != 1 + " pty_open() use pipe. + let hstdout = 1 + else + if command.fd.stdout =~ '^>' + let mode = 'a' + let command.fd.stdout = command.fd.stdout[1:] + else + let mode = 'w' + endif + + let hstdout = s:is_pseudo_device(command.fd.stdout) ? + \ 0 : vimproc#fopen(command.fd.stdout, mode).fd + endif + + if is_pty && command.fd.stderr == '' && cnt == 0 + \ && len(a:commands) != 1 + " pty_open() use pipe. + let hstderr = 1 + else + if command.fd.stderr =~ '^>' + let mode = 'a' + let command.fd.stderr = command.fd.stderr[1:] + else + let mode = 'w' + endif + let hstderr = s:is_pseudo_device(command.fd.stderr) ? + \ 0 : vimproc#fopen(command.fd.stderr, mode).fd + endif + + if command.fd.stderr ==# '/dev/stdout' + let npipe = 2 + endif + + let args = s:convert_args(command.args) + let command_name = fnamemodify(args[0], ':t:r') + let pty_npipe = cnt == 0 + \ && hstdin == 0 && hstdout == 0 && hstderr == 0 + \ && exists('g:vimproc#popen2_commands') + \ && get(g:vimproc#popen2_commands, command_name, 0) != 0 ? + \ 2 : npipe + + if is_pty && (cnt == 0 || cnt == len(a:commands)-1) + " Use pty_open(). + let pipe = s:vp_pty_open(pty_npipe, + \ s:get_winwidth(), winheight(0), + \ hstdin, hstdout, hstderr, args) + else + let pipe = s:vp_pipe_open(pty_npipe, + \ hstdin, hstdout, hstderr, args) + endif + + if len(pipe) == 4 + let [pid, fd_stdin, fd_stdout, fd_stderr] = pipe + let stderr = s:fdopen(fd_stderr, + \ 'vp_pipe_close', 'vp_pipe_read', 'vp_pipe_write') + else + let [pid, fd_stdin, fd_stdout] = pipe + let stderr = s:closed_fdopen( + \ 'vp_pipe_close', 'vp_pipe_read', 'vp_pipe_write') + endif + + call add(pid_list, pid) + let stdin = s:fdopen(fd_stdin, + \ 'vp_pipe_close', 'vp_pipe_read', 'vp_pipe_write') + let stdin.is_pty = is_pty + \ && (cnt == 0 || cnt == len(a:commands)-1) + \ && hstdin == 0 + call add(stdin_list, stdin) + let stdout = s:fdopen(fd_stdout, + \ 'vp_pipe_close', 'vp_pipe_read', 'vp_pipe_write') + let stdout.is_pty = is_pty + \ && (cnt == 0 || cnt == len(a:commands)-1) + \ && hstdout == 0 + call add(stdout_list, stdout) + let stderr.is_pty = is_pty + \ && (cnt == 0 || cnt == len(a:commands)-1) + \ && hstderr == 0 + call add(stderr_list, stderr) + + let hstdin = stdout_list[-1].fd + let cnt += 1 + endfor + + let proc = {} + let proc.pid_list = pid_list + let proc.pid = pid_list[-1] + let proc.stdin = s:fdopen_pipes(stdin_list, + \ 'vp_pipes_close', 'read_pipes', 'write_pipes') + let proc.stdout = s:fdopen_pipes(stdout_list, + \ 'vp_pipes_close', 'read_pipes', 'write_pipes') + let proc.stderr = s:fdopen_pipes(stderr_list, + \ 'vp_pipes_close', 'read_pipes', 'write_pipes') + let proc.get_winsize = s:funcref('vp_get_winsize') + let proc.set_winsize = s:funcref('vp_set_winsize') + let proc.kill = s:funcref('vp_kill') + let proc.waitpid = s:funcref('vp_waitpid') + let proc.checkpid = s:funcref('vp_checkpid') + let proc.is_valid = 1 + let proc.is_pty = is_pty + if a:is_pty + let proc.ttyname = '' + let proc.width = winwidth(0) - &l:numberwidth - &l:foldcolumn + let proc.height = winheight(0) + let proc.get_winsize = s:funcref('vp_get_winsize') + let proc.set_winsize = s:funcref('vp_set_winsize') + endif + + return proc +endfunction"}}} + +let s:null_device = vimproc#util#is_windows() ? 'NUL' : '/dev/null' + +function! s:is_null_device(filename) abort + return a:filename ==# '/dev/null' +endfunction + +function! s:is_pseudo_device(filename) abort "{{{ + if vimproc#util#is_windows() && ( + \ a:filename ==# '/dev/stdin' + \ || a:filename ==# '/dev/stdout' + \ || a:filename ==# '/dev/stderr') + return 1 + endif + + return a:filename == '' + \ || a:filename ==# '/dev/clip' + \ || a:filename ==# '/dev/quickfix' +endfunction"}}} + +function! vimproc#pgroup_open(statements, ...) abort "{{{ + if type(a:statements) == type('') + let statements = + \ vimproc#parser#parse_statements(a:statements) + for statement in statements + let statement.statement = + \ vimproc#parser#parse_pipe(statement.statement) + endfor + else + let statements = a:statements + endif + + let is_pty = get(a:000, 0, 0) + let npipe = get(a:000, 1, 3) + + return s:pgroup_open(statements, is_pty && !vimproc#util#is_windows(), npipe) +endfunction"}}} + +function! s:pgroup_open(statements, is_pty, npipe) abort "{{{ + let proc = {} + + let cwd = getcwd() + try + call vimproc#util#cd(a:statements[0].cwd) + + let proc.current_proc = + \ vimproc#plineopen{a:npipe}(a:statements[0].statement, a:is_pty) + finally + call vimproc#util#cd(cwd) + endtry + + let proc.pid = proc.current_proc.pid + let proc.pid_list = proc.current_proc.pid_list + let proc.condition = a:statements[0].condition + let proc.statements = a:statements[1:] + let proc.stdin = s:fdopen_pgroup(proc, proc.current_proc.stdin, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + let proc.stdout = s:fdopen_pgroup(proc, proc.current_proc.stdout, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + let proc.stderr = s:fdopen_pgroup(proc, proc.current_proc.stderr, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + let proc.kill = s:funcref('vp_pgroup_kill') + let proc.waitpid = s:funcref('vp_pgroup_waitpid') + let proc.is_valid = 1 + let proc.is_pty = 0 + " echomsg expand('') + " echomsg 'open:' string(map(copy(proc.current_proc.stdin.fd), 'v:val.fd')) + " echomsg 'open:' string(map(copy(proc.current_proc.stdout.fd), 'v:val.fd')) + " echomsg 'open:' string(map(copy(proc.current_proc.stderr.fd), 'v:val.fd')) + + return proc +endfunction"}}} + +function! vimproc#ptyopen(commands, ...) abort "{{{ + let commands = type(a:commands) == type('') ? + \ vimproc#parser#parse_pipe(a:commands) : + \ a:commands + let npipe = get(a:000, 0, 3) + + return s:plineopen(npipe, commands, !vimproc#util#is_windows()) +endfunction"}}} + +function! vimproc#socket_open(host, port) abort "{{{ + if !vimproc#host_exists(a:host) + throw printf('vimproc: host "%s" does not exist', a:host) + endif + + let fd = s:vp_socket_open(a:host, a:port) + return s:fdopen(fd, 'vp_socket_close', 'vp_socket_read', 'vp_socket_write') +endfunction"}}} + +function! vimproc#host_exists(host) abort "{{{ + let rval = s:vp_host_exists( + \ substitute(substitute(a:host, '^\a\+://', '', ''), '/.*$', '', '')) + return 0 + rval +endfunction"}}} + +function! vimproc#kill(pid, sig) abort "{{{ + if a:sig == 0 && vimproc#util#is_windows() + " Use waitpid(). + let cond = s:waitpid(a:pid, 1)[0] + if cond ==# 'error' + let s:last_errmsg = 'waitpid error' + endif + return cond !=# 'run' + endif + + try + let [ret] = s:libcall('vp_kill', [a:pid, a:sig]) + catch + let s:last_errmsg = v:exception + return 1 + endtry + + return ret +endfunction"}}} + +function! vimproc#decode_signal(signal) abort "{{{ + return get(s:signames, a:signal, 'UNKNOWN') +endfunction"}}} + +function! vimproc#write(filename, string, ...) abort "{{{ + if a:string == '' + return + endif + + let mode = get(a:000, 0, + \ a:filename =~ '^>' ? 'a' : 'w') + + let filename = a:filename =~ '^>' ? + \ a:filename[1:] : a:filename + + if s:is_null_device(filename) + " Nothing. + elseif filename ==# '/dev/clip' + " Write to clipboard. + + if mode =~ 'a' + let @+ .= a:string + else + let @+ = a:string + endif + elseif filename ==# '/dev/quickfix' + " Write to quickfix. + let qflist = getqflist() + + for str in split(a:string, '\n\|\r\n') + if str =~ '^.\+:.\+:.\+$' + let line = split(str[2:], ':') + let filename = str[:1] . line[0] + + if len(line) >= 3 && line[1] =~ '^\d\+$' + call add(qflist, { + \ 'filename' : filename, + \ 'lnum' : line[1], + \ 'text' : join(line[2:], ':'), + \ }) + else + call add(qflist, { + \ 'text' : str, + \ }) + endif + endif + endfor + + call setqflist(qflist) + else + " Write file. + let hfile = vimproc#fopen(filename, mode) + call hfile.write(a:string) + call hfile.close() + endif +endfunction"}}} + +function! vimproc#readdir(dirname) abort "{{{ + let dirname = vimproc#util#expand(a:dirname) + if dirname == '' + let dirname = getcwd() + endif + let dirname = substitute(dirname, '.\zs/$', '', '') + + if !vimproc#util#is_windows() + let dirname = substitute(dirname, '//', '/', 'g') + endif + + if !isdirectory(dirname) + return [] + endif + + let dirname = vimproc#util#iconv(dirname, &encoding, + \ vimproc#util#systemencoding()) + + try + let files = s:libcall('vp_readdir', [dirname]) + catch /vp_readdir/ + return [] + endtry + + call map(filter(files, 'v:val !~ "/\\.\\.\\?$"'), 'vimproc#util#iconv( + \ v:val, vimproc#util#systemencoding(), &encoding)') + if vimproc#util#is_windows() + call map(files, 'vimproc#util#substitute_path_separator(v:val)') + endif + call map(files, "substitute(v:val, '/\\./', '/', 'g')") + + return files +endfunction"}}} + +function! vimproc#delete_trash(filename) abort "{{{ + if !vimproc#util#is_windows() + call s:print_error('Not implemented in this platform.') + return + endif + + let filename = a:filename + + if !filewritable(filename) && !isdirectory(filename) + return 1 + endif + + " Substitute path separator to "/". + let filename = substitute( + \ fnamemodify(filename, ':p'), '/', '\\', 'g') + + " Delete last /. + if filename =~ '[^:][/\\]$' + " Delete last /. + let filename = filename[: -2] + endif + + " Encoding conversion. + let filename = vimproc#util#iconv(filename, + \ &encoding, vimproc#util#systemencoding()) + + let [ret] = s:libcall('vp_delete_trash', [filename]) + + return str2nr(ret) +endfunction"}}} + +function! vimproc#test_readdir(dirname) abort "{{{ + let start = reltime() + call split(glob(a:dirname.'/*'), '\n') + echomsg reltimestr(reltime(start)) + + let start = reltime() + call vimproc#readdir(a:dirname) + echomsg reltimestr(reltime(start)) +endfunction"}}} + +function! s:close_all(self) abort "{{{ + if has_key(a:self, 'stdin') + call a:self.stdin.close() + endif + if has_key(a:self, 'stdout') + call a:self.stdout.close() + endif + if has_key(a:self, 'stderr') + call a:self.stderr.close() + endif +endfunction"}}} +function! s:close() dict "{{{ + if self.is_valid + call self.f_close() + endif + + let self.is_valid = 0 + let self.eof = 1 + let self.__eof = 1 +endfunction"}}} +function! s:read(...) dict "{{{ + if self.__eof + let self.eof = 1 + return '' + endif + + let maxsize = get(a:000, 0, -1) + let timeout = get(a:000, 1, s:read_timeout) + let buf = [] + let eof = 0 + + while maxsize != 0 && !eof + let [out, eof] = self.f_read(maxsize, + \ (timeout < s:read_timeout ? timeout : s:read_timeout)) + if out ==# '' + let timeout -= s:read_timeout + if timeout <= 0 + break + endif + else + let buf += [out] + let maxsize -= len(out) + let timeout = 0 + endif + endwhile + + let self.eof = eof + let self.__eof = eof + + return join(buf, '') +endfunction"}}} +function! s:read_lines(...) dict "{{{ + if self.__eof + return [] + endif + + let lines = self.buffer[:-2] + let res = get(self.buffer, -1, '') + + let out = call(self.read, a:000, self) + if out !=# '' + let outs = split(out, '\r*\n\|\r', 1) + let res .= outs[0] + if len(outs) > 1 + let lines += [substitute(res, '\r*$', '', '')] + outs[1:-2] + let res = outs[-1] + endif + endif + + if self.__eof || out ==# '' + if res !=# '' + let lines += [res] + endif + let self.buffer = [] + else + let self.buffer = [res] + endif + + return lines +endfunction"}}} +function! s:read_line(...) dict "{{{ + let line = '' + if !self.__eof && len(self.buffer) <= 1 + let lines = call(self.read_lines, a:000, self) + let self.buffer = lines[1:] + self.buffer + let line = get(lines, 0, '') + elseif !empty(self.buffer) + let [line; self.buffer] = self.buffer + endif + let self.eof = self.__eof && empty(self.buffer) + return line +endfunction"}}} + +function! s:write(str, ...) dict "{{{ + let timeout = get(a:000, 0, s:write_timeout) + return self.f_write(a:str, timeout) +endfunction"}}} + +function! s:fdopen(fd, f_close, f_read, f_write) abort "{{{ + return { + \ 'fd' : a:fd, + \ 'eof' : 0, '__eof' : 0, 'is_valid' : 1, 'buffer' : [], + \ 'f_close' : s:funcref(a:f_close), 'f_read' : s:funcref(a:f_read), 'f_write' : s:funcref(a:f_write), + \ 'close' : s:funcref('close'), 'read' : s:funcref('read'), 'write' : s:funcref('write'), + \ 'read_line' : s:funcref('read_line'), 'read_lines' : s:funcref('read_lines'), + \} +endfunction"}}} +function! s:closed_fdopen(f_close, f_read, f_write) abort "{{{ + return { + \ 'fd' : -1, + \ 'eof' : 1, '__eof' : 1, 'is_valid' : 0, 'buffer' : [], + \ 'f_close' : s:funcref(a:f_close), 'f_read' : s:funcref(a:f_read), 'f_write' : s:funcref(a:f_write), + \ 'close' : s:funcref('close'), 'read' : s:funcref('read'), 'write' : s:funcref('write'), + \ 'read_line' : s:funcref('read_line'), 'read_lines' : s:funcref('read_lines'), + \} +endfunction"}}} +function! s:fdopen_pty(fd_stdin, fd_stdout, f_close, f_read, f_write) abort "{{{ + return { + \ 'eof' : 0, '__eof' : 0, 'is_valid' : 1, 'buffer' : [], + \ 'fd_stdin' : a:fd_stdin, 'fd_stdout' : a:fd_stdout, + \ 'f_close' : s:funcref(a:f_close), 'f_read' : s:funcref(a:f_read), 'f_write' : s:funcref(a:f_write), + \ 'close' : s:funcref('close'), 'read' : s:funcref('read'), 'write' : s:funcref('write'), + \ 'read_line' : s:funcref('read_line'), 'read_lines' : s:funcref('read_lines'), + \} +endfunction"}}} +function! s:fdopen_pipes(fd, f_close, f_read, f_write) abort "{{{ + return { + \ 'eof' : 0, '__eof' : 0, 'is_valid' : 1, 'buffer' : [], + \ 'fd' : a:fd, + \ 'f_close' : s:funcref(a:f_close), + \ 'close' : s:funcref('close'), 'read' : s:funcref(a:f_read), 'write' : s:funcref(a:f_write), + \ 'read_line' : s:funcref('read_line'), 'read_lines' : s:funcref('read_lines'), + \} +endfunction"}}} +function! s:fdopen_pgroup(proc, fd, f_close, f_read, f_write) abort "{{{ + return { + \ 'eof' : 0, '__eof' : 0, 'is_valid' : 1, 'buffer' : [], + \ 'proc' : a:proc, 'fd' : a:fd, + \ 'f_close' : s:funcref(a:f_close), + \ 'close' : s:funcref('close'), 'read' : s:funcref(a:f_read), 'write' : s:funcref(a:f_write), + \ 'read_line' : s:funcref('read_line'), 'read_lines' : s:funcref('read_lines'), + \} +endfunction"}}} + +function! s:garbage_collect(is_force) abort "{{{ + for pid in values(s:bg_processes) + " Check processes. + try + let [cond, _] = s:libcall('vp_waitpid', [pid]) + " echomsg string([pid, cond, _]) + if cond !=# 'run' || a:is_force + if cond !=# 'exit' + " Kill process. + call vimproc#kill(pid, g:vimproc#SIGTERM) + endif + + if vimproc#util#is_windows() + call s:libcall('vp_close_handle', [pid]) + endif + call remove(s:bg_processes, pid) + endif + catch + " Ignore error. + endtry + endfor +endfunction"}}} + +" For debug API. +function! vimproc#_get_bg_processes() abort "{{{ + return s:bg_processes +endfunction"}}} + +"----------------------------------------------------------- +" UTILS + +function! s:str2hd(str) abort + return join(map(range(len(a:str)), + \ 'printf("%02X", char2nr(a:str[v:val]))'), '') +endfunction + +function! s:hd2str(hd) abort + " a:hd is a list because to avoid copying the value. + return get(s:libcall('vp_decode', [a:hd[0]]), 0, '') +endfunction + +function! s:hd2str_lua(hd) abort + let ret = [] + lua << EOF +do + local ret = vim.eval('ret') + local hd = vim.eval('a:hd[0]') + local len = string.len(hd) + local s = {} + for i = 1, len, 2 do + table.insert(s, string.char(tonumber(string.sub(hd, i, i+1), 16))) + end + + ret:add(table.concat(s)) +end +EOF + return ret[0] +endfunction + +function! s:str2list(str) abort + return map(range(len(a:str)), 'char2nr(a:str[v:val])') +endfunction + +function! s:list2str(lis) abort + return s:hd2str(s:list2hd([a:lis])) +endfunction + +function! s:hd2list(hd) abort + return map(split(a:hd, '..\zs'), 'str2nr(v:val, 16)') +endfunction + +function! s:list2hd(lis) abort + return join(map(a:lis, 'printf("%02X", v:val)'), '') +endfunction + +function! s:convert_args(args) abort "{{{ + if empty(a:args) + return [] + endif + + let args = map(copy(a:args), 'vimproc#util#iconv( + \ v:val, &encoding, vimproc#util#systemencoding())') + + if vimproc#util#is_windows() && !executable(a:args[0]) + " Search from internal commands. + let internal_commands = [ + \ 'copy', 'date', 'del', 'dir', 'echo', 'erase', 'for', 'ftype', + \ 'if', 'md', 'mkdir', 'move', 'path', 'rd', 'ren', 'rename', + \ 'rmdir', 'start', 'time', 'type', 'ver', 'vol'] + let index = index(internal_commands, a:args[0], 0, 1) + if index >= 0 + " Use cmd.exe + return ['cmd', '/c', args[0]] + args[1:] + endif + endif + + let command_name = vimproc#get_command_name(a:args[0]) + + return map(vimproc#analyze_shebang(command_name), 'vimproc#util#iconv( + \ v:val, &encoding, vimproc#util#systemencoding())') + args[1:] +endfunction"}}} + +function! vimproc#analyze_shebang(filename) abort "{{{ + if !filereadable(a:filename) || + \ getfsize(a:filename) > 100000 || + \ (vimproc#util#is_windows() && + \ '.'.fnamemodify(a:filename, ':e') !~? + \ '^'.substitute($PATHEXT, ';', '$\\|^', 'g').'$') + " Maybe a binary file. + return [a:filename] + endif + + let lines = readfile(a:filename, '', 1) + if empty(lines) || lines[0] !~ '^#!.\+' + " Shebang not found. + return [a:filename] + endif + + " Get shebang line. + let shebang = split(matchstr(lines[0], '^#!\zs.\+')) + + " Convert command name. + if vimproc#util#is_windows() + \ && shebang[0] =~ '^/' + let shebang[0] = vimproc#get_command_name( + \ fnamemodify(shebang[0], ':t')) + endif + + return shebang + [a:filename] +endfunction"}}} + +"----------------------------------------------------------- +" LOW LEVEL API + +augroup vimproc + autocmd VimLeave * call s:finalize() + autocmd CursorHold,BufWritePost * call s:garbage_collect(0) +augroup END + +" Initialize. +let s:lasterr = [] +let s:read_timeout = 100 +let s:write_timeout = 100 +let s:bg_processes = {} + +if vimproc#util#has_lua() + function! s:split(str, sep) abort + let result = [] + lua << EOF + do + local result = vim.eval('result') + local str = vim.eval('a:str') + local sep = vim.eval('a:sep') + local last + + if string.find(str, sep, 1, true) == nil then + result:add(str) + else + for part, pos in string.gmatch(str, + '(.-)' .. sep .. '()') do + result:add(part) + last = pos + end + + result:add(string.sub(str, last)) + end + end +EOF + + return result + endfunction +else + function! s:split(str, sep) abort + let [result, pos] = [[], 0] + while 1 + let tmp = stridx(a:str, a:sep, pos) + if tmp == -1 + call add(result, strpart(a:str, pos)) + break + endif + call add(result, strpart(a:str, pos, tmp - pos)) + let pos = tmp + 1 + endwhile + + return result + endfunction +endif + +" Encode a 32-bit integer into a 5-byte string. +function! s:encode_size(n) abort + " Set each bit7 to 1 in order to avoid NUL byte. + return printf("%c%c%c%c%c", + \ ((a:n / 0x10000000) % 0x80) + 0x80, + \ ((a:n / 0x200000) % 0x80) + 0x80, + \ ((a:n / 0x4000) % 0x80) + 0x80, + \ ((a:n / 0x80) % 0x80) + 0x80, + \ ( a:n % 0x80) + 0x80) +endfunction + +" Decode a 32-bit integer from a 5-byte string. +function! s:decode_size(str, off) abort + return + \ (char2nr(a:str[a:off + 0]) - 0x80) * 0x10000000 + + \ (char2nr(a:str[a:off + 1]) - 0x80) * 0x200000 + + \ (char2nr(a:str[a:off + 2]) - 0x80) * 0x4000 + + \ (char2nr(a:str[a:off + 3]) - 0x80) * 0x80 + + \ (char2nr(a:str[a:off + 4]) - 0x80) +endfunction + +" Encode a list into a string. +function! s:encode_list(arr) abort + " End Of Value + let EOV = "\xFF" + " EOV, encoded size0, data0, EOV, encoded size1, data1, EOV, ... + return empty(a:arr) ? '' : + \ (EOV . join(map(copy(a:arr), 's:encode_size(strlen(v:val)) . v:val'), EOV) . EOV) +endfunction + +" Decode a list from a string. +function! s:decode_list(str) abort + let err = 0 + " End Of Value + let EOV = "\xFF" + if a:str[0] != EOV + let err = 1 + return [[a:str], err] + endif + let arr = [] + let slen = strlen(a:str) + let off = 1 + while slen - off >= 5 + let size = s:decode_size(a:str, off) + let arr += [a:str[off + 5 : off + 5 + size - 1]] + let off += 5 + size + 1 + endwhile + return [arr, err] +endfunction + +function! s:libcall(func, args) abort "{{{ + let stack_buf = libcall(g:vimproc#dll_path, a:func, s:encode_list(a:args)) + if empty(stack_buf) + return [] + endif + let [result, err] = s:decode_list(stack_buf) + if err + let s:lasterr = result + let msg = vimproc#util#iconv(string(result), + \ vimproc#util#systemencoding(), &encoding) + + throw printf('vimproc: %s: %s', a:func, msg) + endif + return result +endfunction"}}} + +" args[0]: fd, args[1]: count, args[2]: timeout +function! s:libcall_raw_read(func, args) abort "{{{ + let [err, hd] = s:libcall(a:func, a:args) + return [hd, err] +endfunction "}}} + +" args[0]: fd, args[1]: data, args[2]: timeout +function! s:libcall_raw_write(func, args) abort "{{{ + return s:libcall(a:func, [a:args[0], a:args[2], a:args[1]]) +endfunction "}}} + +function! s:SID_PREFIX() abort + if !exists('s:sid_prefix') + let s:sid_prefix = matchstr(expand(''), + \ '\d\+_\zeSID_PREFIX$') + endif + return s:sid_prefix +endfunction + +" Get funcref. +function! s:funcref(funcname) abort + return function(s:SID_PREFIX().a:funcname) +endfunction + +function! s:finalize() abort + call s:garbage_collect(1) + + if exists('s:dll_handle') + call s:vp_dlclose(s:dll_handle) + endif +endfunction + +function! s:vp_dlopen(path) abort + let [handle] = s:libcall('vp_dlopen', [a:path]) + return handle +endfunction + +function! s:vp_dlclose(handle) abort + call s:libcall('vp_dlclose', [a:handle]) +endfunction + +function! s:vp_file_open(path, flags, mode) abort + let [fd] = s:libcall('vp_file_open', [a:path, a:flags, a:mode]) + return fd +endfunction + +function! s:vp_file_close() dict + if self.fd != 0 + call s:libcall('vp_file_close', [self.fd]) + let self.fd = 0 + endif +endfunction + +function! s:vp_file_read(number, timeout) dict + let [hd, eof] = s:libcall_raw_read('vp_file_read', [self.fd, a:number, a:timeout]) + return [hd, eof] +endfunction + +function! s:vp_file_write(hd, timeout) dict + let [nleft] = s:libcall_raw_write('vp_file_write', [self.fd, a:hd, a:timeout]) + return nleft +endfunction + +function! s:quote_arg(arg) abort + return (a:arg == '' || a:arg =~ '[ "]') ? + \ '"' . substitute(a:arg, '"', '\\"', 'g') . '"' : a:arg +endfunction + +function! s:vp_pipe_open(npipe, hstdin, hstdout, hstderr, argv) abort "{{{ + try + if vimproc#util#is_windows() + let cmdline = s:quote_arg(substitute(a:argv[0], '/', '\', 'g')) + for arg in a:argv[1:] + let cmdline .= ' ' . s:quote_arg(arg) + endfor + let [pid; fdlist] = s:libcall('vp_pipe_open', + \ [a:npipe, a:hstdin, a:hstdout, a:hstderr, cmdline]) + else + let [pid; fdlist] = s:libcall('vp_pipe_open', + \ [a:npipe, a:hstdin, a:hstdout, a:hstderr, len(a:argv)] + a:argv) + endif + catch + call s:print_error(v:throwpoint) + call s:print_error(v:exception) + call s:print_error( + \ 'Error occurred in calling s:vp_pipe_open()') + call s:print_error(printf( + \ 'a:argv = %s', string(a:argv))) + call s:print_error(printf( + \ 'original a:argv = %s', vimproc#util#iconv( + \ string(a:argv), vimproc#util#systemencoding(), &encoding))) + endtry + + if a:npipe != len(fdlist) + call s:print_error(printf( + \ 'a:npipe = %d, a:argv = %s', a:npipe, string(a:argv))) + call s:print_error(printf( + \ 'pid = %d, fdlist = %s', pid, string(fdlist))) + echoerr 'Bug behavior is detected!: ' . pid + endif + + return [pid] + fdlist +endfunction"}}} + +function! s:vp_pipe_close() dict + " echomsg 'close:'.self.fd + if self.fd != 0 + call s:libcall('vp_pipe_close', [self.fd]) + let self.fd = 0 + endif +endfunction + +function! s:vp_pipes_close() dict + for fd in self.fd + try + call fd.close() + catch /vimproc: vp_pipe_close: / + " Ignore error. + endtry + endfor +endfunction + +function! s:vp_pgroup_close() dict + call self.fd.close() +endfunction + +function! s:vp_pipe_read(number, timeout) dict + if self.fd == 0 + return ['', 1] + endif + + let [hd, eof] = s:libcall_raw_read('vp_pipe_read', [self.fd, a:number, a:timeout]) + return [hd, eof] +endfunction + +function! s:vp_pipe_write(hd, timeout) dict + if self.fd == 0 + return 0 + endif + + let [nleft] = s:libcall_raw_write('vp_pipe_write', [self.fd, a:hd, a:timeout]) + return nleft +endfunction + +function! s:read_pipes(...) dict "{{{ + if type(self.fd[-1]) != type({}) + let self.eof = 1 + return '' + endif + + let number = get(a:000, 0, -1) + let timeout = get(a:000, 1, s:read_timeout) + + let output = self.fd[-1].read(number, timeout) + let self.eof = self.fd[-1].eof + + return output +endfunction"}}} + +function! s:write_pipes(str, ...) dict "{{{ + let timeout = get(a:000, 0, s:write_timeout) + + if self.fd[0].eof + return 0 + endif + + " Write data. + let nleft = self.fd[0].write(a:str, timeout) + let self.eof = self.fd[0].eof + + return nleft +endfunction"}}} + +function! s:read_pgroup(...) dict "{{{ + let number = get(a:000, 0, -1) + let timeout = get(a:000, 1, s:read_timeout) + + let output = '' + + if !self.fd.eof + let output = self.fd.read(number, timeout) + endif + + if self.proc.current_proc.stdout.eof + \ && self.proc.current_proc.stderr.eof + " Get status. + let [cond, status] = self.proc.current_proc.waitpid() + + if empty(self.proc.statements) + \ || (self.proc.condition ==# 'true' && status) + \ || (self.proc.condition ==# 'false' && !status) + let self.proc.statements = [] + + " Caching status. + let self.proc.cond = cond + let self.proc.status = status + if has_key(self.proc.current_proc, 'pipe_status') + let self.proc.pipe_status = self.proc.current_proc.pipe_status + endif + else + " Initialize next statement. + + let cwd = getcwd() + try + call vimproc#util#cd(self.proc.statements[0].cwd) + + let proc = vimproc#plineopen3( + \ self.proc.statements[0].statement) + finally + call vimproc#util#cd(cwd) + endtry + let self.proc.current_proc = proc + + let self.pid = proc.pid + let self.pid_list = proc.pid_list + let self.proc.pid = proc.pid + let self.proc.pid_list = proc.pid_list + let self.proc.condition = self.proc.statements[0].condition + let self.proc.statements = self.proc.statements[1:] + + let self.proc.stdin = s:fdopen_pgroup( + \ self.proc, proc.stdin, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + let self.proc.stdout = s:fdopen_pgroup( + \ self.proc, proc.stdout, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + let self.proc.stderr = s:fdopen_pgroup( + \ self.proc, proc.stderr, + \ 'vp_pgroup_close', 'read_pgroup', 'write_pgroup') + endif + endif + + if self.proc.current_proc.stdout.eof + let self.proc.stdout.eof = 1 + let self.proc.stdout.__eof = 1 + endif + + if self.proc.current_proc.stderr.eof + let self.proc.stderr.eof = 1 + let self.proc.stderr.__eof = 1 + endif + + return output +endfunction"}}} + +function! s:write_pgroup(str, ...) dict "{{{ + let timeout = get(a:000, 0, s:write_timeout) + + let nleft = 0 + if !self.fd.eof + " Write data. + let nleft = self.fd.write(a:str, timeout) + endif + + return nleft +endfunction"}}} + +function! s:vp_pty_open(npipe, width, height, hstdin, hstdout, hstderr, argv) abort + let [pid; fdlist] = s:libcall('vp_pty_open', + \ [a:npipe, a:width, a:height, + \ a:hstdin, a:hstdout, a:hstderr, len(a:argv)] + a:argv) + return [pid] + fdlist +endfunction + +function! s:vp_pty_close() dict + call s:libcall('vp_pty_close', [self.fd]) +endfunction + +function! s:vp_pty_read(number, timeout) dict + let [hd, eof] = s:libcall_raw_read('vp_pty_read', [self.fd, a:number, a:timeout]) + return [hd, eof] +endfunction + +function! s:vp_pty_write(hd, timeout) dict + let [nleft] = s:libcall_raw_write('vp_pty_write', [self.fd, a:hd, a:timeout]) + return nleft +endfunction + +function! s:vp_get_winsize() dict + let [width, height] = [s:get_winwidth(), winheight(0)] + + if !vimproc#util#is_windows() + for pid in self.pid_list + let [width, height] = s:libcall('vp_pty_get_winsize', [pid]) + endfor + endif + + return [width, height] +endfunction + +function! s:vp_set_winsize(width, height) dict + if vimproc#util#is_windows() || !self.is_valid + \ || (abs(a:width - self.width) < 3 && abs(a:height - self.height) < 3) + \ || !self.is_pty + return + endif + + let self.width = a:width + let self.height = a:height + + try + if self.stdin.eof == 0 && self.stdin.fd[-1].is_pty + call s:libcall('vp_pty_set_winsize', + \ [self.stdin.fd[-1].fd, a:width-5, a:height]) + endif + if self.stdout.eof == 0 && self.stdout.fd[0].is_pty + call s:libcall('vp_pty_set_winsize', + \ [self.stdout.fd[0].fd, a:width-5, a:height]) + endif + if self.stderr.eof == 0 && self.stderr.fd[0].is_pty + call s:libcall('vp_pty_set_winsize', + \ [self.stderr.fd[0].fd, a:width-5, a:height]) + endif + catch + return + endtry + + " Send SIGWINCH = 28 signal. + for pid in self.pid_list + call vimproc#kill(pid, g:vimproc#SIGWINCH) + endfor +endfunction + +function! s:vp_kill(...) dict + let sig = get(a:000, 0, g:vimproc#SIGTERM) + if sig != 0 + call s:close_all(self) + let self.is_valid = 0 + endif + + let ret = 0 + for pid in get(self, 'pid_list', [self.pid]) + call s:waitpid(pid, 1) + let ret = vimproc#kill(pid, sig) + endfor + + return ret +endfunction + +function! s:vp_pgroup_kill(...) dict + let sig = get(a:000, 0, g:vimproc#SIGTERM) + if sig != 0 + call s:close_all(self) + let self.is_valid = 0 + endif + + if self.pid == 0 + " Ignore. + return + endif + + return self.current_proc.kill(sig) +endfunction + +function! s:waitpid(pid, ...) abort + let nohang = a:0 ? a:1 : 0 + try + while 1 + let [cond, status] = s:libcall('vp_waitpid', [a:pid]) + " echomsg string([a:pid, cond, status]) + if cond !=# 'run' || nohang + break + endif + endwhile + + if cond ==# 'run' + " Add process list. + let s:bg_processes[a:pid] = a:pid + let [cond, status] = ['exit', '0'] + elseif vimproc#util#is_windows() + call s:libcall('vp_close_handle', [a:pid]) + endif + + let s:last_status = str2nr(status) + catch /No child processes/ + let [cond, status] = ['exit', '0'] + let s:last_status = 0 + catch + let [cond, status] = ['error', '0'] + let s:last_status = -1 + endtry + + return [cond, str2nr(status)] +endfunction + +function! s:vp_checkpid() dict + try + let [cond, status] = s:libcall('vp_waitpid', [self.pid]) + if cond !=# 'run' + let [self.cond, self.status] = [cond, status] + endif + catch /waitpid() error:\|vp_waitpid:/ + let [cond, status] = ['error', '0'] + endtry + + return [cond, str2nr(status)] +endfunction + +function! s:vp_waitpid(...) dict + let nohang = a:0 ? a:1 : 0 + call s:close_all(self) + + let self.is_valid = 0 + + if has_key(self, 'cond') && has_key(self, 'status') + " Use cache. + let [cond, status] = [self.cond, self.status] + else + let [cond, status] = s:waitpid(self.pid, nohang) + endif + + if cond ==# 'exit' + let self.pid = 0 + endif + + if has_key(self, 'pid_list') + if !has_key(self, 'pipe_status') + let self.pipe_status = repeat([['run', 0]], len(self.pid_list)) + endif + let self.pipe_status[:] = map(self.pipe_status[:-2], + \ 'v:val[0] !=# "run" ? v:val : s:waitpid(self.pid_list[v:key], nohang)') + \ + [[cond, status]] + endif + + return [cond, status] +endfunction + +function! s:vp_pgroup_waitpid() dict + call s:close_all(self) + + let self.is_valid = 0 + + if !has_key(self, 'cond') || + \ !has_key(self, 'status') + return s:waitpid(self.pid) + endif + + return [self.cond, self.status] +endfunction + +function! s:vp_socket_open(host, port) abort + let [socket] = s:libcall('vp_socket_open', [a:host, a:port]) + return socket +endfunction + +function! s:vp_socket_close() dict + call s:libcall('vp_socket_close', [self.fd]) + let self.is_valid = 0 +endfunction + +function! s:vp_socket_read(number, timeout) dict + let [hd, eof] = s:libcall_raw_read('vp_socket_read', + \ [self.fd, a:number, a:timeout]) + return [hd, eof] +endfunction + +function! s:vp_socket_write(hd, timeout) dict + let [nleft] = s:libcall_raw_write('vp_socket_write', + \ [self.fd, a:hd, a:timeout]) + return nleft +endfunction + +function! s:vp_host_exists(host) abort + let [rval] = s:libcall('vp_host_exists', [a:host]) + return rval +endfunction + +function! s:get_winwidth() abort + return winwidth(0) - &l:numberwidth - &l:foldcolumn +endfunction + +" Initialize. +if !exists('s:dll_handle') + let s:dll_handle = s:vp_dlopen(g:vimproc#dll_path) + let s:last_status = 0 + let s:last_errmsg = '' + call s:define_signals() +endif + +" vimproc dll version check. "{{{ +try + if vimproc#dll_version() != vimproc#version() + call s:print_error(printf('Your vimproc binary version is "%d",'. + \ ' but vimproc version is "%d".', + \ vimproc#dll_version(), vimproc#version())) + if g:vimproc#download_windows_dll && vimproc#util#is_windows() + if vimproc#util#try_update_windows_dll(s:VERSION_STRING) + call s:print_error('DLL automatically update succeeded.') + call s:print_error('Please restart Vim.') + endif + endif + endif +catch + call s:print_error(v:throwpoint) + call s:print_error(v:exception) + call s:print_error('Your vimproc binary is not compatible with this vimproc!') + call s:print_error('Please re-compile it.') +endtry +"}}} + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +unlet s:save_cpo +" }}} + +" __END__ +" vim:foldmethod=marker:fen:sw=2:sts=2 diff --git a/bundle/vimproc.vim/autoload/vimproc/cmd.vim b/bundle/vimproc.vim/autoload/vimproc/cmd.vim new file mode 100644 index 000000000..586d9f4ed --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/cmd.vim @@ -0,0 +1,103 @@ +"============================================================================= +" FILE: cmd.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +if !vimproc#util#is_windows() + function! vimproc#cmd#system(expr) abort + return vimproc#system(a:expr) + endfunction + let &cpo = s:save_cpo + finish +endif + +" Based from : http://d.hatena.ne.jp/osyo-manga/20130611/1370950114 + +let s:cmd = {} + +augroup vimproc + autocmd VimLeave * call s:cmd.close() +augroup END + + +function! s:cmd.open() abort "{{{ + let cmd = 'cmd.exe' + let self.vimproc = vimproc#popen3(cmd) + let self.cwd = getcwd() + + " Wait until getting first prompt. + let output = '' + while output !~ '.\+>$' + let output .= self.vimproc.stdout.read() + endwhile +endfunction"}}} + +function! s:cmd.close() abort "{{{ + call self.vimproc.waitpid() +endfunction"}}} + +function! s:cmd.system(cmd) abort "{{{ + " Execute cmd. + if self.cwd !=# getcwd() + " Execute cd. + let input = '(cd /D "' . getcwd() . '" & ' . a:cmd . ')' + let self.cwd = getcwd() + else + let input = a:cmd + endif + + call self.vimproc.stdin.write(input . "\n") + + " Wait until getting prompt. + let output = '' + while 1 + let output .= self.vimproc.stdout.read() + let lastnl = strridx(output, "\n") + if lastnl >= 0 && + \ output[lastnl + 1:] =~ '^\%([A-Z]:\\\|\\\\.\+\\.\+\\\).*>$' + break + endif + endwhile + let result = split(output, '\r\n\|\n')[1:-2] + + return join(result, "\n") +endfunction"}}} + +call s:cmd.open() + +function! vimproc#cmd#system(expr) abort + let cmd = type(a:expr) == type('') ? a:expr : + \ join(map(a:expr, + \ 'match(v:val, "\\s") >= 0 ? "\"".v:val."\"" : v:val')) + return s:cmd.system(cmd) +endfunction + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +" }}} +" vim:foldmethod=marker:fen:sw=2:sts=2 diff --git a/bundle/vimproc.vim/autoload/vimproc/commands.vim b/bundle/vimproc.vim/autoload/vimproc/commands.vim new file mode 100644 index 000000000..dfe2b524e --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/commands.vim @@ -0,0 +1,110 @@ +"============================================================================= +" FILE: commands.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +" Command functions: +function! vimproc#commands#_install(args) abort "{{{ + let savemp = &makeprg + let savecwd = getcwd() + + try + if executable('gmake') + let &makeprg = 'gmake' + elseif executable('make') + let &makeprg = 'make' + elseif executable('nmake') + let &makeprg = 'nmake -f make_msvc.mak nodebug=1' + endif + + " Change to the correct directory and run make + execute 'lcd' fnameescape(fnamemodify(g:vimproc#dll_path, ':h:h')) + execute 'make' a:args + finally + " Restore working directory and makeprg + execute 'lcd' fnameescape(savecwd) + let &makeprg = savemp + endtry +endfunction"}}} +function! vimproc#commands#_bang(cmdline) abort "{{{ + " Expand % and #. + let cmdline = join(map(vimproc#parser#split_args_through( + \ vimproc#util#iconv(a:cmdline, + \ vimproc#util#termencoding(), &encoding)), + \ 'substitute(expand(v:val), "\n", " ", "g")')) + + " Open pipe. + let subproc = vimproc#pgroup_open(cmdline, 1) + + call subproc.stdin.close() + + while !subproc.stdout.eof || !subproc.stderr.eof + if !subproc.stdout.eof + let output = subproc.stdout.read(10000, 0) + if output != '' + let output = vimproc#util#iconv(output, + \ vimproc#util#stdoutencoding(), &encoding) + + echon output + sleep 1m + endif + endif + + if !subproc.stderr.eof + let output = subproc.stderr.read(10000, 0) + if output != '' + let output = vimproc#util#iconv(output, + \ vimproc#util#stderrencoding(), &encoding) + echohl WarningMsg | echon output | echohl None + + sleep 1m + endif + endif + endwhile + + call subproc.stdout.close() + call subproc.stderr.close() + + call subproc.waitpid() +endfunction"}}} +function! vimproc#commands#_read(cmdline) abort "{{{ + " Expand % and #. + let cmdline = join(map(vimproc#parser#split_args_through( + \ vimproc#util#iconv(a:cmdline, + \ vimproc#util#termencoding(), &encoding)), + \ 'substitute(expand(v:val), "\n", " ", "g")')) + + " Expand args. + call append('.', split(vimproc#util#iconv(vimproc#system(cmdline), + \ vimproc#util#stdoutencoding(), &encoding), '\r\n\|\n')) +endfunction"}}} + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +" }}} +" vim:foldmethod=marker:fen:sw=2:sts=2 diff --git a/bundle/vimproc.vim/autoload/vimproc/filepath.vim b/bundle/vimproc.vim/autoload/vimproc/filepath.vim new file mode 100644 index 000000000..750d7f060 --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/filepath.vim @@ -0,0 +1,176 @@ +" This file from vital.vim. +" https://github.com/vim-jp/vital.vim + +" You should check the following related builtin functions. +" fnamemodify() +" resolve() +" simplify() + +let s:save_cpo = &cpo +set cpo&vim + +let s:path_sep_pattern = (exists('+shellslash') ? '[\\/]' : '/') . '\+' +let s:is_windows = has('win16') || has('win32') || has('win64') +let s:is_cygwin = has('win32unix') +let s:is_mac = !s:is_windows && !s:is_cygwin + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!executable('xdg-open') && system('uname') =~? '^darwin')) + +" Get the directory separator. +function! s:separator() abort + return !exists('+shellslash') || &shellslash ? '/' : '\' +endfunction + +" Get the path separator. +let s:path_separator = s:is_windows ? ';' : ':' +function! s:path_separator() abort + return s:path_separator +endfunction + +" Get the path extensions +function! s:path_extensions() abort + if !exists('s:path_extensions') + if s:is_windows + if exists('$PATHEXT') + let pathext = $PATHEXT + else + " get default PATHEXT + let pathext = matchstr(system('set pathext'), '^pathext=\zs.*\ze\n', 'i') + endif + let s:path_extensions = split(tolower(pathext), s:path_separator) + elseif s:is_cygwin + " cygwin is not use $PATHEXT + let s:path_extensions = ['', '.exe'] + else + let s:path_extensions = [''] + endif + endif + return s:path_extensions +endfunction + +" Convert all directory separators to "/". +function! s:unify_separator(path) abort + return substitute(a:path, s:path_sep_pattern, '/', 'g') +endfunction + +" Get the full path of command. +function! s:which(command, ...) abort + let maxcount = (a:0 >= 2 && type(a:2) == type(0)) ? a:2 : 1 + if maxcount == 1 && exists('*exepath') + let full = exepath(a:command) + if s:is_windows && (full =~? '\.lnk$') && (getftype(full) ==# 'file') + return resolve(full) + endif + return full + endif + let pathlist = a:command =~# s:path_sep_pattern ? [''] : + \ !a:0 ? split($PATH, s:path_separator) : + \ type(a:1) == type([]) ? copy(a:1) : + \ split(a:1, s:path_separator) + let pathlist = vimproc#util#uniq(pathlist) + + let pathext = s:path_extensions() + if index(pathext, '.' . tolower(fnamemodify(a:command, ':e'))) != -1 + let pathext = [''] + endif + + let dirsep = s:separator() + let cmdlist = [] + for dir in pathlist + let head = dir ==# '' ? '' : dir . dirsep + for ext in pathext + let full = fnamemodify(head . a:command . ext, ':p') + if s:is_windows && (full =~? '\.lnk$') && (getftype(full) ==# 'file') + let full = resolve(full) + endif + + if executable(full) + if s:is_case_tolerant() + let full = glob(substitute( + \ vimproc#util#substitute_path_separator( + \ toupper(full)), '\u:\@!', '[\0\L\0]', 'g'), 1) + endif + if full != '' + let cmdlist += [full] + if maxcount > 0 && len(cmdlist) >= maxcount + return join(cmdlist, "\n") + endif + endif + endif + endfor + endfor + + return join(cmdlist, "\n") +endfunction + +" Split the path with directory separator. +" Note that this includes the drive letter of MS Windows. +function! s:split(path) abort + return split(a:path, s:path_sep_pattern) +endfunction + +" Join the paths. +" join('foo', 'bar') => 'foo/bar' +" join('foo/', 'bar') => 'foo/bar' +" join('/foo/', ['bar', 'buz/']) => '/foo/bar/buz/' +function! s:join(...) abort + let sep = s:separator() + let path = '' + for part in a:000 + let path .= sep . + \ (type(part) is type([]) ? call('s:join', part) : + \ part) + unlet part + endfor + return substitute(path[1 :], s:path_sep_pattern, sep, 'g') +endfunction + +" Check if the path is absolute path. +if s:is_windows + function! s:is_absolute(path) abort + return a:path =~? '^[a-z]:[/\]' + endfunction +else + function! s:is_absolute(path) abort + return a:path[0] ==# '/' + endfunction +endif + +" Return the parent directory of the path. +" NOTE: fnamemodify(path, ':h') does not return the parent directory +" when path[-1] is the separator. +function! s:dirname(path) abort + let path = a:path + let orig = a:path + + let path = s:remove_last_separator(path) + if path == '' + return orig " root directory + endif + + let path = fnamemodify(path, ':h') + return path +endfunction + +" Remove the separator at the end of a:path. +function! s:remove_last_separator(path) abort + let sep = s:separator() + let pat = (sep == '\' ? '\\' : '/') . '\+$' + return substitute(a:path, pat, '', '') +endfunction + + +" Return true if filesystem ignores alphabetic case of a filename. +" Return false otherwise. +let s:is_case_tolerant = filereadable(expand(':r') . '.VIM') +function! s:is_case_tolerant() abort + return s:is_case_tolerant +endfunction + +function! vimproc#filepath#which(command, path, maxcount) abort + return s:which(a:command, a:path, a:maxcount) +endfunction + +let &cpo = s:save_cpo + +" vim:set et ts=2 sts=2 sw=2 tw=0: diff --git a/bundle/vimproc.vim/autoload/vimproc/lexer.vim b/bundle/vimproc.vim/autoload/vimproc/lexer.vim new file mode 100644 index 000000000..721159021 --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/lexer.vim @@ -0,0 +1,130 @@ +"============================================================================= +" FILE: parser.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +" Constants. {{{ +let g:vimproc#lexer#token_type = { + \ 'int' : 257, + \ 'string' : 258, + \ } +" }}} + +function! vimproc#lexer#init_lexer(text) abort + let lexer = deepcopy(s:lexer) + let lexer.reader = vimproc#lexer#init_reader(a:text) + + return lexer +endfunction + +let s:lexer = {} +function! s:lexer.advance() abort + call self.skip_spaces() + + let c = self.reader.read() + if c < 0 + return 0 + endif + + if c =~ '\d' + call self.reader.unread() + call self.lex_digit() + let self.tok = g:vimproc#lexer#token_type.int + else + throw 'Exception: Not int.' + endif + + return 1 +endfunction + +function! s:lexer.lex_digit() abort + let self.val = 0 + while 1 + let c = self.reader.read() + if c < 0 + break + elseif c !~ '\d' + call self.reader.unread() + break + endif + + let self.val = self.val * 10 + c + endwhile +endfunction + +function! s:lexer.skip_spaces() abort + while 1 + let c = self.reader.read() + if c < 0 + break + elseif c !~ '\s' + call self.reader.unread() + break + endif + endwhile +endfunction + +function! s:lexer.token() abort + return self.tok +endfunction + +function! s:lexer.value() abort + return self.val +endfunction + +function! vimproc#lexer#init_reader(text) abort + let reader = deepcopy(s:reader) + let reader.text = split(a:text, '\zs') + let reader.pos = 0 + + return reader +endfunction + +let s:reader = {} + +function! s:reader.read() abort + if self.pos >= len(self.text) + " Buffer over. + return -1 + endif + + let c = self.text[self.pos] + let self.pos += 1 + + return c +endfunction + +function! s:reader.unread() abort + let self.pos -= 1 +endfunction + + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +" }}} +" vim:foldmethod=marker:fen:sw=2:sts=2 diff --git a/bundle/vimproc.vim/autoload/vimproc/parser.vim b/bundle/vimproc.vim/autoload/vimproc/parser.vim new file mode 100644 index 000000000..6240f3c49 --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/parser.vim @@ -0,0 +1,1018 @@ +"============================================================================= +" FILE: parser.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +" For vimshell parser. +function! vimproc#parser#parse_pipe(statement) abort "{{{ + let commands = [] + for cmdline in vimproc#parser#split_pipe(a:statement) + " Split args. + let cmdline = s:parse_cmdline(cmdline) + + " Parse redirection. + if cmdline =~ '[<>]' + let [fd, cmdline] = s:parse_redirection(cmdline) + else + let fd = { 'stdin' : '', 'stdout' : '', 'stderr' : '' } + endif + + for key in ['stdout', 'stderr'] + if fd[key] == '' || fd[key] =~ '^>' + continue + endif + + if fd[key] ==# '/dev/clip' + " Clear. + let @+ = '' + elseif fd[key] ==# '/dev/quickfix' + " Clear quickfix. + call setqflist([]) + endif + endfor + + call add(commands, { + \ 'args' : vimproc#parser#split_args(cmdline), + \ 'fd' : fd + \}) + endfor + + return commands +endfunction"}}} +function! s:parse_cmdline(cmdline) abort "{{{ + let cmdline = a:cmdline + + " Expand block. + if cmdline =~ '{' + let cmdline = s:parse_block(cmdline) + endif + + " Expand tilde. + if cmdline =~ '\~' + let cmdline = s:parse_tilde(cmdline) + endif + + " Expand filename. + if cmdline =~ ' =' + let cmdline = s:parse_equal(cmdline) + endif + + " Expand variables. + if cmdline =~ '\$' + let cmdline = s:parse_variables(cmdline) + endif + + " Expand wildcard. + if cmdline =~ '[[*?]\|\\[()|]' + let cmdline = s:parse_wildcard(cmdline) + endif + + return s:parse_tilde(cmdline) +endfunction"}}} +function! vimproc#parser#parse_statements(script) abort "{{{ + if type(a:script) == type('') && a:script =~ '^\s*:' + return [ { + \ 'statement' : a:script, + \ 'condition' : 'always', + \ 'cwd' : getcwd(), + \ } ] + endif + + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + let statements = [] + let statement = '' + let i = 0 + while i < max + if script[i] == ';' + if statement != '' + call add(statements, + \ { + \ 'statement' : statement, + \ 'condition' : 'always', + \ 'cwd' : getcwd(), + \}) + endif + let statement = '' + let i += 1 + elseif script[i] == '&' + if i+1 < max && script[i+1] == '&' + if statement != '' + call add(statements, + \ { + \ 'statement' : statement, + \ 'condition' : 'true', + \ 'cwd' : getcwd(), + \}) + endif + let statement = '' + let i += 2 + else + let statement .= script[i] + + let i += 1 + endif + elseif script[i] == '|' + if i+1 < max && script[i+1] == '|' + if statement != '' + call add(statements, + \ { + \ 'statement' : statement, + \ 'condition' : 'false', + \ 'cwd' : getcwd(), + \}) + endif + let statement = '' + let i += 2 + else + let statement .= script[i] + + let i += 1 + endif + elseif script[i] == "'" + " Single quote. + let [string, i] = s:skip_single_quote(script, i) + let statement .= string + elseif script[i] == '"' + " Double quote. + let [string, i] = s:skip_double_quote(script, i) + let statement .= string + elseif script[i] == '`' + " Back quote. + let [string, i] = s:skip_back_quote(script, i) + let statement .= string + elseif script[i] == '\' + " Escape. + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + let statement .= '\' . script[i] + let i += 1 + elseif script[i] == '#' && statement == '' + " Comment. + break + else + let statement .= script[i] + let i += 1 + endif + endwhile + + if statement !~ '^\s*$' + call add(statements, + \ { + \ 'statement' : statement, + \ 'condition' : 'always', + \ 'cwd' : getcwd(), + \}) + endif + + return statements +endfunction"}}} + +function! vimproc#parser#split_statements(script) abort "{{{ + return map(vimproc#parser#parse_statements(a:script), + \ 'v:val.statement') +endfunction"}}} +function! vimproc#parser#split_args(script) abort "{{{ + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + let args = [] + let arg = '' + let i = 0 + while i < max + if script[i] == "'" + " Single quote. + let [arg_quote, i] = s:parse_single_quote(script, i) + let arg .= arg_quote + if arg == '' + call add(args, '') + endif + elseif script[i] == '"' + " Double quote. + let [arg_quote, i] = s:parse_double_quote(script, i) + let arg .= arg_quote + if arg == '' + call add(args, '') + endif + elseif script[i] == '`' + " Back quote. + let head = i > 0 ? script[: i-1] : [] + let [arg_quote, i] = s:parse_back_quote(script, i) + + " Re-parse script. + return vimproc#parser#split_args( + \ head + split(arg_quote, '\zs') + script[i :]) + elseif script[i] == '\' + " Escape. + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + let arg .= script[i] + let i += 1 + elseif script[i] == '#' && arg == '' + " Comment. + break + elseif script[i] != ' ' + let arg .= script[i] + let i += 1 + else + " Space. + if arg != '' + call add(args, arg) + endif + + let arg = '' + + let i += 1 + endif + endwhile + + if arg != '' + call add(args, arg) + endif + + return args +endfunction"}}} +function! vimproc#parser#split_args_through(script) abort "{{{ + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + let args = [] + let arg = '' + let i = 0 + while i < max + if script[i] == "'" + " Single quote. + let [string, i] = s:skip_single_quote(script, i) + let arg .= string + if arg == '' + call add(args, '') + endif + elseif script[i] == '"' + " Double quote. + let [string, i] = s:skip_double_quote(script, i) + let arg .= string + if arg == '' + call add(args, '') + endif + elseif script[i] == '`' + " Back quote. + let [string, i] = s:skip_back_quote(script, i) + let arg .= string + if arg == '' + call add(args, '') + endif + elseif script[i] == '\' + " Escape. + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + let arg .= '\'.script[i] + let i += 1 + elseif script[i] != ' ' + let arg .= script[i] + let i += 1 + else + " Space. + if arg != '' + call add(args, arg) + endif + + let arg = '' + + let i += 1 + endif + endwhile + + if arg != '' + call add(args, arg) + endif + + return args +endfunction"}}} +function! vimproc#parser#split_pipe(script) abort "{{{ + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + let command = '' + + let i = 0 + let commands = [] + while i < max + if script[i] == '|' + " Pipe. + call add(commands, command) + + " Search next command. + let command = '' + let i += 1 + elseif script[i] == "'" + " Single quote. + let [string, i] = s:skip_single_quote(script, i) + let command .= string + elseif script[i] == '"' + " Double quote. + let [string, i] = s:skip_double_quote(script, i) + let command .= string + elseif script[i] == '`' + " Back quote. + let [string, i] = s:skip_back_quote(script, i) + let command .= string + elseif script[i] == '\' && i + 1 < max + " Escape. + let command .= '\' . script[i+1] + let i += 2 + else + let command .= script[i] + let i += 1 + endif + endwhile + + call add(commands, command) + + return commands +endfunction"}}} +function! vimproc#parser#split_commands(script) abort "{{{ + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + let commands = [] + let command = '' + let i = 0 + while i < max + if script[i] == '\' + " Escape. + let command .= script[i] + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + let command .= script[i] + let i += 1 + elseif script[i] == '|' + if command != '' + call add(commands, command) + endif + let command = '' + + let i += 1 + else + + let command .= script[i] + let i += 1 + endif + endwhile + + if command != '' + call add(commands, command) + endif + + return commands +endfunction"}}} +function! vimproc#parser#expand_wildcard(wildcard) abort "{{{ + " Check wildcard. + let i = 0 + let max = len(a:wildcard) + let script = '' + let found = 0 + while i < max + if a:wildcard[i] == '*' || a:wildcard[i] == '?' || a:wildcard[i] == '[' + let found = 1 + break + else + let [script, i] = s:skip_else(script, a:wildcard, i) + endif + endwhile + + if !found + return [ a:wildcard ] + endif + + let wildcard = a:wildcard + + " Exclude wildcard. + let exclude = matchstr(wildcard, '\\\@ 'echo =ls hoge' + " ^ ^ + let i += strlen(a:script[i] . a:script[i+1] . prog) + endif + else + let [script, i] = s:skip_else(script, a:script, i) + endif + endwhile + + return script +endfunction"}}} +function! s:parse_variables(script) abort "{{{ + let script = '' + + let i = 0 + let max = len(a:script) + try + while i < max + if a:script[i] == '$' && a:script[i :] =~ '^$$\?\h' + " Eval variables. + let variable_name = matchstr(a:script, '^$$\?\zs\h\w*', i) + if exists('b:vimshell') + " For vimshell. + let script_head = a:script[i :] + if script_head =~ '^$\l' && + \ has_key(b:vimshell.variables, variable_name) + let script .= b:vimshell.variables[variable_name] + elseif script_head =~ '^\$\$' && + \ has_key(b:vimshell.system_variables, variable_name) + let script .= b:vimshell.system_variables[variable_name] + elseif script_head =~ '^$\h' + let script .= vimproc#util#substitute_path_separator( + \ eval('$' . variable_name)) + endif + else + let script .= vimproc#util#substitute_path_separator( + \ eval(matchstr(a:script, '^$\h\w*', i))) + endif + + let i = matchend(a:script, '^$$\?\h\w*', i) + else + let [script, i] = s:skip_else(script, a:script, i) + endif + endwhile + catch /^Vim\%((\a\+)\)\=:E15/ + " Parse error. + return a:script + endtry + + return script +endfunction"}}} +function! s:parse_wildcard(script) abort "{{{ + let script = '' + for arg in vimproc#parser#split_args_through(a:script) + let script .= join(vimproc#parser#expand_wildcard(arg)) . ' ' + endfor + + return script +endfunction"}}} +function! s:parse_redirection(script) abort "{{{ + let script = '' + let fd = { 'stdin' : '', 'stdout' : '', 'stderr' : '' } + + let i = 0 + let max = len(a:script) + while i < max + if a:script[i] == '<' + " Input redirection. + let i += 1 + let fd.stdin = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + let i = matchend(a:script, '^\s*\S\+', i) + elseif a:script[i] =~ '^[12]' && a:script[i :] =~ '^[12]>' + " Output redirection. + let i += 2 + if a:script[i-2] == 1 + let fd.stdout = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + else + let fd.stderr = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\zs\(\S\+\|&\d\+\)', i)), 0, '') + if fd.stderr ==# '&1' + " Redirection to stdout. + let fd.stderr = '/dev/stdout' + endif + endif + + let i = matchend(a:script, '^\s*\zs\(\S\+\|&\d\+\)', i) + elseif a:script[i] == '&' && a:script[i :] =~ '^&>' + " Output stderr. + let i += 2 + let fd.stderr = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + let i = matchend(a:script, '^\s*\S\+', i) + elseif a:script[i] == '>' + " Output redirection. + if a:script[i :] =~ '^>&' + " Output stderr. + let i += 2 + let fd.stderr = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + elseif a:script[i :] =~ '^>>' + " Append stdout. + let i += 2 + let fd.stdout = '>' . get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + else + " Output stdout. + let i += 1 + let fd.stdout = get(vimproc#parser#split_args( + \ matchstr(a:script, '^\s*\S\+', i)), 0, '') + endif + + let i = matchend(a:script, '^\s*\zs\S*', i) + else + let [script, i] = s:skip_else(script, a:script, i) + endif + endwhile + + return [fd, script] +endfunction"}}} + +function! s:parse_single_quote(script, i) abort "{{{ + if a:script[a:i] != "'" + return ['', a:i] + endif + + let arg = '' + let i = a:i + 1 + let max = len(a:script) + while i < max + if a:script[i] == "'" + if i+1 < max && a:script[i+1] == "'" + " Escape quote. + let arg .= "'" + let i += 2 + else + " Quote end. + return [arg, i+1] + endif + else + let arg .= a:script[i] + let i += 1 + endif + endwhile + + throw 'Exception: Quote ('') is not found.' +endfunction"}}} +function! s:parse_double_quote(script, i) abort "{{{ + if a:script[a:i] != '"' + return ['', a:i] + endif + + let escape_sequences = { + \ 'a' : "\", 'b' : "\", + \ 't' : "\", 'r' : "\", + \ 'n' : "\", 'e' : "\", + \ '\' : '\', '?' : '?', + \ '"' : '"', "'" : "'", + \ '`' : '`', '$' : '$', + \} + let arg = '' + let i = a:i + 1 + let script = type(a:script) == type([]) ? + \ a:script : split(a:script, '\zs') + let max = len(script) + while i < max + if script[i] == '"' + " Quote end. + return [arg, i+1] + elseif script[i] == '$' + " Eval variables. + let var = matchstr(join(script[i :], ''), '^$\h\w*') + if var != '' + let arg .= s:parse_variables(var) + let i += len(var) + else + let arg .= '$' + let i += 1 + endif + elseif script[i] == '`' + " Backquote. + let [arg_quote, i] = s:parse_back_quote(script, i) + let arg .= arg_quote + elseif script[i] == '\' + " Escape. + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + if script[i] == 'x' + let num = matchstr(join(script[i+1 :], ''), '^\x\+') + let arg .= nr2char(str2nr(num, 16)) + let i += len(num) + elseif has_key(escape_sequences, script[i]) + let arg .= escape_sequences[script[i]] + else + let arg .= '\' . script[i] + endif + let i += 1 + else + let arg .= script[i] + let i += 1 + endif + endwhile + + throw 'Exception: Quote (") is not found.' +endfunction"}}} +function! s:parse_back_quote(script, i) abort "{{{ + if a:script[a:i] != '`' + return ['', a:i] + endif + + let arg = '' + let max = len(a:script) + if a:i + 1 < max && a:script[a:i + 1] == '=' + " Vim eval quote. + let i = a:i + 2 + + while i < max + if a:script[i] == '\' + " Escape. + let i += 1 + + if i >= max + throw 'Exception: Join to next line (\).' + endif + + let arg .= '\' . a:script[i] + let i += 1 + elseif a:script[i] == '`' + " Quote end. + return [eval(arg), i+1] + else + let arg .= a:script[i] + let i += 1 + endif + endwhile + else + " Eval quote. + let i = a:i + 1 + + while i < max + if a:script[i] == '`' + " Quote end. + return [substitute(vimproc#system(arg), '\n$', '', ''), i+1] + else + let arg .= a:script[i] + let i += 1 + endif + endwhile + endif + + throw 'Exception: Quote (`) is not found.' +endfunction"}}} + +" Skip helper. +function! s:skip_single_quote(script, i) abort "{{{ + let max = len(a:script) + let string = '' + let i = a:i + + " a:script[i] is always "'" when this function is called + if i >= max || a:script[i] != '''' + throw 'Exception: Quote ('') is not found.' + endif + let string .= a:script[i] + let i += 1 + + let ss = [] + while i < max + if a:script[i] == '''' + if i+1 < max && a:script[i+1] == '''' + " Escape quote. + let ss += [a:script[i]] + let i += 1 + else + break + endif + endif + + let ss += [a:script[i]] + let i += 1 + endwhile + let string .= join(ss, '') + + if i < max + " must end with "'" + if a:script[i] != '''' + throw 'Exception: Quote ('') is not found.' + endif + let string .= a:script[i] + let i += 1 + endif + + return [string, i] +endfunction"}}} +function! s:skip_double_quote(script, i) abort "{{{ + let max = len(a:script) + let string = '' + let i = a:i + + " a:script[i] is always '"' when this function is called + if i >= max || a:script[i] != '"' + throw 'Exception: Quote (") is not found.' + endif + let string .= a:script[i] + let i += 1 + + let ss = [] + while i < max + if a:script[i] == '\' && i+1 < max + " Escape quote. + let ss += [a:script[i]] + let i += 1 + elseif a:script[i] == '"' + break + endif + + let ss += [a:script[i]] + let i += 1 + endwhile + let string .= join(ss, '') + + if i < max + " must end with '"' + if a:script[i] != '"' + throw 'Exception: Quote (") is not found.' + endif + let string .= a:script[i] + let i += 1 + endif + + return [string, i] +endfunction"}}} +function! s:skip_back_quote(script, i) abort "{{{ + let max = len(a:script) + let string = '' + let i = a:i + + " a:script[i] is always '`' when this function is called + if a:script[i] != '`' + throw 'Exception: Quote (`) is not found.' + endif + let string .= a:script[i] + let i += 1 + + while i < max && a:script[i] != '`' + let string .= a:script[i] + let i += 1 + endwhile + + if i < max + " must end with "`" + if a:script[i] != '`' + throw 'Exception: Quote (`) is not found.' + endif + let string .= a:script[i] + let i += 1 + endif + + return [string, i] +endfunction"}}} +function! s:skip_else(args, script, i) abort "{{{ + if a:script[a:i] == "'" + " Single quote. + let [string, i] = s:skip_single_quote(a:script, a:i) + let script = a:args . string + elseif a:script[a:i] == '"' + " Double quote. + let [string, i] = s:skip_double_quote(a:script, a:i) + let script = a:args . string + elseif a:script[a:i] == '`' + " Back quote. + let [string, i] = s:skip_back_quote(a:script, a:i) + let script = a:args . string + elseif a:script[a:i] == '\' + " Escape. + let script = a:args . '\' . a:script[a:i+1] + let i = a:i + 2 + else + let script = a:args . a:script[a:i] + let i = a:i + 1 + endif + + return [script, i] +endfunction"}}} + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +" }}} +" vim:foldmethod=marker:fen:sw=2:sts=2 diff --git a/bundle/vimproc.vim/autoload/vimproc/util.vim b/bundle/vimproc.vim/autoload/vimproc/util.vim new file mode 100644 index 000000000..f67f01d2a --- /dev/null +++ b/bundle/vimproc.vim/autoload/vimproc/util.vim @@ -0,0 +1,174 @@ +"============================================================================= +" FILE: util.vim +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +" }}} +"============================================================================= + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +let s:is_windows = has('win32') +let s:is_cygwin = has('win32unix') +let s:is_mac = !s:is_windows && !s:is_cygwin + \ && (has('mac') || has('macunix') || has('gui_macvim') || + \ (!isdirectory('/proc') && executable('sw_vers'))) + +" iconv() wrapper for safety. +function! vimproc#util#has_iconv() abort "{{{ + " On Windows, some encodings can be converted by iconv() even if + " libiconv.dll is not available. + return (has('iconv') || (s:is_windows && exists('*iconv'))) +endfunction"}}} +function! vimproc#util#iconv(expr, from, to) abort "{{{ + if !vimproc#util#has_iconv() + \ || a:expr == '' || a:from == '' + \ || a:to == '' || a:from ==# a:to + return a:expr + endif + + let result = iconv(a:expr, a:from, a:to) + return result != '' ? result : a:expr +endfunction"}}} +function! vimproc#util#systemencoding() abort "{{{ + return s:is_windows ? 'utf-8' : 'char' +endfunction"}}} +function! vimproc#util#termencoding() abort "{{{ + return 'char' +endfunction"}}} +function! vimproc#util#stdinencoding() abort "{{{ + return exists('g:stdinencoding') && type(g:stdinencoding) == type("") ? + \ g:stdinencoding : vimproc#util#termencoding() +endfunction"}}} +function! vimproc#util#stdoutencoding() abort "{{{ + return exists('g:stdoutencoding') && type(g:stdoutencoding) == type("") ? + \ g:stdoutencoding : vimproc#util#termencoding() +endfunction"}}} +function! vimproc#util#stderrencoding() abort "{{{ + return exists('g:stderrencoding') && type(g:stderrencoding) == type("") ? + \ g:stderrencoding : vimproc#util#termencoding() +endfunction"}}} +function! vimproc#util#expand(path) abort "{{{ + return vimproc#util#substitute_path_separator( + \ (a:path =~ '^\~') ? fnamemodify(a:path, ':p') : + \ (a:path =~ '^\$\h\w*') ? substitute(a:path, + \ '^\$\h\w*', '\=eval(submatch(0))', '') : + \ a:path) +endfunction"}}} +function! vimproc#util#is_windows() abort "{{{ + return s:is_windows +endfunction"}}} +function! vimproc#util#is_mac() abort "{{{ + return s:is_mac +endfunction"}}} +function! vimproc#util#is_cygwin() abort "{{{ + return s:is_cygwin +endfunction"}}} +function! vimproc#util#has_lua() abort "{{{ + " Note: Disabled if_lua feature if less than 7.3.885. + " Because if_lua has double free problem. + return has('lua') && (v:version > 703 || v:version == 703 && has('patch885')) +endfunction"}}} +function! vimproc#util#substitute_path_separator(path) abort "{{{ + return s:is_windows ? substitute(a:path, '\\', '/', 'g') : a:path +endfunction"}}} +function! vimproc#util#cd(path) abort "{{{ + execute (haslocaldir() ? 'lcd' : 'cd') fnameescape(a:path) +endfunction"}}} + +function! vimproc#util#uniq(list, ...) abort "{{{ + let list = a:0 ? map(copy(a:list), printf('[v:val, %s]', a:1)) : copy(a:list) + let i = 0 + let seen = {} + while i < len(list) + let key = string(a:0 ? list[i][1] : list[i]) + if has_key(seen, key) + call remove(list, i) + else + let seen[key] = 1 + let i += 1 + endif + endwhile + return a:0 ? map(list, 'v:val[0]') : list +endfunction"}}} +function! vimproc#util#set_default(var, val, ...) abort "{{{ + if !exists(a:var) || type({a:var}) != type(a:val) + let alternate_var = get(a:000, 0, '') + + let {a:var} = exists(alternate_var) ? + \ {alternate_var} : a:val + endif +endfunction"}}} +function! vimproc#util#try_update_windows_dll(version) abort "{{{ + let old_path = g:vimproc#dll_path . '.old' + if filereadable(old_path) + if delete(old_path) == -1 + return 0 + endif + endif + if filereadable(g:vimproc#dll_path) + if delete(g:vimproc#dll_path) == -1 + if rename(g:vimproc#dll_path, old_path) + return 0 + endif + endif + endif + return vimproc#util#try_download_windows_dll(a:version) +endfunction"}}} +function! vimproc#util#try_download_windows_dll(version) abort "{{{ + let fname = printf('vimproc_win%s.dll', has('win64') ? '64' : '32') + let url = printf('https://github.com/Shougo/vimproc.vim/releases/download/ver.%s/%s', a:version, fname) + + if executable('curl') + let cmd = printf('curl --insecure --silent --location --output %s %s', + \ s:win_escape(g:vimproc#dll_path), + \ s:win_escape(url)) + call system(cmd) + return filereadable(g:vimproc#dll_path) + + elseif executable('powershell') + let pscmd = printf("(New-Object Net.WebClient).DownloadFile('%s', '%s')", + \ url, g:vimproc#dll_path) + let cmd = printf('powershell -Command %s', s:win_escape(pscmd)) + call system(cmd) + return filereadable(g:vimproc#dll_path) + endif + return 0 +endfunction"}}} +function! s:win_escape(str) abort "{{{ + return '"' . substitute(a:str, '"', '""', 'g') . '"' +endfunction"}}} + + +" Global options definition. "{{{ +call vimproc#util#set_default( + \ 'g:stdinencoding', 'char') +call vimproc#util#set_default( + \ 'g:stdoutencoding', 'char') +call vimproc#util#set_default( + \ 'g:stderrencoding', 'char') +"}}} + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +" }}} +" vim: foldmethod=marker diff --git a/bundle/vimproc.vim/doc/vimproc.txt b/bundle/vimproc.vim/doc/vimproc.txt new file mode 100644 index 000000000..55eab7c80 --- /dev/null +++ b/bundle/vimproc.vim/doc/vimproc.txt @@ -0,0 +1,534 @@ +*vimproc.txt* Asynchronous execution plugin for Vim + +Version: 9.3 +Author : Shougo +Original Author : Yukihiro Nakadaira +License: MIT license {{{ + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +}}} + +CONTENTS *vimproc-contents* + +Introduction |vimproc-introduction| +Install |vimproc-install| +Interface |vimproc-interface| + Commands |vimproc-commands| + Functions |vimproc-functions| + Variables |vimproc-variables| + Objects |vimproc-objects| +Tips |vimproc-tips| +Examples |vimproc-examples| +FAQ |vimproc-faq| + +============================================================================== +INTRODUCTION *vimproc-introduction* + +*vimproc* is a great asynchronous execution library for Vim. It is a fork of +proc.vim by Yukihiro Nakadaira. I added some features and fixed some bugs and +I'm maintaining it now. Instead of an external shell (example: 'shell'), +|vimproc| uses an external DLL file. + + +============================================================================== +INSTALL *vimproc-install* + +First, download vimproc by cloning the Git repository: + +http://github.com/Shougo/vimproc.vim + +Next, you have to compile the external DLL "vimproc_xxx.so" (or +"vimproc_win32.dll" for Windows, "vimproc_cygwin.dll" for Windows/Cygwin). +Because vimproc depends on the functions of the DLL, vimproc will show an +error message if the compiled DLL doesn't exist. + +You can install the DLL using |VimProcInstall|. If you are having any trouble +or want to build manually then read on. + +Supported platforms: +* Windows 32/64bit (Compiled by MinGW or Visual Studio) +* macOS (10.5 or later) +* Linux +* Cygwin +* Solaris +* BSD (but cannot check) +* Android (experimental) + +Unsupported platforms: +* Other UNIX platforms + +Build Steps: + +Note: You must use GNU make to build vimproc. +Note: You must execute the command from the root of the vimproc repository + +Linux *vimproc-linux* +> + $ make +< +macOS *vimproc-macos* *vimproc-macosx* +> + $ make +< +Note: If you want to build for multiple architectures, you can use $ARCHS and +$CC variables. + +Build for i386 and x86-64: *vimproc-multiarch* +> + $ make ARCHS='i386 x86_64' +< +FreeBSD *vimproc-freebsd* +> + $ gmake + +If you want to use BSD make, use the platform specific makefile: > + + $ make -f make_bsd.mak + +Solaris *vimproc-solaris* +> + $ gmake +< +Note: If you want to use Sun Compiler, you can use $SUNCC variable. +> + $ gmake SUNCC=cc +< +Windows *vimproc-windows* + +Note: In Windows, using MinGW is recommended. +Note: If you do not have the "gcc" or "x86_64-w64-mingw32-gcc" binary in your +%PATH, you must change CC variable accordingly. + +Windows using MinGW (32bit Vim): +> + $ mingw32-make -f make_mingw32.mak +< +Windows using MinGW (If you want to use MinGW compiler in Cygwin): +> + $ mingw32-make -f make_mingw32.mak CC=mingw32-gcc +< +Windows using MinGW (64bit Vim): +> + $ mingw32-make -f make_mingw64.mak +< +Windows using Visual Studio (32bit/64bit Vim): +> + $ nmake -f make_msvc.mak +< +You should run this from VS command prompt. +The architecture will be automatically detected, but you can also specify the +architecture explicitly. E.g.: +> + 32bit: nmake -f make_msvc.mak CPU=i386 + 64bit: nmake -f make_msvc.mak CPU=AMD64 +< +* Cygwin: *vimproc-cygwin* +> + $ make +< +Note: The `vimproc_cygwin.dll` compiled in Cygwin won't work with Windows Vim. + +If you use |dein.vim| or |neobundle.vim|, you can update and build vimproc +automatically. +http://github.com/Shougo/dein.vim +http://github.com/Shougo/neobundle.vim + +Example for dein.vim: +> + call dein#add('Shougo/vimproc.vim', {'build': 'make'}) +< +Example for neobundle.vim: +> + NeoBundle 'Shougo/vimproc.vim', { + \ 'build' : { + \ 'windows' : 'tools\\update-dll-mingw', + \ 'cygwin' : 'make -f make_cygwin.mak', + \ 'mac' : 'make -f make_mac.mak', + \ 'linux' : 'make', + \ 'unix' : 'gmake', + \ } + \ } +< +Windows Binaries: +* Kaoriya Vim (http://www.kaoriya.net/software/vim/) comes bundled with a + precompiled version for vimproc in Windows environment +* https://github.com/Shougo/vimproc.vim/releases + +============================================================================== +INTERFACE *vimproc-interface* + +------------------------------------------------------------------------------ +COMMANDS *vimproc-commands* + +:VimProcBang {path} *:VimProcBang* + Executes {path} command and echo result. This + command replaces |:!|. + Note: It is not asynchronous. + +:VimProcRead {path} *:VimProcRead* + Executes {path} command and paste result in current + buffer. This command replaces |:read|. + +:VimProcInstall {args} *:VimProcInstall* + Tries to build the necessary DLL using `gmake`/`make`. + You can supply extra arguments to `make`, for example + to compile using clang `:VimProcInstall CC=clang`. + +------------------------------------------------------------------------------ +FUNCTIONS *vimproc-functions* + +vimproc#version() *vimproc#version()* + Returns vimproc version number. Version 5.0 is 500. Version + 5.1 (5.01) is 501. It has the same format as |v:version|. + +vimproc#dll_version() *vimproc#dll_version()* + Same to |vimproc#version()|, but it returns vimproc DLL + version. + +vimproc#open({filename}) *vimproc#open()* + Opens {filename} with a system associated command. + + *vimproc#get_command_name()* +vimproc#get_command_name({command} [, {path} [, {count}]]) + Searches {command} from {path} and returns command name. If + you omit {path}, uses $PATH instead. If you set {count}, + returns {count}th candidate. If you set {count} to a negative + number, it returns a list which contains all candidates. If + {count} is omitted, then 1 is used. + +vimproc#system({expr} [, {input} [, {timeout}]]) *vimproc#system()* + It replaces |system()|. If you call |system()| in Windows + environment, DOS window will appear. But, |vimproc#system()| + is not. + Note: It does not execute a shell. So a shell internal + command is invalid. Ex: pwd, cd, ... + + The {expr} is same to |vimproc#plineopen3()|. The type is + String or arguments list. If {expr} is a String, it is parsed + automatically. + If the end of {expr} is "&", executes a command in the + background. +> + call vimproc#system('ls &') +< + If you set {timeout}, vimproc will kill the process after + {timeout} and throw "vimproc: vimproc#system(): Timeout." + exception. + The unit is millisecond. + Note: |+reltime| and Vim 7.2 is required. + If you set {input}, inputs the string to the command. + +vimproc#system2({expr} [, {input} [, {timeout}]]) *vimproc#system2()* + Same as |vimproc#system()|. But it converts the encoding of + inputs and outputs automatically. + + *vimproc#system_passwd()* +vimproc#system_passwd({expr} [, {input} [, {timeout}]]) + Same as |vimproc#system()|. But it supports password input. + +vimproc#system_bg({expr}) *vimproc#system_bg()* + Same as |vimproc#system()|. But it executes a command in the + background. + Note: It disables user input. + Note: This function does not support the following statements: + ";", "&&" and "||". + +vimproc#system_gui({expr}) *vimproc#system_gui()* + Same as |vimproc#system_bg()|. + Note: It is obsolete API. + +vimproc#cmd#system({expr}) *vimproc#cmd#system()* + Same as |vimproc#system()| on non-Windows platforms. + On Windows, it is similar to |vimproc#system()| but faster. + It executes a "cmd.exe" process in the background when it is + called first time. After the next call, it reuses the + "cmd.exe" process. The process will be automatically closed + when Vim exits. + +vimproc#get_last_status() *vimproc#get_last_status()* + Gets the last |vimproc#system()| status value. + +vimproc#get_last_errmsg() *vimproc#get_last_errmsg()* + Gets the last |vimproc#system()| error messages. + +vimproc#shellescape({string}) *vimproc#shellescape()* + Escapes {string} for vimproc function arguments. + +vimproc#fopen({path} [, {flags} [, {mode}]]) *vimproc#fopen()* + Opens {path} file and returns a |vimproc-file-object|. + The optional {flags} is only either one of fopen() mode + string (e.g. "r", "wb+") or open() flag values as string + (e.g. "O_RDONLY | O_BINARY"). If {flags} is omitted, + "r" (read-only) is used. + The optional {mode} number specifies the permissions in case + a new file is created. If {mode} is omitted, 0644 (octal) + is used. + +vimproc#socket_open({host}, {port}) *vimproc#socket_open()* + Opens the {host}:{port} socket and returns a + |vimproc-socket-object|. + The {host} is a String. The {port} is a Number. + +vimproc#host_exists({host}) *vimproc#host_exists()* + Checks to see if {host} exists. + Note: Protocol name and path are ignored. + +vimproc#popen2({args} [, {is-pty}]) *vimproc#popen2()* + Executes {args} command and returns a |vimproc-process-object|. + If {args} is a String, {args} is parsed automatically. + Otherwise the {args} is a list of a command and its arguments. + If {is-pty} is 1, vimproc will use pty. + +vimproc#popen3({args} [, {is-pty}]) *vimproc#popen3()* + Same as |vimproc#popen2()|, but this function splits + stderr output. + +vimproc#plineopen2({commands} [, {is-pty}]) *vimproc#plineopen2()* + Executes {commands} command and returns a + |vimproc-process-object|. + If {commands} is a String, {commands} is parsed automatically. + Note: You can use pipes. + + Otherwise the {commands} is a list of dictionaries. + The keys are follows: + args The arguments list. + fd The output filename. If it is empty, the + output is sent to the next process. + + If {is-pty} is 1, vimproc will use pty. + +vimproc#plineopen3({commands} [, {is-pty}]) *vimproc#plineopen3()* + Same as |vimproc#plineopen2()|, but this function splits + stderr output. + +vimproc#pgroup_open({statements} [, {is-pty}]) *vimproc#pgroup_open()* + Executes {statements} command and returns a + |vimproc-process-object|. + If {statements} is a String, {statements} is parsed + automatically. + Note: You can use pipes, ";", "&&" and "||". + + Otherwise the {statements} is a dictionary list split by + commands. + The keys are follows: + statement The execute pipeline information same as + |vimproc#plineopen2()|'s {commands} argument. + condition The condition which executes next command. + "always" : execute always. (";") + "true" : execute if previous command is + succeeded. ("&&") + "false" : execute if previous command is + failed. ("||") + If {is-pty} is 1, vimproc will use pty. + +vimproc#ptyopen({args} [, {npipe}]) *vimproc#ptyopen()* + Executes {args} command and returns a |vimproc-process-object|. + If {args} is a String, {args} is parsed automatically. + The {npipe} is 2 or 3. If it is 2, combines stdout and + stderr. + Note: You can use pipes. + + Otherwise the {args} is a list of a command and its arguments. + +vimproc#kill({pid}, {sig}) *vimproc#kill()* + Sends {sig} signal to {pid} process. + If an error is occurred, it returns 1 for error and sets + |vimproc#get_last_errmsg()|. + If {sig} is 0, it checks whether {pid} exists. + +vimproc#write({filename}, {string} [, {mode}]) *vimproc#write()* + Writes {string} to {filename} file. + The {mode} is a write mode. "w", "b" or "a" is valid. + "w" : normal mode. + "b" : binary mode. + "a" : append mode. + If you omit {mode}, use "w". + But {filename} head is ">", "a" is used. + +vimproc#readdir({dirname}) *vimproc#readdir()* + Returns files in {dirname}. If {dirname} is not found, + returns an empty list. + Note: Filename encoding is converted to 'termencoding'. + +vimproc#delete_trash({filename}) *vimproc#delete_trash()* + Moves a file {filename} to a trashbox directory. + Note: Windows environment only. + Note: Filename encoding is converted to 'termencoding'. + +------------------------------------------------------------------------------ +VARIABLES *vimproc-variables* + + *g:vimproc#dll_path* +g:vimproc#dll_path (default + Win32: "$VIMRUNTIME/lib/vimproc_win32.dll" + Win64: "$VIMRUNTIME/lib/vimproc_win64.dll" + Cygwin: "$VIMRUNTIME/lib/vimproc_cygwin.dll" + Mac: "$VIMRUNTIME/lib/vimproc_mac.so" + Linux32: "$VIMRUNTIME/lib/vimproc_linux32.so" + Linux64: "$VIMRUNTIME/lib/vimproc_linux64.so" + Others: "$VIMRUNTIME/lib/vimproc_unix.so") + This variable stores a DLL name used by vimproc. You must + compile this DLL file. If this DLL does not exist, vimproc + will echo error. + *g:vimproc_dll_path* + Note: |g:vimproc_dll_path| is obsolete name. + + *g:vimproc#disable* +g:vimproc#disable (default : not defined) + If it is defined, you cannot call vimproc functions. + You can use it to disable vimproc before loading it. + + *g:vimproc#download_windows_dll* +g:vimproc#download_windows_dll (default : 0) + If this is non-zero, vimproc tries downloading MS Windows DLL + file from GitHub Releases page(*). + Vimproc also tries updating DLL file if it is outdated. + Vimproc does nothing if you don't use MS Windows. + + (*) https://github.com/Shougo/vimproc.vim/releases + + *g:vimproc#popen2_commands* +g:vimproc#popen2_commands (default : refer to autoload/vimproc.vim) + This variable is that vimproc use popen2 commands instead of + popen3 as dictionary. The key is command name and the value + is 1 or 0. If the command does not work in popen3, you can + set this variable. + *g:vimproc_popen2_commands* + Note: |g:vimproc_popen2_commands| is obsolete name. + + *g:vimproc#password_pattern* +g:vimproc#password_pattern (default : refer to autoload/vimproc.vim) + The default password pattern. + Note: This variable is used for vimshell. + *g:vimproc_password_pattern* + Note: |g:vimproc_password_pattern| is obsolete name. + + *g:stdinencoding* +g:stdinencoding (default : "char") + The default vimproc stdin encoding. + + *g:stdoutencoding* +g:stdoutencoding (default : "char") + The default vimproc stdout encoding. + + *g:stderrencoding* +g:stderrencoding (default : "char") + The default vimproc stderr encoding. + +------------------------------------------------------------------------------ +OBJECTS *vimproc-objects* + + *vimproc-file-object* +File object + The file object provides some operations for file io. + It has functions and attributes follows: + eof If reaches end of file, it is 1. + Otherwise, 0. + is_valid Todo + read([{number}[, {timeout}[, {oneline}]]]) + Read this file content up to the {number} + characters. + read_line([{number}[, {timeout}[, {oneline}]]]) + Read next line from this file up to the + {number} characters. + read_lines([{number}[, {timeout}[, {oneline}]]]) + Read all lines from this file up to the + {number} characters. + write({str}[, {timeout}]) + Write given {str} to this file. + close() Close this file. + + *vimproc-socket-object* +Socket object + The socket object provides some operations for socket io. + It functions and attributes same to |vimproc-file-object|. + + *vimproc-process-object* +Process object + The process object provides some operations for piped io. + It has functions and attributes follows: + pid The pid of a child process was started. + pid_list Todo + stderr The |vimproc-file-object|. + stdout The |vimproc-file-object|. + stdin The |vimproc-file-object|. + is_pty Todo + is_valid Todo + checkpid() Todo + kill({signal}) It is similar to kill command. It can send + {signal} to a child process. + waitpid() Wait for a child process to stop or terminate. + get_winsize() Todo + set_winsize({width}, {height}) + Todo + +============================================================================== +TIPS *vimproc-tips* + +Pseudo devices *vimproc-tips-pseudo-devices* + vimproc supports pseudo devices: + + /dev/null + Remove all output. + + /dev/clip + Print to clipboard. + + /dev/quickfix + Print to |quickfix|. + +============================================================================== +EXAMPLES *vimproc-examples* +> + " File open test. + let file = vimproc#fopen("./test1.vim", "O_RDONLY", 0) + let res = file.read() + call file.close() + new + call append(0, split(res, '\r\n\|\r\|\n')) + + " Pipe open test. + let sub = vimproc#popen2('ls') + let res = '' + while !sub.stdout.eof + let res .= sub.stdout.read() + endwhile + let [cond, status] = sub.waitpid() + new + call append(0, split(res, '\r\n\|\r\|\n') + [string([cond, status])]) + + " Socket open test. + let sock = vimproc#socket_open('www.yahoo.com', 80) + call sock.write("GET / HTTP/1.0\r\n\r\n") + let res = '' + while !sock.eof + let res .= sock.read() + endwhile + call sock.close() + new + call append(0, split(res, '\r\n\|\r\|\n')) +< +============================================================================== +FAQ *vimproc-faq* + +Q: I want to check a process is a zombie process. + +A: You can use vimproc#kill({pid}, 0) or {process}.kill(0). + +============================================================================== +vim:tw=78:ts=8:ft=help:norl:noet:fen: diff --git a/bundle/vimproc.vim/make_android.mak b/bundle/vimproc.vim/make_android.mak new file mode 100644 index 000000000..2e4c5dc13 --- /dev/null +++ b/bundle/vimproc.vim/make_android.mak @@ -0,0 +1,21 @@ +# You must set environment variables to suit your environment, in this Makefile or your shell. +# For example, using Android NDK on Mac OSX: +# NDK_TOP=/path/to/your/ndk/android-ndk-r8d +# SYSROOT=$(NDK_TOP)/platforms/android-8/arch-arm +# CFLAGS=-march=armv5te -msoft-float +# CC=$(NDK_TOP)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-gcc -mandroid --sysroot=$(SYSROOT) + +CFLAGS+=-W -Wall -Wno-unused -Wno-unused-parameter -std=c99 -O2 -fPIC -pedantic +LDFLAGS+=-shared + +TARGET=lib/vimproc_unix.so +SRC=src/proc.c src/ptytty.c +INC=src/vimstack.c src/ptytty.h + +all: $(TARGET) + +$(TARGET): $(SRC) $(INC) + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_bsd.mak b/bundle/vimproc.vim/make_bsd.mak new file mode 100644 index 000000000..3a23207f0 --- /dev/null +++ b/bundle/vimproc.vim/make_bsd.mak @@ -0,0 +1,17 @@ +# for *BSD platform. + +SUFFIX!=uname -sm | tr '[:upper:]' '[:lower:]' | sed -e 's/ /_/' + +TARGET=lib/vimproc_$(SUFFIX).so + +SRC=src/proc.c +CFLAGS+=-W -O2 -Wall -Wno-unused -Wno-unused-parameter -std=gnu99 -pedantic -shared -fPIC +LDFLAGS+=-lutil + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_cygwin.mak b/bundle/vimproc.vim/make_cygwin.mak new file mode 100644 index 000000000..0d0387a26 --- /dev/null +++ b/bundle/vimproc.vim/make_cygwin.mak @@ -0,0 +1,12 @@ +CFLAGS+=-O2 -W -Wall -Wno-unused -Wno-unused-parameter -use=gnu99 -shared +TARGET=lib/vimproc_cygwin.dll +SRC=src/proc.c +LDFLAGS+=-lutil + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_cygwin64.mak b/bundle/vimproc.vim/make_cygwin64.mak new file mode 100644 index 000000000..b2f9758ce --- /dev/null +++ b/bundle/vimproc.vim/make_cygwin64.mak @@ -0,0 +1,12 @@ +CFLAGS+=-O2 -W -Wall -Wno-unused -Wno-unused-parameter -use=gnu99 -shared +TARGET=lib/vimproc_cygwin64.dll +SRC=src/proc.c +LDFLAGS+=-lutil + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_mac.mak b/bundle/vimproc.vim/make_mac.mak new file mode 100644 index 000000000..97ead7c7f --- /dev/null +++ b/bundle/vimproc.vim/make_mac.mak @@ -0,0 +1,26 @@ +# for Mac. + +ifneq ($(shell which clang),) +CC=clang +else +ifneq ($(shell which llvm-gcc),) +CC=llvm-gcc +else +CC=gcc +endif +endif + +TARGET=lib/vimproc_mac.so +SRC=src/proc.c +ARCHS= +CFLAGS+=-O2 -W -Wall -Wno-unused -Wno-unused-parameter -bundle -fPIC $(foreach ARCH,$(ARCHS),-arch $(ARCH)) +LDFLAGS= + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +.PHONY : clean +clean: + -rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_mingw32.mak b/bundle/vimproc.vim/make_mingw32.mak new file mode 100644 index 000000000..5302166b2 --- /dev/null +++ b/bundle/vimproc.vim/make_mingw32.mak @@ -0,0 +1,15 @@ +# for MinGW. + +TARGET=lib/vimproc_win32.dll +SRC=src/proc_w32.c +CC=gcc +CFLAGS+=-O2 -Wall -shared -m32 +LDFLAGS+=-lwsock32 + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_mingw64.mak b/bundle/vimproc.vim/make_mingw64.mak new file mode 100644 index 000000000..32d737ddd --- /dev/null +++ b/bundle/vimproc.vim/make_mingw64.mak @@ -0,0 +1,15 @@ +# for MinGW. + +TARGET=lib/vimproc_win64.dll +SRC=src/proc_w32.c +CC=x86_64-w64-mingw32-gcc +CFLAGS+=-O2 -Wall -shared -m64 +LDFLAGS+=-lwsock32 + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_msvc.mak b/bundle/vimproc.vim/make_msvc.mak new file mode 100644 index 000000000..92769d9a1 --- /dev/null +++ b/bundle/vimproc.vim/make_msvc.mak @@ -0,0 +1,74 @@ +# WINDOWS BUILD SETTINGS. + +WINVER = 0x0500 +APPVER = 5.0 +TARGET = WINNT +_WIN32_IE = 0x0500 + +!ifdef CPU +! if "$(CPU)" == "I386" +CPU = i386 +! endif +!else # !CPU +CPU = i386 +! if !defined(PLATFORM) && defined(TARGET_CPU) +PLATFORM = $(TARGET_CPU) +! endif +! ifdef PLATFORM +! if ("$(PLATFORM)" == "x64") || ("$(PLATFORM)" == "X64") +CPU = AMD64 +! elseif ("$(PLATFORM)" != "x86") && ("$(PLATFORM)" != "X86") +! error *** ERROR Unknown target platform "$(PLATFORM)". Make aborted. +! endif +! endif +!endif + +# CONTROL BUILD MODE + +!IFDEF DEBUG +CFLAGS = $(CFLAGS) -D_DEBUG +!ELSE +CFLAGS = $(CFLAGS) -D_NDEBUG +!ENDIF + +# VIMPROC SPECIFICS + +!if "$(CPU)" == "AMD64" +VIMPROC=vimproc_win64 +!else +VIMPROC=vimproc_win32 +!endif + +SRCDIR = src +LIBDIR = lib +OUTDIR = $(SRCDIR)\obj$(CPU) + +OBJS = $(OUTDIR)/proc_w32.obj + +LINK = link +LFLAGS = /nologo /dll +DEFINES = -D_CRT_SECURE_NO_WARNINGS=1 -D_BIND_TO_CURRENT_VCLIBS_VERSION=1 +CFLAGS = /nologo $(CFLAGS) $(DEFINES) /wd4100 /wd4127 /O2 /LD /c + +# RULES + +build: $(LIBDIR)\$(VIMPROC).dll + +clean: + -IF EXIST $(OUTDIR)/nul RMDIR /s /q $(OUTDIR) + -DEL /F /Q $(LIBDIR)\$(VIMPROC).* + +$(LIBDIR)\$(VIMPROC).dll: $(OBJS) + $(LINK) $(LFLAGS) /OUT:$@ $(OBJS) shell32.lib ws2_32.lib + IF EXIST $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +{$(SRCDIR)}.c{$(OUTDIR)}.obj:: + $(CC) $(CFLAGS) -Fo$(OUTDIR)\ $< + +$(OUTDIR): + IF NOT EXIST $(OUTDIR)/nul MKDIR $(OUTDIR) + +$(OUTDIR)/proc_w32.obj: $(OUTDIR) $(SRCDIR)/proc_w32.c $(SRCDIR)/vimstack.c + +.PHONY: build clean diff --git a/bundle/vimproc.vim/make_sunos.mak b/bundle/vimproc.vim/make_sunos.mak new file mode 100644 index 000000000..416ec4ae5 --- /dev/null +++ b/bundle/vimproc.vim/make_sunos.mak @@ -0,0 +1,24 @@ +# For SunOS + +ifneq ($(SUNCC),) +CC=$(SUNCC) +CFLAGS+=-errwarn -xc99 -xO3 -native -KPIC +LDFLAGS+=-G +else # gcc +CC=gcc +CFLAGS+=-W -Wall -Wno-unused -Wno-unused-parameter -std=c99 -O2 -fPIC -pedantic +LDFLAGS+=-shared +endif +CPPFLAGS+=-D_XPG6 -D__EXTENSIONS__ + +TARGET=lib/vimproc_unix.so +SRC=src/proc.c src/ptytty.c +INC=src/vimstack.c src/ptytty.h + +all: $(TARGET) + +$(TARGET): $(SRC) $(INC) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/make_unix.mak b/bundle/vimproc.vim/make_unix.mak new file mode 100644 index 000000000..49b86efc4 --- /dev/null +++ b/bundle/vimproc.vim/make_unix.mak @@ -0,0 +1,20 @@ +# for *nix platform. + +ifneq (,$(wildcard /lib*/ld-linux*.so.2)) + SUFFIX=linux$(if $(wildcard /lib*/ld-linux*64.so.2),64,32) +else + SUFFIX=unix +endif +TARGET=lib/vimproc_$(SUFFIX).so + +SRC=src/proc.c +CFLAGS+=-W -O2 -Wall -Wno-unused -Wno-unused-parameter -std=gnu99 -pedantic -shared -fPIC +LIBS=-lutil + +all: $(TARGET) + +$(TARGET): $(SRC) src/vimstack.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(SRC) $(LIBS) + +clean: + rm -f $(TARGET) diff --git a/bundle/vimproc.vim/plugin/vimproc.vim b/bundle/vimproc.vim/plugin/vimproc.vim new file mode 100644 index 000000000..0b742944e --- /dev/null +++ b/bundle/vimproc.vim/plugin/vimproc.vim @@ -0,0 +1,51 @@ +"============================================================================= +" FILE: vimproc.vim +" AUTHOR: Shougo Matsushita +" License: MIT license {{{ +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be included +" in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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 exists('g:loaded_vimproc') + finish +elseif v:version < 702 + echoerr 'vimproc does not work this version of Vim "' . v:version . '".' + finish +endif + +let g:loaded_vimproc = 1 + +" Saving 'cpoptions' {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +command! -nargs=* VimProcInstall + \ call vimproc#commands#_install() +command! -nargs=+ -complete=shellcmd VimProcBang + \ call vimproc#commands#_bang() +command! -nargs=+ -complete=shellcmd VimProcRead + \ call vimproc#commands#_read() + +" Restore 'cpoptions' {{{ +let &cpo = s:save_cpo +unlet s:save_cpo +" }}} +" vim: foldmethod=marker diff --git a/bundle/vimproc.vim/src/fakepoll.h b/bundle/vimproc.vim/src/fakepoll.h new file mode 100644 index 000000000..adc101995 --- /dev/null +++ b/bundle/vimproc.vim/src/fakepoll.h @@ -0,0 +1,161 @@ +/* fakepoll.h */ +/* poll using select */ +/* Warning: a call to this poll() takes about 4K of stack space. */ + +/* Greg Parker gparker-web@sealiesoftware.com December 2000 */ +/* This code is in the public domain and may be copied or modified without */ +/* permission. */ + +/* Nico Raffato gparker-web@sealiesoftware.com September 2009 */ + +/* Updated Sep 2009: */ +/* * fix crash when an fd is less than 0 */ +/* * don't set POLLIN or POLLOUT in revents if it wasn't requested */ +/* in events (only happens when an fd is in the poll set twice) */ + +#ifndef _FAKE_POLL_H +#define _FAKE_POLL_H + +#include +#include +#include +#include +#include + +#ifndef OPEN_MAX + #define OPEN_MAX (sysconf(_SC_OPEN_MAX)) +#endif + +typedef struct pollfd { + int fd; /* file desc to poll */ + short events; /* events of interest on fd */ + short revents; /* events that occurred on fd */ +} pollfd_t; + + +/* poll flags */ +#define POLLIN 0x0001 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 + +/* synonyms */ +#define POLLNORM POLLIN +#define POLLPRI POLLIN +#define POLLRDNORM POLLIN +#define POLLRDBAND POLLIN +#define POLLWRNORM POLLOUT +#define POLLWRBAND POLLOUT + +/* ignored */ +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +int poll(struct pollfd *pollSet, int pollCount, int pollTimeout) +{ + struct timeval tv; + struct timeval *tvp; + fd_set readFDs, writeFDs, exceptFDs; + fd_set *readp, *writep, *exceptp; + struct pollfd *pollEnd, *p; + int selected; + int result; + int maxFD; + + if (!pollSet) { + pollEnd = NULL; + readp = NULL; + writep = NULL; + exceptp = NULL; + maxFD = 0; + } else { + pollEnd = pollSet + pollCount; + readp = &readFDs; + writep = &writeFDs; + exceptp = &exceptFDs; + + FD_ZERO(readp); + FD_ZERO(writep); + FD_ZERO(exceptp); + + /* Find the biggest fd in the poll set */ + maxFD = 0; + for (p = pollSet; p < pollEnd; p++) { + if (p->fd > maxFD) maxFD = p->fd; + } + + if (maxFD >= OPEN_MAX) { + /* At least one fd is too big */ + errno = EINVAL; + return -1; + } + + /* Transcribe flags from the poll set to the fd sets */ + for (p = pollSet; p < pollEnd; p++) { + if (p->fd < 0) { + /* Negative fd checks nothing and always reports zero */ + } else { + if (p->events & POLLIN) FD_SET(p->fd, readp); + if (p->events & POLLOUT) FD_SET(p->fd, writep); + if (p->events != 0) FD_SET(p->fd, exceptp); + /* POLLERR is never set coming in; poll() always reports errors */ + /* But don't report if we're not listening to anything at all. */ + } + } + } + + /* poll timeout is in milliseconds. Convert to struct timeval. */ + /* poll timeout == -1 : wait forever : select timeout of NULL */ + /* poll timeout == 0 : return immediately : select timeout of zero */ + if (pollTimeout >= 0) { + tv.tv_sec = pollTimeout / 1000; + tv.tv_usec = (pollTimeout % 1000) * 1000; + tvp = &tv; + } else { + tvp = NULL; + } + + selected = select(maxFD+1, readp, writep, exceptp, tvp); + + + if (selected < 0) { + /* Error during select */ + result = -1; + } else if (selected > 0) { + /* Select found something */ + /* Transcribe result from fd sets to poll set. */ + /* Also count the number of selected fds. poll returns the */ + /* number of ready fds; select returns the number of bits set. */ + int polled = 0; + for (p = pollSet; p < pollEnd; p++) { + p->revents = 0; + if (p->fd < 0) { + /* Negative fd always reports zero */ + } else { + if ((p->events & POLLIN) && FD_ISSET(p->fd, readp)) { + p->revents |= POLLIN; + } + if ((p->events & POLLOUT) && FD_ISSET(p->fd, writep)) { + p->revents |= POLLOUT; + } + if ((p->events != 0) && FD_ISSET(p->fd, exceptp)) { + p->revents |= POLLERR; + } + + if (p->revents) polled++; + } + } + result = polled; + } else { + /* selected == 0, select timed out before anything happened */ + /* Clear all result bits and return zero. */ + for (p = pollSet; p < pollEnd; p++) { + p->revents = 0; + } + result = 0; + } + + return result; +} + + +#endif /* _FAKE_POLL_H */ diff --git a/bundle/vimproc.vim/src/proc.c b/bundle/vimproc.vim/src/proc.c new file mode 100644 index 000000000..6a4e77e0c --- /dev/null +++ b/bundle/vimproc.vim/src/proc.c @@ -0,0 +1,1273 @@ +/* vim:set sw=4 sts=4 et: */ +/** + * FILE: proc.c + * AUTHOR: Yukihiro Nakadaira (original) + * Nico Raffo (modified) + */ + +#define _XOPEN_SOURCE 600 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined __APPLE__ +# include +# include +#endif +#include + +#include + +/* for poll() */ +#if defined __APPLE__ +# include "fakepoll.h" +#else +# include +#endif + +/* for forkpty() / login_tty() */ +#if (defined __linux__ || defined __CYGWIN__ || defined __gnu_hurd__) && !defined __ANDROID__ +# include +# include +#elif defined __APPLE__ || defined __NetBSD__ || defined __OpenBSD__ +# include +#elif defined __sun__ || defined __ANDROID__ +# include "ptytty.h" +#else +# include +# include +#endif + +/* for ioctl() */ +#ifdef __APPLE__ +# include +#endif + +/* for tc* and ioctl */ +#include +#include +#ifndef TIOCGWINSZ +# include /* 4.3+BSD requires this too */ +#endif + +/* for waitpid() */ +#include +#include +#if defined __NetBSD__ +# define WIFCONTINUED(x) (_WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) == 0x13) +#elif defined __ANDROID__ +# define WIFCONTINUED(x) (WIFSTOPPED(x) && WSTOPSIG(x) == 0x13) +#endif + +/* for socket */ +#if defined __FreeBSD__ +# define __BSD_VISIBLE 1 +# include +#endif +#include +#include +#include +#include + +/* for ctermid */ +#if defined __ANDROID__ +# define ctermid(x) "/dev/tty" +#endif + +#include "vimstack.c" + +const int debug = 0; + +/* API */ +const char *vp_dlopen(char *args); /* [handle] (path) */ +const char *vp_dlclose(char *args); /* [] (handle) */ +const char *vp_dlversion(char *args); /* [version] () */ + +const char *vp_file_open(char *args); /* [fd] (path, flags, mode) */ +const char *vp_file_close(char *args); /* [] (fd) */ +const char *vp_file_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +const char *vp_file_write(char *args); /* [nleft] (fd, timeout, hd) */ + +const char *vp_pipe_open(char *args); /* [pid, [fd] * npipe] + (npipe, hstdin, hstdout, hstderr, argc, [argv]) */ +const char *vp_pipe_close(char *args); /* [] (fd) */ +const char *vp_pipe_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +const char *vp_pipe_write(char *args); /* [nleft] (fd, timeout, hd) */ + +const char *vp_pty_open(char *args); +/* [pid, stdin, stdout, stderr] + (npipe, width, height,hstdin, hstdout, hstderr, argc, [argv]) */ +const char *vp_pty_close(char *args); /* [] (fd) */ +const char *vp_pty_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +const char *vp_pty_write(char *args); /* [nleft] (fd, timeout, hd) */ +const char *vp_pty_get_winsize(char *args); /* [width, height] (fd) */ +const char *vp_pty_set_winsize(char *args); /* [] (fd, width, height) */ + +const char *vp_kill(char *args); /* [] (pid, sig) */ +const char *vp_waitpid(char *args); /* [cond, status] (pid) */ + +const char *vp_socket_open(char *args); /* [socket] (host, port) */ +const char *vp_socket_close(char *args);/* [] (socket) */ +const char *vp_socket_read(char *args); /* [eof, hd] (socket, cnt, timeout) */ +const char *vp_socket_write(char *args);/* [nleft] (socket, hd, timeout) */ + +const char *vp_host_exists(char *args); /* [int] (host) */ + +const char *vp_decode(char *args); /* [decoded_str] (encode_str) */ + +const char *vp_get_signals(char *args); /* [signals] () */ +/* --- */ + +#define VP_BUFSIZE (65536) +#define VP_READ_BUFSIZE (VP_BUFSIZE - (VP_HEADER_SIZE + 1) * 2 - 1) + +static vp_stack_t _result = VP_STACK_NULL; + +const char * +vp_dlopen(char *args) +{ + vp_stack_t stack; + char *path; + void *handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); + VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, VP_BUFSIZE)); + + handle = dlopen(path, RTLD_LAZY); + if (handle == NULL) + return dlerror(); + vp_stack_push_num(&_result, "%p", handle); + return vp_stack_return(&_result); +} + +const char * +vp_dlclose(char *args) +{ + vp_stack_t stack; + void *handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); + + /* On FreeBSD6, to call dlclose() twice with same pointer causes SIGSEGV */ + if (dlclose(handle) == -1) + return dlerror(); + vp_stack_free(&_result); + return NULL; +} + +const char * +vp_dlversion(char *args) +{ + vp_stack_push_num(&_result, "%2d%02d", 9, 3); + return vp_stack_return(&_result); +} + +static int +str_to_oflag(const char *flags) +{ + int oflag = 0; + + if (strchr("rwa", flags[0])) { + if (strchr(flags, '+')) { + oflag = O_RDWR; + } else { + oflag = flags[0] == 'r' ? O_RDONLY : O_WRONLY; + } + if (flags[0] == 'w' || flags[0] == 'a') { + oflag |= O_CREAT | (flags[0] == 'w' ? O_TRUNC : O_APPEND); + } +#define VP_CHR_TO_OFLAG(_c, _f) do { \ + if (strchr(flags, (_c))) { oflag |= (_f); } \ +} while (0) + +#ifdef O_EXCL + VP_CHR_TO_OFLAG('x', O_EXCL); +#endif +#ifdef O_CLOEXEC + VP_CHR_TO_OFLAG('e', O_CLOEXEC); +#endif +#ifdef O_BINARY + VP_CHR_TO_OFLAG('b', O_BINARY); +#endif +#ifdef O_TEXT + VP_CHR_TO_OFLAG('t', O_TEXT); +#endif +#ifdef O_SEQUENTIAL + VP_CHR_TO_OFLAG('S', O_SEQUENTIAL); +#endif +#ifdef O_RANDOM + VP_CHR_TO_OFLAG('R', O_RANDOM); +#endif + +#undef VP_CHR_TO_OFLAG + } else { + if (strstr(flags, "O_RDONLY")) { + oflag = O_RDONLY; + } else if (strstr(flags, "O_WRONLY")) { + oflag = O_WRONLY; + } else if (strstr(flags, "O_RDWR")) { + oflag = O_RDWR; + } else { + return -1; + } +#define VP_STR_TO_OFLAG(_f) do { \ + if (strstr(flags, #_f)) { oflag |= (_f); } \ +} while (0) + + VP_STR_TO_OFLAG(O_APPEND); + VP_STR_TO_OFLAG(O_CREAT); + VP_STR_TO_OFLAG(O_TRUNC); +#ifdef O_EXCL + VP_STR_TO_OFLAG(O_EXCL); +#endif +#ifdef O_NONBLOCK + VP_STR_TO_OFLAG(O_NONBLOCK); +#endif +#ifdef O_SHLOCK + VP_STR_TO_OFLAG(O_SHLOCK); +#endif +#ifdef O_EXLOCK + VP_STR_TO_OFLAG(O_EXLOCK); +#endif +#ifdef O_DIRECT + VP_STR_TO_OFLAG(O_DIRECT); +#endif +#ifdef O_FSYNC + VP_STR_TO_OFLAG(O_FSYNC); +#endif +#ifdef O_NOFOLLOW + VP_STR_TO_OFLAG(O_NOFOLLOW); +#endif +#ifdef O_TEMPORARY + VP_STR_TO_OFLAG(O_TEMPORARY); +#endif +#ifdef O_RANDOM + VP_STR_TO_OFLAG(O_RANDOM); +#endif +#ifdef O_SEQUENTIAL + VP_STR_TO_OFLAG(O_SEQUENTIAL); +#endif +#ifdef O_BINARY + VP_STR_TO_OFLAG(O_BINARY); +#endif +#ifdef O_TEXT + VP_STR_TO_OFLAG(O_TEXT); +#endif +#ifdef O_INHERIT + VP_STR_TO_OFLAG(O_INHERIT); +#endif +#ifdef _O_SHORT_LIVED + VP_STR_TO_OFLAG(O_SHORT_LIVED); +#endif + +#undef VP_STR_TO_OFLAG + } + + return oflag; +} + +static int +fd_set_nonblock(int fd) +{ +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + int flag; + + if ((flag = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + if (!(flag & O_NONBLOCK)) + return fcntl(fd, F_SETFL, flag | O_NONBLOCK); +#endif + return 0; +} +#ifdef __linux__ +# define VP_SET_NONBLOCK_IF_NEEDED(_fd) (void)fd_set_nonblock(_fd) +#else +# define VP_SET_NONBLOCK_IF_NEEDED(_fd) do { /* nop */ } while (0) +#endif + +const char * +vp_fd_read(char *args, int is_pty_pipe) +{ +#ifdef __linux__ +# define VP_POLLIN (POLLIN | POLLHUP) +#else +# define VP_POLLIN (POLLIN) +#endif + vp_stack_t stack; + int fd; + int cnt; + int timeout; + int n; + char *buf; + char *eof; + unsigned int size = 0; + struct pollfd pfd = {0, POLLIN, 0}; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &cnt)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + + if (cnt < 0 || VP_READ_BUFSIZE < cnt) { + cnt = VP_READ_BUFSIZE; + } + + /* initialize buffer */ + _result.top = _result.buf; + vp_stack_push_num(&_result, "%d", 0); /* set eof to 0 */ + eof = _result.top - 1; + buf = _result.top; + *(buf++) = VP_EOV; + buf += VP_HEADER_SIZE; + + pfd.fd = fd; + while (cnt > 0) { + n = poll(&pfd, 1, timeout); + if (n == -1) { + /* eof or error */ + *eof = '1'; + break; + } else if (n == 0) { + /* timeout */ + break; + } + if (pfd.revents & VP_POLLIN) { + n = read(fd, buf, cnt); + if (n == -1) { + if (pfd.revents & POLLERR + || pfd.revents & POLLNVAL + || pfd.revents & POLLWRNORM + /* Cygwin(after ver.2.0) fails pty read and returns + * POLLIN. */ + || (!is_pty_pipe && pfd.revents & POLLIN) + ) { + return vp_stack_return_error(&_result, + "read() error: revents = %d, error = %s", + pfd.revents, strerror(errno)); + } + /* eof */ + *eof = '1'; + break; + } else if (n == 0) { + /* eof */ + *eof = '1'; + break; + } + /* decrease stack top for concatenate. */ + cnt -= n; + buf += n; + size += n; + /* try read more bytes without waiting */ + timeout = 0; + continue; + } else if (pfd.revents & (POLLERR | POLLHUP)) { + /* eof or error */ + *eof = '1'; + break; + } else if (pfd.revents & POLLNVAL) { + return vp_stack_return_error(&_result, "poll() POLLNVAL: %d", + pfd.revents); + } + /* DO NOT REACH HERE */ + return vp_stack_return_error(&_result, "poll() unknown status: %d", + pfd.revents); + } + vp_encode_size(size, _result.top + 1); + _result.top = buf; + return vp_stack_return(&_result); +#undef VP_POLLIN +} + +const char * +vp_file_open(char *args) +{ + vp_stack_t stack; + char *path; + char *flags; + int mode; /* used when flags have O_CREAT */ + int oflag = 0; + int fd; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &flags)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &mode)); + + oflag = str_to_oflag(flags); + if (oflag == -1) + return vp_stack_return_error(&_result, "open flag error."); + + fd = open(path, oflag, mode); + if (fd == -1) + return vp_stack_return_error(&_result, "open() error: %s", + strerror(errno)); + vp_stack_push_num(&_result, "%d", fd); + return vp_stack_return(&_result); +} + +const char * +vp_file_close(char *args) +{ + vp_stack_t stack; + int fd; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + + if (close(fd) == -1) + return vp_stack_return_error(&_result, "close() error: %s", + strerror(errno)); + return NULL; +} + +const char * +vp_file_read(char *args) +{ + return vp_fd_read(args, 0); +} + +const char * +vp_file_write(char *args) +{ + vp_stack_t stack; + int fd; + char *buf; + size_t size; + int timeout; + size_t nleft; + int n; + struct pollfd pfd = {0, POLLOUT, 0}; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + + size = vp_decode_size(stack.top); + buf = stack.top + VP_HEADER_SIZE; + + pfd.fd = fd; + nleft = 0; + while (nleft < size) { + n = poll(&pfd, 1, timeout); + if (n == -1) { + return vp_stack_return_error(&_result, "poll() error: %s", + strerror(errno)); + } else if (n == 0) { + /* timeout */ + break; + } + if (pfd.revents & POLLOUT) { + n = write(fd, buf + nleft, size - nleft); + if (n == -1) { + return vp_stack_return_error(&_result, "write() error: %s", + strerror(errno)); + } + nleft += n; + /* try write more bytes without waiting */ + timeout = 0; + continue; + } else if (pfd.revents & (POLLERR | POLLHUP)) { + /* eof or error */ + break; + } else if (pfd.revents & POLLNVAL) { + return vp_stack_return_error(&_result, "poll() POLLNVAL: %d", + pfd.revents); + } + /* DO NOT REACH HERE */ + return vp_stack_return_error(&_result, "poll() unknown status: %s", + pfd.revents); + } + vp_stack_push_num(&_result, "%zu", nleft); + return vp_stack_return(&_result); +} + +static void +close_allfd(int fds[3][2]) +{ + int i; + + for (i = 0; i < 6; ++i) { + int fd = fds[i / 2][i % 2]; + + if (fd > 0) { + (void)close(fd); + } + } +} + +const char * +vp_pipe_open(char *args) +{ +#define VP_GOTO_ERROR(_fmt) do { errfmt = (_fmt); goto error; } while(0) + vp_stack_t stack; + int npipe, hstdin, hstderr, hstdout; + int argc; + int fd[3][2] = {{0}}; + pid_t pid; + int dummy; + char *errfmt; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &npipe)); + if (npipe != 2 && npipe != 3) + return vp_stack_return_error(&_result, "npipe range error. wrong pipes."); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdin)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdout)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstderr)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &argc)); + + if (hstdin > 0) { + fd[0][0] = hstdin; + fd[0][1] = 0; + } else { + if (pipe(fd[0]) < 0) { + VP_GOTO_ERROR("pipe() error: %s"); + } + } + if (hstdout > 0) { + fd[1][1] = hstdout; + fd[1][0] = 0; + } else { + if (pipe(fd[1]) < 0) { + VP_GOTO_ERROR("pipe() error: %s"); + } + } + if (hstderr > 0) { + fd[2][1] = hstderr; + fd[2][0] = 0; + } else if (npipe == 3 && hstderr == 0) { + if (pipe(fd[2]) < 0) { + VP_GOTO_ERROR("pipe() error: %s"); + } + } + + pid = fork(); + if (pid < 0) { + VP_GOTO_ERROR("fork() error: %s"); + } else if (pid == 0) { + /* child */ + char **argv; + int i; + + /* Set process group. */ + setpgid(0, 0); + + if (fd[0][1] > 0) { + close(fd[0][1]); + } + if (fd[1][0] > 0) { + close(fd[1][0]); + } + if (fd[2][0] > 0) { + close(fd[2][0]); + } + if (fd[0][0] > 0) { + if (dup2(fd[0][0], STDIN_FILENO) != STDIN_FILENO) { + goto child_error; + } + close(fd[0][0]); + } + if (fd[1][1] > 0) { + if (dup2(fd[1][1], STDOUT_FILENO) != STDOUT_FILENO) { + goto child_error; + } + close(fd[1][1]); + } + if (fd[2][1] > 0) { + if (dup2(fd[2][1], STDERR_FILENO) != STDERR_FILENO) { + goto child_error; + } + close(fd[2][1]); + } else if (npipe == 2) { + if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) { + goto child_error; + } + } + + { +#ifndef TIOCNOTTY + setsid(); +#else + /* Ignore tty. */ + char name[L_ctermid]; + if (ctermid(name)[0] != '\0') { + int tfd; + if ((tfd = open(name, O_RDONLY)) != -1) { + ioctl(tfd, TIOCNOTTY, NULL); + close(tfd); + } + } +#endif + } + + argv = malloc(sizeof(char *) * (argc+1)); + if (argv == NULL) { + goto child_error; + } + for (i = 0; i < argc; ++i) { + if (vp_stack_pop_str(&stack, &(argv[i]))) { + free(argv); + goto child_error; + } + } + argv[argc] = NULL; + + execv(argv[0], argv); + /* error */ + goto child_error; + } else { + /* parent */ + if (fd[0][0] > 0) { + close(fd[0][0]); + } + if (fd[1][1] > 0) { + close(fd[1][1]); + } + if (fd[2][1] > 0) { + close(fd[2][1]); + } + + vp_stack_push_num(&_result, "%d", pid); + vp_stack_push_num(&_result, "%d", fd[0][1]); + vp_stack_push_num(&_result, "%d", fd[1][0]); + if (npipe == 3) { + vp_stack_push_num(&_result, "%d", fd[2][0]); + } + return vp_stack_return(&_result); + } + /* DO NOT REACH HERE */ + return NULL; + + /* error */ +error: + close_allfd(fd); + return vp_stack_return_error(&_result, errfmt, strerror(errno)); + +child_error: + dummy = write(STDOUT_FILENO, strerror(errno), strlen(strerror(errno))); + _exit(EXIT_FAILURE); +#undef VP_GOTO_ERROR +} + +const char * +vp_pipe_close(char *args) +{ + return vp_file_close(args); +} + +const char * +vp_pipe_read(char *args) +{ + return vp_fd_read(args, 1); +} + +const char * +vp_pipe_write(char *args) +{ + return vp_file_write(args); +} + +const char * +vp_pty_open(char *args) +{ +#define VP_GOTO_ERROR(_fmt) do { errfmt = (_fmt); goto error; } while(0) + vp_stack_t stack; + int argc; + int fd[3][2] = {{0}}; + pid_t pid; + struct winsize ws = {0, 0, 0, 0}; + int dummy; + int hstdin, hstderr, hstdout; + int fdm; + int npipe; + char *errfmt; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &npipe)); + if (npipe != 2 && npipe != 3) + return vp_stack_return_error(&_result, "npipe range error. wrong pipes."); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_col))); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_row))); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdin)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdout)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstderr)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &argc)); + + /* Set pipe */ + if (hstdin > 0) { + fd[0][0] = hstdin; + fd[0][1] = 0; + } + if (hstdout > 1) { + fd[1][1] = hstdout; + fd[1][0] = 0; + } else if (hstdout == 1) { + if (pipe(fd[1]) < 0) { + VP_GOTO_ERROR("pipe() error: %s"); + } + } + if (hstderr > 1) { + fd[2][1] = hstderr; + fd[2][0] = 0; + } else if (npipe == 3) { + if (hstderr == 1){ + if (pipe(fd[2]) < 0) { + VP_GOTO_ERROR("pipe() error: %s"); + } + } else if (hstderr == 0) { + if (openpty(&fd[2][0], &fd[2][1], NULL, NULL, &ws) < 0) { + VP_GOTO_ERROR("openpty() error: %s"); + } + VP_SET_NONBLOCK_IF_NEEDED(fd[2][0]); + } + } + + pid = forkpty(&fdm, NULL, NULL, &ws); + if (pid < 0) { + VP_GOTO_ERROR("fork() error: %s"); + } else if (pid == 0) { + /* child */ + char **argv; + int i; + + /* Close pipe */ + if (fd[1][0] > 0) { + close(fd[1][0]); + } + if (fd[2][0] > 0) { + close(fd[2][0]); + } + + if (fd[0][0] > 0) { + if (dup2(fd[0][0], STDIN_FILENO) != STDIN_FILENO) { + goto child_error; + } + close(fd[0][0]); + } + + if (fd[1][1] > 0) { + if (dup2(fd[1][1], STDOUT_FILENO) != STDOUT_FILENO) { + goto child_error; + } + close(fd[1][1]); + } + + if (fd[2][1] > 0) { + if (dup2(fd[2][1], STDERR_FILENO) != STDERR_FILENO) { + goto child_error; + } + close(fd[2][1]); + } + + argv = malloc(sizeof(char *) * (argc+1)); + if (argv == NULL) { + goto child_error; + } + for (i = 0; i < argc; ++i) { + if (vp_stack_pop_str(&stack, &(argv[i]))) { + free(argv); + goto child_error; + } + } + argv[argc] = NULL; + + execv(argv[0], argv); + /* error */ + goto child_error; + } else { + /* parent */ + if (fd[1][1] > 0) { + close(fd[1][1]); + } + if (fd[2][1] > 0) { + close(fd[2][1]); + } + + if (hstdin == 0) { + fd[0][1] = fdm; + } + if (hstdout == 0) { + fd[1][0] = hstdin == 0 ? dup(fdm) : fdm; + VP_SET_NONBLOCK_IF_NEEDED(fd[1][0]); + } + + vp_stack_push_num(&_result, "%d", pid); + vp_stack_push_num(&_result, "%d", fd[0][1]); + vp_stack_push_num(&_result, "%d", fd[1][0]); + if (npipe == 3) { + vp_stack_push_num(&_result, "%d", fd[2][0]); + } + return vp_stack_return(&_result); + } + /* DO NOT REACH HERE */ + return NULL; + + /* error */ +error: + close_allfd(fd); + return vp_stack_return_error(&_result, errfmt, strerror(errno)); + +child_error: + dummy = write(STDOUT_FILENO, strerror(errno), strlen(strerror(errno))); + _exit(EXIT_FAILURE); +#undef VP_GOTO_ERROR +} + +const char * +vp_pty_close(char *args) +{ + return vp_file_close(args); +} + +const char * +vp_pty_read(char *args) +{ + return vp_fd_read(args, 1); +} + +const char * +vp_pty_write(char *args) +{ + return vp_file_write(args); +} + +const char * +vp_pty_get_winsize(char *args) +{ + vp_stack_t stack; + int fd; + struct winsize ws = {0, 0, 0, 0}; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + + if (ioctl(fd, TIOCGWINSZ, &ws) < 0) + return vp_stack_return_error(&_result, "ioctl() error: %s", + strerror(errno)); + vp_stack_push_num(&_result, "%hu", ws.ws_col); + vp_stack_push_num(&_result, "%hu", ws.ws_row); + return vp_stack_return(&_result); +} +const char * +vp_pty_set_winsize(char *args) +{ + vp_stack_t stack; + int fd; + struct winsize ws = {0, 0, 0, 0}; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_col))); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_row))); + + if (ioctl(fd, TIOCSWINSZ, &ws) < 0) + return vp_stack_return_error(&_result, "ioctl() error: %s", + strerror(errno)); + return NULL; +} + +const char * +vp_kill(char *args) +{ + vp_stack_t stack; + pid_t pid, pgid; + int sig; + int ret; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &pid)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &sig)); + + ret = kill(pid, sig); + if (ret < 0) + return vp_stack_return_error(&_result, "kill() error: %s", + strerror(errno)); + + if (sig != 0) { + /* Kill by the process group. */ + pgid = getpgid(pid); + if (pid == pgid) { + kill(-pgid, sig); + } + } + + vp_stack_push_num(&_result, "%d", ret); + return vp_stack_return(&_result); +} + +const char * +vp_waitpid(char *args) +{ + vp_stack_t stack; + pid_t pid, pgid; + pid_t n; + int status; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &pid)); + + n = waitpid(pid, &status, WNOHANG | WUNTRACED); + if (n == -1) + return vp_stack_return_error(&_result, "waitpid() error: %s", + strerror(errno)); + if (n == 0 || WIFCONTINUED(status)) { + vp_stack_push_str(&_result, "run"); + vp_stack_push_num(&_result, "%d", 0); + } else if (WIFEXITED(status)) { + /* Kill by the process group. */ + pgid = getpgid(pid); + if (pgid > 0) { + kill(-pgid, 15); + } + + vp_stack_push_str(&_result, "exit"); + vp_stack_push_num(&_result, "%d", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + vp_stack_push_str(&_result, "signal"); + vp_stack_push_num(&_result, "%d", WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + vp_stack_push_str(&_result, "stop"); + vp_stack_push_num(&_result, "%d", WSTOPSIG(status)); + } else { + return vp_stack_return_error(&_result, + "waitpid() unknown status: status=%d", status); + } + + return vp_stack_return(&_result); +} + +/* + * This is based on socket.diff.gz written by Yasuhiro Matsumoto. + * see: http://marc.theaimsgroup.com/?l=vim-dev&m=105289857008664&w=2 + */ +const char * +vp_socket_open(char *args) +{ + vp_stack_t stack; + char *host; + char *port; + char *p; + int n; + unsigned short nport; + int sock; + struct sockaddr_in sockaddr; + struct hostent *hostent; + struct servent *servent; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &port)); + + n = strtol(port, &p, 10); + if (p == port + strlen(port)) { + nport = htons(n); + } else { + servent = getservbyname(port, NULL); + if (servent == NULL) + return vp_stack_return_error(&_result, "getservbyname() error: %s", + port); + nport = servent->s_port; + } + + sock = socket(PF_INET, SOCK_STREAM, 0); + hostent = gethostbyname(host); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = nport; + sockaddr.sin_addr = *((struct in_addr*)*hostent->h_addr_list); + + if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in)) + == -1) + return vp_stack_return_error(&_result, "connect() error: %s", + strerror(errno)); + + vp_stack_push_num(&_result, "%d", sock); + return vp_stack_return(&_result); +} + +const char * +vp_socket_close(char *args) +{ + return vp_file_close(args); +} + +const char * +vp_socket_read(char *args) +{ + return vp_fd_read(args, 0); +} + +const char * +vp_socket_write(char *args) +{ + return vp_file_write(args); +} + +/* + * Added by Richard Emberson + * Check to see if a host exists. + */ +const char * +vp_host_exists(char *args) +{ + vp_stack_t stack; + char *host; + struct hostent *hostent; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); + + hostent = gethostbyname(host); + if (hostent) { + vp_stack_push_num(&_result, "%d", 1); + } else { + vp_stack_push_num(&_result, "%d", 0); + } + + return vp_stack_return(&_result); +} + +const char * +vp_readdir(char *args) +{ + vp_stack_t stack; + char *dirname; + char buf[1024]; + + DIR *dir; + struct dirent *dp; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &dirname)); + + if ((dir=opendir(dirname)) == NULL) { + return vp_stack_return_error(&_result, "opendir() error: %s", + strerror(errno)); + } + + if (strcmp(dirname, "/") == 0) { + dirname[0] = '\0'; + } + + for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { + if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { + snprintf(buf, sizeof(buf), "%s/%s", dirname, dp->d_name); + vp_stack_push_str(&_result, buf); + } + } + closedir(dir); + + return vp_stack_return(&_result); +} + +const char * +vp_decode(char *args) +{ + vp_stack_t stack; + size_t len; + char *str; + char *p, *q; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &str)); + + len = strlen(str); + if (len % 2 != 0) { + return "vp_decode: invalid data length"; + } + + VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, + (_result.top - _result.buf) + (len / 2) + sizeof(VP_EOV_STR))); + + for (p = str, q = _result.top; p < str + len; ) { + char hb, lb; + + hb = CHR2XD[(int)*(p++)]; + lb = CHR2XD[(int)*(p++)]; + if (hb != (char)-1 && lb != (char)-1) { + *(q++) = (hb << 4) | lb; + } + } + *(q++) = VP_EOV; + *q = '\0'; + _result.top = q; + + return vp_stack_return(&_result); +} + +const char * +vp_get_signals(char *args) +{ +#define VP_STACK_PUSH_SIGNAME(_signame) \ + vp_stack_push_num(&_result, #_signame ":%d", (_signame)) +#define VP_STACK_PUSH_ALTSIGNAME(_signame, _altsig) \ + vp_stack_push_num(&_result, #_signame ":%d", (_altsig)) + +#ifdef SIGABRT + VP_STACK_PUSH_SIGNAME(SIGABRT); +#else +#error "SIGABRT is undefined, contrary to ISO C standard." +#endif +#ifdef SIGFPE + VP_STACK_PUSH_SIGNAME(SIGFPE); +#else +#error "SIGFPE is undefined, contrary to ISO C standard." +#endif +#ifdef SIGILL + VP_STACK_PUSH_SIGNAME(SIGILL); +#else +#error "SIGILL is undefined, contrary to ISO C standard." +#endif +#ifdef SIGINT + VP_STACK_PUSH_SIGNAME(SIGINT); +#else +#error "SIGINT is undefined, contrary to ISO C standard." +#endif +#ifdef SIGSEGV + VP_STACK_PUSH_SIGNAME(SIGSEGV); +#else +#error "SIGSEGV is undefined, contrary to ISO C standard." +#endif +#ifdef SIGTERM + VP_STACK_PUSH_SIGNAME(SIGTERM); +#else +#error "SIGTERM is undefined, contrary to ISO C standard." +#endif +#ifdef SIGALRM + VP_STACK_PUSH_SIGNAME(SIGALRM); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGALRM, SIGTERM); +#endif +#ifdef SIGBUS + VP_STACK_PUSH_SIGNAME(SIGBUS); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGBUS, SIGABRT); +#endif +#ifdef SIGCHLD + VP_STACK_PUSH_SIGNAME(SIGCHLD); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGCHLD, 0); +#endif +#ifdef SIGCONT + VP_STACK_PUSH_SIGNAME(SIGCONT); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGCONT, 0); +#endif +#ifdef SIGHUP + VP_STACK_PUSH_SIGNAME(SIGHUP); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGHUP, SIGTERM); +#endif +#ifdef SIGKILL + VP_STACK_PUSH_SIGNAME(SIGKILL); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGKILL, SIGTERM); +#endif +#ifdef SIGPIPE + VP_STACK_PUSH_SIGNAME(SIGPIPE); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGPIPE, SIGTERM); +#endif +#ifdef SIGQUIT + VP_STACK_PUSH_SIGNAME(SIGQUIT); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGQUIT, SIGTERM); +#endif +#ifdef SIGSTOP + VP_STACK_PUSH_SIGNAME(SIGSTOP); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGSTOP, 0); +#endif +#ifdef SIGTSTP + VP_STACK_PUSH_SIGNAME(SIGTSTP); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGTSTP, 0); +#endif +#ifdef SIGTTIN + VP_STACK_PUSH_SIGNAME(SIGTTIN); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGTTIN, 0); +#endif +#ifdef SIGTTOU + VP_STACK_PUSH_SIGNAME(SIGTTOU); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGTTOU, 0); +#endif +#ifdef SIGUSR1 + VP_STACK_PUSH_SIGNAME(SIGUSR1); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGUSR1, SIGTERM); +#endif +#ifdef SIGUSR2 + VP_STACK_PUSH_SIGNAME(SIGUSR2); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGUSR2, SIGTERM); +#endif +#ifdef SIGPOLL + VP_STACK_PUSH_SIGNAME(SIGPOLL); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGPOLL, SIGTERM); +#endif +#ifdef SIGPROF + VP_STACK_PUSH_SIGNAME(SIGPROF); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGPROF, SIGTERM); +#endif +#ifdef SIGSYS + VP_STACK_PUSH_SIGNAME(SIGSYS); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGSYS, SIGABRT); +#endif +#ifdef SIGTRAP + VP_STACK_PUSH_SIGNAME(SIGTRAP); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGTRAP, SIGABRT); +#endif +#ifdef SIGURG + VP_STACK_PUSH_SIGNAME(SIGURG); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGURG, 0); +#endif +#ifdef SIGVTALRM + VP_STACK_PUSH_SIGNAME(SIGVTALRM); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGVTALRM, SIGTERM); +#endif +#ifdef SIGXCPU + VP_STACK_PUSH_SIGNAME(SIGXCPU); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGXCPU, SIGABRT); +#endif +#ifdef SIGXFSZ + VP_STACK_PUSH_SIGNAME(SIGXFSZ); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGXFSZ, SIGABRT); +#endif +#ifdef SIGEMT + VP_STACK_PUSH_SIGNAME(SIGEMT); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGEMT, SIGTERM); +#endif +#ifdef SIGWINCH + VP_STACK_PUSH_SIGNAME(SIGWINCH); +#else + VP_STACK_PUSH_ALTSIGNAME(SIGWINCH, 0); +#endif + return vp_stack_return(&_result); + +#undef VP_STACK_PUSH_SIGNAME +#undef VP_STACK_PUSH_ALTSIGNAME +} + +/* + * vim:set sw=4 sts=4 et: + */ diff --git a/bundle/vimproc.vim/src/proc_w32.c b/bundle/vimproc.vim/src/proc_w32.c new file mode 100644 index 000000000..56c673f8e --- /dev/null +++ b/bundle/vimproc.vim/src/proc_w32.c @@ -0,0 +1,1294 @@ +/*----------------------------------------------------------------------------- + * Copyright (c) 2006 Yukihiro Nakadaira - original version(vimproc) + * Copyright (c) 2009 Shougo Matsushita - modified version + * + * License: MIT license + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* For GetConsoleWindow() for Windows 2000 or later. */ +#ifndef WINVER +#define WINVER 0x0500 +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include +#include +#include +#if 0 +# include +#endif +#define _POSIX_ +#include +#include + +const int debug = 0; + +#ifdef _MSC_VER +# define EXPORT __declspec(dllexport) +#else +# define EXPORT +#endif + +#ifdef _MSC_VER +# if _MSC_VER < 1900 +# define snprintf _snprintf +# endif +# if _MSC_VER < 1400 +# define vsnprintf _vsnprintf +# endif +#endif + +#include "vimstack.c" + +#define lengthof(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* API */ +EXPORT const char *vp_dlopen(char *args); /* [handle] (path) */ +EXPORT const char *vp_dlclose(char *args); /* [] (handle) */ +EXPORT const char *vp_dlversion(char *args); /* [version] () */ + +EXPORT const char *vp_file_open(char *args); /* [fd] (path, flags, mode) */ +EXPORT const char *vp_file_close(char *args); /* [] (fd) */ +EXPORT const char *vp_file_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +EXPORT const char *vp_file_write(char *args); /* [nleft] (fd, timeout, hd) */ + +EXPORT const char *vp_pipe_open(char *args); /* [pid, [fd] * npipe] + (npipe, argc, [argv]) */ +EXPORT const char *vp_pipe_close(char *args); /* [] (fd) */ +EXPORT const char *vp_pipe_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +EXPORT const char *vp_pipe_write(char *args); /* [nleft] (fd, timeout, hd) */ + +EXPORT const char *vp_pty_open(char *args); /* [pid, fd, ttyname] + (width, height, argc, [argv]) */ +EXPORT const char *vp_pty_close(char *args); /* [] (fd) */ +EXPORT const char *vp_pty_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ +EXPORT const char *vp_pty_write(char *args); /* [nleft] (fd, timeout, hd) */ +EXPORT const char *vp_pty_get_winsize(char *args); /* [width, height] (fd) */ +EXPORT const char *vp_pty_set_winsize(char *args); /* [] (fd, width, height) */ + +EXPORT const char *vp_kill(char *args); /* [] (pid, sig) */ +EXPORT const char *vp_waitpid(char *args); /* [cond, status] (pid) */ +EXPORT const char *vp_close_handle(char *args); /* [] (fd) */ + +EXPORT const char *vp_socket_open(char *args); /* [socket] (host, port) */ +EXPORT const char *vp_socket_close(char *args);/* [] (socket) */ +EXPORT const char *vp_socket_read(char *args); /* [eof, hd] (socket, cnt, timeout) */ +EXPORT const char *vp_socket_write(char *args);/* [nleft] (socket, hd, timeout) */ + +EXPORT const char *vp_host_exists(char *args); /* [int] (host) */ + +EXPORT const char *vp_decode(char *args); /* [decoded_str] (encode_str) */ + +EXPORT const char *vp_open(char *args); /* [] (path) */ +EXPORT const char *vp_readdir(char *args); /* [files] (dirname) */ + + +EXPORT const char * vp_delete_trash(char *args); /* [int] (filename) */ + +EXPORT const char *vp_get_signals(char *args); /* [signals] () */ + +static BOOL ExitRemoteProcess(HANDLE hProcess, UINT_PTR uExitCode); + +/* --- */ + +#define VP_BUFSIZE (65536) +#define VP_READ_BUFSIZE (VP_BUFSIZE - (VP_HEADER_SIZE + 1) * 2 - 1) + +static LPWSTR +utf8_to_utf16(const char *str) +{ + LPWSTR buf; + int len; + + len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if (len == 0) + return NULL; + buf = malloc(sizeof(WCHAR) * (len + 1)); + if (buf == NULL) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len); + buf[len] = 0; + return buf; +} + +static char * +utf16_to_utf8(LPCWSTR wstr) +{ + char *buf; + int len; + + len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + if (len == 0) + return NULL; + buf = malloc(sizeof(char) * (len + 1)); + if (buf == NULL) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buf, len, NULL, NULL); + buf[len] = 0; + return buf; +} + +static const char * +lasterror() +{ + static char lpMsgBuf[512]; + WCHAR buf[512]; + char *p; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), 0, + buf, lengthof(buf), NULL); + p = utf16_to_utf8(buf); + if (p == NULL) + return NULL; + lstrcpyn(lpMsgBuf, p, lengthof(lpMsgBuf)); + free(p); + return lpMsgBuf; +} + +#define open _open +#define close _close +#define read _read +#define write _write +#define lseek _lseek + +static vp_stack_t _result = VP_STACK_NULL; + +const char * +vp_dlopen(char *args) +{ + vp_stack_t stack; + char *path; + LPWSTR pathw; + HINSTANCE handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); + VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, VP_BUFSIZE)); + + pathw = utf8_to_utf16(path); + if (pathw == NULL) + return lasterror(); + handle = LoadLibraryW(pathw); + free(pathw); + if (handle == NULL) + return lasterror(); + vp_stack_push_num(&_result, "%p", handle); + return vp_stack_return(&_result); +} + +const char * +vp_dlclose(char *args) +{ + vp_stack_t stack; + HINSTANCE handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); + + if (!FreeLibrary(handle)) + return lasterror(); + vp_stack_free(&_result); + return NULL; +} + +const char * +vp_dlversion(char *args) +{ + vp_stack_push_num(&_result, "%2d%02d", 9, 3); + return vp_stack_return(&_result); +} + +static int +str_to_oflag(const char *flags) +{ + int oflag = 0; + + if (strchr("rwa", flags[0])) { + if (strchr(flags, '+')) { + oflag = _O_RDWR; + } else { + oflag = flags[0] == 'r' ? _O_RDONLY : _O_WRONLY; + } + if (flags[0] == 'w' || flags[0] == 'a') { + oflag |= _O_CREAT | (flags[0] == 'w' ? _O_TRUNC : _O_APPEND); + } +#define VP_CHR_TO_OFLAG(_c, _f) do { \ + if (strchr(flags, (_c))) { oflag |= _ ## _f; } \ +} while (0) + +#ifdef _O_EXCL + VP_CHR_TO_OFLAG('x', O_EXCL); +#endif +#ifdef _O_CLOEXEC + VP_CHR_TO_OFLAG('e', O_CLOEXEC); +#endif +#ifdef _O_BINARY + VP_CHR_TO_OFLAG('b', O_BINARY); +#endif +#ifdef _O_TEXT + VP_CHR_TO_OFLAG('t', O_TEXT); +#endif +#ifdef _O_SEQUENTIAL + VP_CHR_TO_OFLAG('S', O_SEQUENTIAL); +#endif +#ifdef _O_RANDOM + VP_CHR_TO_OFLAG('R', O_RANDOM); +#endif + +#undef VP_CHR_TO_OFLAG + } else { + if (strstr(flags, "O_RDONLY")) { + oflag = _O_RDONLY; + } else if (strstr(flags, "O_WRONLY")) { + oflag = _O_WRONLY; + } else if (strstr(flags, "O_RDWR")) { + oflag = _O_RDWR; + } else { + return -1; + } +#define VP_STR_TO_OFLAG(_f) do { \ + if (strstr(flags, #_f)) { oflag |= _ ## _f; } \ +} while (0) + + VP_STR_TO_OFLAG(O_APPEND); + VP_STR_TO_OFLAG(O_CREAT); + VP_STR_TO_OFLAG(O_TRUNC); +#ifdef _O_EXCL + VP_STR_TO_OFLAG(O_EXCL); +#endif +#ifdef _O_NONBLOCK + VP_STR_TO_OFLAG(O_NONBLOCK); +#endif +#ifdef _O_SHLOCK + VP_STR_TO_OFLAG(O_SHLOCK); +#endif +#ifdef _O_EXLOCK + VP_STR_TO_OFLAG(O_EXLOCK); +#endif +#ifdef _O_DIRECT + VP_STR_TO_OFLAG(O_DIRECT); +#endif +#ifdef _O_FSYNC + VP_STR_TO_OFLAG(O_FSYNC); +#endif +#ifdef _O_NOFOLLOW + VP_STR_TO_OFLAG(O_NOFOLLOW); +#endif +#ifdef _O_TEMPORARY + VP_STR_TO_OFLAG(O_TEMPORARY); +#endif +#ifdef _O_RANDOM + VP_STR_TO_OFLAG(O_RANDOM); +#endif +#ifdef _O_SEQUENTIAL + VP_STR_TO_OFLAG(O_SEQUENTIAL); +#endif +#ifdef _O_BINARY + VP_STR_TO_OFLAG(O_BINARY); +#endif +#ifdef _O_TEXT + VP_STR_TO_OFLAG(O_TEXT); +#endif +#ifdef _O_INHERIT + VP_STR_TO_OFLAG(O_INHERIT); +#endif +#ifdef _O_SHORT_LIVED + VP_STR_TO_OFLAG(O_SHORT_LIVED); +#endif + +#undef VP_STR_TO_OFLAG + } + + return oflag; +} + +const char * +vp_file_open(char *args) +{ + vp_stack_t stack; + char *path; + LPWSTR pathw; + char *flags; + int mode; /* used when flags have O_CREAT */ + int oflag = 0; + int fd; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &flags)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &mode)); + + oflag = str_to_oflag(flags); + if (oflag == -1) + return vp_stack_return_error(&_result, "open flag error."); + + pathw = utf8_to_utf16(path); + if (pathw == NULL) + return lasterror(); + + fd = _wopen(pathw, oflag, mode); + free(pathw); + if (fd == -1) { + return vp_stack_return_error(&_result, "open() error: %s", + strerror(errno)); + } + if (oflag & O_APPEND) { + /* Note: Windows7 ignores O_APPEND flag. why? */ + lseek(fd, 0, SEEK_END); + } + vp_stack_push_num(&_result, "%d", fd); + return vp_stack_return(&_result); +} + +const char * +vp_file_close(char *args) +{ + vp_stack_t stack; + int fd; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + + if (close(fd) == -1) + return vp_stack_return_error(&_result, "close() error: %s", + strerror(errno)); + return NULL; +} + +const char * +vp_file_read(char *args) +{ + vp_stack_t stack; + int fd; + int cnt; + int timeout; + DWORD ret; + int n; + char *buf; + char *eof; + unsigned int size = 0; + HANDLE hFile; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &cnt)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + + if (cnt < 0 || VP_READ_BUFSIZE < cnt) { + cnt = VP_READ_BUFSIZE; + } + + /* initialize buffer */ + _result.top = _result.buf; + vp_stack_push_num(&_result, "%d", 0); /* set eof to 0 */ + eof = _result.top - 1; + buf = _result.top; + *(buf++) = VP_EOV; + buf += VP_HEADER_SIZE; + + hFile = (HANDLE)_get_osfhandle(fd); + while (cnt > 0) { + ret = WaitForSingleObject(hFile, timeout); + if (ret == WAIT_FAILED) { + return vp_stack_return_error(&_result, "WaitForSingleObject() error: %s", + lasterror()); + } else if (ret == WAIT_TIMEOUT) { + /* timeout */ + break; + } + n = read(fd, buf, cnt); + if (n == -1) { + return vp_stack_return_error(&_result, "read() error: %s", + strerror(errno)); + } else if (n == 0) { + /* eof */ + *eof = '1'; + break; + } + /* decrease stack top for concatenate. */ + cnt -= n; + buf += n; + size += n; + /* try read more bytes without waiting */ + timeout = 0; + } + vp_encode_size(size, _result.top + 1); + _result.top = buf; + return vp_stack_return(&_result); +} + +const char * +vp_file_write(char *args) +{ + vp_stack_t stack; + int fd; + char *buf; + size_t size; + int timeout; + size_t nleft; + DWORD ret; + int n; + HANDLE hFile; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + + size = vp_decode_size(stack.top); + buf = stack.top + VP_HEADER_SIZE; + + nleft = 0; + hFile = (HANDLE)_get_osfhandle(fd); + while (nleft < size) { + ret = WaitForSingleObject(hFile, timeout); + if (ret == WAIT_FAILED) { + return vp_stack_return_error(&_result, "WaitForSingleObject() error: %s", + lasterror()); + } else if (ret == WAIT_TIMEOUT) { + /* timeout */ + break; + } + n = write(fd, buf + nleft, (unsigned int)(size - nleft)); + if (n == -1) { + return vp_stack_return_error(&_result, "write() error: %s", + strerror(errno)); + } + nleft += n; + /* try write more bytes without waiting */ + timeout = 0; + } + vp_stack_push_num(&_result, "%u", nleft); + return vp_stack_return(&_result); +} + +/* + * http://support.microsoft.com/kb/190351/ + */ +const char * +vp_pipe_open(char *args) +{ +#define VP_GOTO_ERROR(_fmt) do { errfmt = (_fmt); goto error; } while(0) +#define VP_DUP_HANDLE(hIn, phOut, inherit) \ + if (!DuplicateHandle(GetCurrentProcess(), hIn, \ + GetCurrentProcess(), phOut, \ + 0, inherit, DUPLICATE_SAME_ACCESS)) { \ + VP_GOTO_ERROR("DuplicateHandle() error: %s"); \ + } + vp_stack_t stack; + int npipe, hstdin, hstderr, hstdout; + char *errfmt; + const char *errmsg; + char *cmdline; + LPWSTR cmdlinew; + HANDLE hInputWrite = INVALID_HANDLE_VALUE, hInputRead = INVALID_HANDLE_VALUE; + HANDLE hOutputWrite = INVALID_HANDLE_VALUE, hOutputRead = INVALID_HANDLE_VALUE; + HANDLE hErrorWrite = INVALID_HANDLE_VALUE, hErrorRead = INVALID_HANDLE_VALUE; + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + BOOL ret; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &npipe)); + if (npipe != 2 && npipe != 3) + return vp_stack_return_error(&_result, "npipe range error"); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdin)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdout)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstderr)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &cmdline)); + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + if (hstdin) { + /* Get handle. */ + VP_DUP_HANDLE((HANDLE)_get_osfhandle(hstdin), &hInputRead, TRUE); + } else { + HANDLE hInputWriteTmp; + + /* Create pipe. */ + if (!CreatePipe(&hInputRead, &hInputWrite, &sa, 0)) + VP_GOTO_ERROR("CreatePipe() error: %s"); + + VP_DUP_HANDLE(hInputWrite, &hInputWriteTmp, FALSE); + CloseHandle(hInputWrite); + hInputWrite = hInputWriteTmp; + } + + if (hstdout) { + /* Get handle. */ + VP_DUP_HANDLE((HANDLE)_get_osfhandle(hstdout), &hOutputWrite, TRUE); + } else { + HANDLE hOutputReadTmp; + + /* Create pipe. */ + if (!CreatePipe(&hOutputRead, &hOutputWrite, &sa, 0)) + VP_GOTO_ERROR("CreatePipe() error: %s"); + + VP_DUP_HANDLE(hOutputRead, &hOutputReadTmp, FALSE); + CloseHandle(hOutputRead); + hOutputRead = hOutputReadTmp; + } + + if (npipe == 2) { + VP_DUP_HANDLE(hOutputWrite, &hErrorWrite, TRUE); + } else { + if (hstderr) { + /* Get handle. */ + VP_DUP_HANDLE((HANDLE)_get_osfhandle(hstderr), &hErrorWrite, TRUE); + } else { + HANDLE hErrorReadTmp; + + /* Create pipe. */ + if (!CreatePipe(&hErrorRead, &hErrorWrite, &sa, 0)) + VP_GOTO_ERROR("CreatePipe() error: %s"); + + VP_DUP_HANDLE(hErrorRead, &hErrorReadTmp, FALSE); + CloseHandle(hErrorRead); + hErrorRead = hErrorReadTmp; + } + } + + ZeroMemory(&si, sizeof(STARTUPINFOW)); + si.cb = sizeof(STARTUPINFOW); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOW; + si.hStdInput = hInputRead; + si.hStdOutput = hOutputWrite; + si.hStdError = hErrorWrite; + + cmdlinew = utf8_to_utf16(cmdline); + if (cmdlinew == NULL) + VP_GOTO_ERROR("utf8_to_utf16() error: %s"); + + ret = CreateProcessW(NULL, cmdlinew, NULL, NULL, TRUE, + CREATE_NO_WINDOW, NULL, NULL, &si, &pi); + free(cmdlinew); + if (!ret) + VP_GOTO_ERROR("CreateProcess() error: %s"); + + CloseHandle(pi.hThread); + + CloseHandle(hInputRead); + CloseHandle(hOutputWrite); + CloseHandle(hErrorWrite); + + vp_stack_push_num(&_result, "%p", pi.hProcess); + vp_stack_push_num(&_result, "%d", hstdin ? + 0 : _open_osfhandle((size_t)hInputWrite, 0)); + vp_stack_push_num(&_result, "%d", hstdout ? + 0 : _open_osfhandle((size_t)hOutputRead, _O_RDONLY)); + if (npipe == 3) + vp_stack_push_num(&_result, "%d", hstderr ? + 0 : _open_osfhandle((size_t)hErrorRead, _O_RDONLY)); + return vp_stack_return(&_result); + +error: + errmsg = lasterror(); + if (hInputWrite != INVALID_HANDLE_VALUE) CloseHandle(hInputWrite); + if (hInputRead != INVALID_HANDLE_VALUE) CloseHandle(hInputRead); + if (hOutputWrite != INVALID_HANDLE_VALUE) CloseHandle(hOutputWrite); + if (hOutputRead != INVALID_HANDLE_VALUE) CloseHandle(hOutputRead); + if (hErrorWrite != INVALID_HANDLE_VALUE) CloseHandle(hErrorWrite); + if (hErrorRead != INVALID_HANDLE_VALUE) CloseHandle(hErrorRead); + return vp_stack_return_error(&_result, errfmt, errmsg); +#undef VP_DUP_HANDLE +#undef VP_GOTO_ERROR +} + +const char * +vp_pipe_close(char *args) +{ + vp_stack_t stack; + int fd; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + + if (close(fd)) + return vp_stack_return_error(&_result, "close() error: %s", + lasterror()); + return NULL; +} + +const char * +vp_pipe_read(char *args) +{ + vp_stack_t stack; + int fd; + int cnt; + int timeout; + DWORD n; + DWORD err; + char *buf; + char *eof; + unsigned int size = 0; + HANDLE hPipe; + DWORD tcstart; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &cnt)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + + if (cnt < 0 || VP_READ_BUFSIZE < cnt) { + cnt = VP_READ_BUFSIZE; + } + + /* initialize buffer */ + _result.top = _result.buf; + vp_stack_push_num(&_result, "%d", 0); /* set eof to 0 */ + eof = _result.top - 1; + buf = _result.top; + *(buf++) = VP_EOV; + buf += VP_HEADER_SIZE; + + hPipe = (HANDLE)_get_osfhandle(fd); + tcstart = GetTickCount(); + while (cnt > 0) { + if (!PeekNamedPipe(hPipe, NULL, 0, NULL, &n, NULL)) { + /* can be ERROR_HANDLE_EOF? */ + err = GetLastError(); + if (err == 0 || err == ERROR_BROKEN_PIPE) { + /* error or eof */ + if (err == ERROR_BROKEN_PIPE) { + *eof = '1'; + } + break; + } + return vp_stack_return_error(&_result, "PeekNamedPipe() error: %08X %s", + err, lasterror()); + } else if (n == 0) { + if (GetTickCount() - tcstart >= timeout) { + break; + } + Sleep(1); + continue; + } + n = read(fd, buf, cnt); + if (n == -1) { + return vp_stack_return_error(&_result, "read() error: %s", + strerror(errno)); + } + /* decrease stack top for concatenate. */ + cnt -= n; + buf += n; + size += n; + /* try read more bytes without waiting */ + timeout = 0; + } + vp_encode_size(size, _result.top + 1); + _result.top = buf; + return vp_stack_return(&_result); +} + +const char * +vp_pipe_write(char *args) +{ + return vp_file_write(args); +} + +const char * +vp_pty_open(char *args) +{ + return "vp_pty_open() is not available"; +} + +const char * +vp_pty_close(char *args) +{ + return "vp_pty_close() is not available"; +} + +const char * +vp_pty_read(char *args) +{ + return "vp_pty_read() is not available"; +} + +const char * +vp_pty_write(char *args) +{ + return "vp_pty_write() is not available"; +} + +const char * +vp_pty_get_winsize(char *args) +{ + return "vp_pty_get_winsize() is not available"; +} + +const char * +vp_pty_set_winsize(char *args) +{ + return "vp_pty_set_winsize() is not available"; +} + +const char * +vp_kill(char *args) +{ + vp_stack_t stack; + HANDLE handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); + + /*if (!TerminateProcess(handle, 2) || !CloseHandle(handle))*/ + /*return vp_stack_return_error(&_result, "kill() error: %s",*/ + /*lasterror());*/ + if (!ExitRemoteProcess(handle, 2)) { + return vp_stack_return_error(&_result, "kill() error: %s", + lasterror()); + } + + vp_stack_push_num(&_result, "%d", 0); + return vp_stack_return(&_result); +} + +/* Improved kill function. */ +/* http://homepage3.nifty.com/k-takata/diary/2009-05.html */ +static BOOL ExitRemoteProcess(HANDLE hProcess, UINT_PTR uExitCode) +{ + LPTHREAD_START_ROUTINE pfnExitProcess = + (LPTHREAD_START_ROUTINE) GetProcAddress( + GetModuleHandle("kernel32.dll"), "ExitProcess"); + if ((hProcess != NULL) && (pfnExitProcess != NULL)) { + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, + pfnExitProcess, (LPVOID) uExitCode, 0, NULL); + if (hThread != NULL) { + CloseHandle(hThread); + return TRUE; + } + } + return FALSE; +} + +const char * +vp_waitpid(char *args) +{ + vp_stack_t stack; + HANDLE handle; + DWORD exitcode; + DWORD ret; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); + + ret = WaitForSingleObject(handle, 0); + if (ret == WAIT_OBJECT_0) { + /* The process has been exited. */ + if (!GetExitCodeProcess(handle, &exitcode)) { + return vp_stack_return_error(&_result, + "GetExitCodeProcess() error: %s", lasterror()); + } + } else if (ret == WAIT_TIMEOUT) { + exitcode = STILL_ACTIVE; + } else { + return vp_stack_return_error(&_result, + "WaitForSingleObject() error: %s", lasterror()); + } + + vp_stack_push_str(&_result, (ret == WAIT_TIMEOUT) ? "run" : "exit"); + vp_stack_push_num(&_result, "%u", exitcode); + return vp_stack_return(&_result); +} + +const char * +vp_close_handle(char *args) +{ + vp_stack_t stack; + HANDLE handle; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); + + if (!CloseHandle(handle)) { + return vp_stack_return_error(&_result, + "CloseHandle() error: %s", lasterror()); + } + return NULL; +} + +/* + * This is based on socket.diff.gz written by Yasuhiro Matsumoto. + * see: http://marc.theaimsgroup.com/?l=vim-dev&m=105289857008664&w=2 + */ +static int sockets_number = 0; + +static int +detain_winsock() +{ + WSADATA wsadata; + int res = 0; + + if (sockets_number == 0) { /* Need startup process. */ + res = WSAStartup(MAKEWORD(2, 0), &wsadata); + if(res) return res; /* Fail */ + } + ++sockets_number; + return res; +} + +static int +release_winsock() +{ + int res = 0; + + if (sockets_number != 0) { + res = WSACleanup(); + if(res) return res; /* Fail */ + + --sockets_number; + } + return res; +} + + +const char * +vp_socket_open(char *args) +{ + vp_stack_t stack; + char *host; + char *port; + int port_nr; + int n; + unsigned short nport; + int sock; + struct sockaddr_in sockaddr; + struct hostent *hostent; + struct servent *servent; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &port)); + + if (detain_winsock()) { + return vp_stack_return_error(&_result, "WSAStartup() error: %s", + lasterror()); + } + + if (sscanf(port, "%d%n", &port_nr, &n) == 1 && port[n] == '\0') { + nport = htons((u_short)port_nr); + } else { + servent = getservbyname(port, NULL); + if (servent == NULL) + return vp_stack_return_error(&_result, "getservbyname() error: %s", + port); + nport = servent->s_port; + } + + sock = (int)socket(PF_INET, SOCK_STREAM, 0); + hostent = gethostbyname(host); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = nport; + sockaddr.sin_addr = *((struct in_addr*)*hostent->h_addr_list); + + if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in)) + == -1) { + return vp_stack_return_error(&_result, "connect() error: %s", + strerror(errno)); + } + + vp_stack_push_num(&_result, "%d", sock); + return vp_stack_return(&_result); +} + +const char * +vp_socket_close(char *args) +{ + vp_stack_t stack; + int sock; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &sock)); + + if (closesocket(sock) == SOCKET_ERROR) { + return vp_stack_return_error(&_result, "closesocket() error: %d", + WSAGetLastError()); + } + release_winsock(); + return NULL; +} + +const char * +vp_socket_read(char *args) +{ + vp_stack_t stack; + int sock; + int cnt; + int timeout; + struct timeval tv; + int n; + char *buf; + char *eof; + unsigned int size = 0; + fd_set fdset; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &sock)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &cnt)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000; + + if (cnt < 0 || VP_READ_BUFSIZE < cnt) { + cnt = VP_READ_BUFSIZE; + } + + /* initialize buffer */ + _result.top = _result.buf; + vp_stack_push_num(&_result, "%d", 0); /* set eof to 0 */ + eof = _result.top - 1; + buf = _result.top; + *(buf++) = VP_EOV; + buf += VP_HEADER_SIZE; + + while (cnt > 0) { + FD_ZERO(&fdset); + FD_SET((unsigned)sock, &fdset); + + n = select(0, &fdset, NULL, NULL, (timeout == -1) ? NULL : &tv); + if (n == SOCKET_ERROR) { + return vp_stack_return_error(&_result, "select() error: %d", + WSAGetLastError()); + } else if (n == 0) { + /* timeout */ + break; + } + n = recv(sock, buf, cnt, 0); + if (n == -1) { + return vp_stack_return_error(&_result, "recv() error: %s", + strerror(errno)); + } else if (n == 0) { + /* eof */ + *eof = '1'; + break; + } + /* decrease stack top for concatenate. */ + cnt -= n; + buf += n; + size += n; + /* try read more bytes without waiting */ + timeout = 0; + tv.tv_sec = 0; + tv.tv_usec = 0; + } + vp_encode_size(size, _result.top + 1); + _result.top = buf; + return vp_stack_return(&_result); +} + +const char * +vp_socket_write(char *args) +{ + vp_stack_t stack; + int sock; + char *buf; + size_t size; + int timeout; + struct timeval tv; + size_t nleft; + int n; + fd_set fdset; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &sock)); + VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000; + + size = vp_decode_size(stack.top); + buf = stack.top + VP_HEADER_SIZE; + + nleft = 0; + while (nleft < size) { + FD_ZERO(&fdset); + FD_SET((unsigned)sock, &fdset); + + n = select(0, NULL, &fdset, NULL, (timeout == -1) ? NULL : &tv); + if (n == SOCKET_ERROR) { + return vp_stack_return_error(&_result, "select() error: %d", + WSAGetLastError()); + } else if (n == 0) { + /* timeout */ + break; + } + n = send(sock, buf + nleft, (int)(size - nleft), 0); + if (n == -1) + return vp_stack_return_error(&_result, "send() error: %s", + strerror(errno)); + nleft += n; + /* try write more bytes without waiting */ + timeout = 0; + tv.tv_sec = 0; + tv.tv_usec = 0; + } + vp_stack_push_num(&_result, "%u", nleft); + return vp_stack_return(&_result); +} + + +/* + * Added by Richard Emberson + * Check to see if a host exists. + */ +const char * +vp_host_exists(char *args) +{ + vp_stack_t stack; + char *host; + struct hostent *hostent; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); + + if(detain_winsock()) + { + return vp_stack_return_error(&_result, "WSAStartup() error: %s", + lasterror()); + } + hostent = gethostbyname(host); + release_winsock(); + + if (hostent) { + vp_stack_push_num(&_result, "%d", 1); + } else { + vp_stack_push_num(&_result, "%d", 0); + } + + return vp_stack_return(&_result); +} + + +/* Referenced from */ +/* http://www.syuhitu.org/other/dir.html */ +const char * +vp_readdir(char *args) +{ + vp_stack_t stack; + char *dirname; + LPWSTR dirnamew; + WCHAR buf[1024]; + + WIN32_FIND_DATAW fd; + HANDLE h; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &dirname)); + + dirnamew = utf8_to_utf16(dirname); + if (dirnamew == NULL) + return lasterror(); + _snwprintf(buf, lengthof(buf), L"%s\\*", dirnamew); + buf[lengthof(buf) - 1] = 0; + + /* Get handle. */ + h = FindFirstFileExW(buf, +#if WINVER >= 0x601 + FindExInfoBasic, +#else + FindExInfoStandard, +#endif + &fd, + FindExSearchNameMatch, NULL, 0 + ); + + if (h == INVALID_HANDLE_VALUE) { + free(dirnamew); + return vp_stack_return_error(&_result, + "FindFirstFileEx() error: %s", + lasterror()); + } + + do { + if (wcscmp(fd.cFileName, L".") && wcscmp(fd.cFileName, L"..")) { + char *p; + _snwprintf(buf, lengthof(buf), L"%s/%s", dirnamew, fd.cFileName); + buf[lengthof(buf) - 1] = 0; + p = utf16_to_utf8(buf); + if (p) { + vp_stack_push_str(&_result, p); + free(p); + } + } + } while (FindNextFileW(h, &fd)); + free(dirnamew); + + FindClose(h); + return vp_stack_return(&_result); +} + +const char * +vp_delete_trash(char *args) +{ + vp_stack_t stack; + char *filename; + LPWSTR filenamew; + LPWSTR buf; + size_t len; + SHFILEOPSTRUCTW fs; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &filename)); + + filenamew = utf8_to_utf16(filename); + if (filenamew == NULL) + return lasterror(); + + len = wcslen(filenamew); + + buf = malloc(sizeof(WCHAR) * (len + 2)); + if (buf == NULL) { + free(filenamew); + return vp_stack_return_error(&_result, "malloc() error: %s", + "Memory cannot allocate"); + } + + /* Copy filename + '\0\0' */ + wcscpy(buf, filenamew); + buf[len + 1] = 0; + free(filenamew); + + ZeroMemory(&fs, sizeof(SHFILEOPSTRUCTW)); + fs.hwnd = NULL; + fs.wFunc = FO_DELETE; + fs.pFrom = buf; + fs.pTo = NULL; + fs.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; + + vp_stack_push_num(&_result, "%d", SHFileOperationW(&fs)); + + free(buf); + + return vp_stack_return(&_result); +} + +const char * +vp_open(char *args) +{ + vp_stack_t stack; + char *path; + LPWSTR pathw; + size_t ret; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); + + pathw = utf8_to_utf16(path); + if (pathw == NULL) + return lasterror(); + + ret = (size_t)ShellExecuteW(NULL, L"open", pathw, NULL, NULL, SW_SHOWNORMAL); + free(pathw); + if (ret < 32) { + return vp_stack_return_error(&_result, "ShellExecute() error: %s", + lasterror()); + } + + return NULL; +} + +const char * +vp_decode(char *args) +{ + vp_stack_t stack; + size_t len; + char *str; + char *p, *q; + + VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); + VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &str)); + + len = strlen(str); + if (len % 2 != 0) { + return "vp_decode: invalid data length"; + } + + VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, + (_result.top - _result.buf) + (len / 2) + sizeof(VP_EOV_STR))); + + for (p = str, q = _result.top; p < str + len; ) { + char hb, lb; + + hb = CHR2XD[(int)*(p++)]; + lb = CHR2XD[(int)*(p++)]; + if (hb >= 0 && lb >= 0) { + *(q++) = (char)((hb << 4) | lb); + } + } + *(q++) = VP_EOV; + *q = '\0'; + _result.top = q; + + return vp_stack_return(&_result); +} + +const char * +vp_get_signals(char *args) +{ + const char *signames[] = { + "SIGABRT", + "SIGFPE", + "SIGILL", + "SIGINT", + "SIGSEGV", + "SIGTERM", + "SIGALRM", + "SIGCHLD", + "SIGCONT", + "SIGHUP", + "SIGKILL", + "SIGPIPE", + "SIGQUIT", + "SIGSTOP", + "SIGTSTP", + "SIGTTIN", + "SIGTTOU", + "SIGUSR1", + "SIGUSR2" + }; + size_t i; + + for (i = 0; i < lengthof(signames); ++i) + vp_stack_push_num(&_result, "%s:%d", signames[i], i + 1); + return vp_stack_return(&_result); +} + +/* + * vim:set sw=4 sts=4 et: + */ diff --git a/bundle/vimproc.vim/src/ptytty.c b/bundle/vimproc.vim/src/ptytty.c new file mode 100644 index 000000000..6cbfb4114 --- /dev/null +++ b/bundle/vimproc.vim/src/ptytty.c @@ -0,0 +1,171 @@ +/* vim:set sw=4 sts=4 et: */ + +/* for ptsname_r */ +#if defined __ANDROID__ +# define _GNU_SOURCE +#endif + +#include +#include + +#include +#include +#include +#if defined __sun__ +# include +#endif +#include +#include + +#include "ptytty.h" + +static int +ptsname_compat(int fd, char **buf) +{ +#if defined __ANDROID__ + static char b[16]; + + if (ptsname_r(fd, b, sizeof(b)) == -1) + return -1; + *buf = b; +#else + if ((*buf = ptsname(fd)) == NULL) + return -1; +#endif + return 0; +} + +static int +_internal_get_pty(int *master, char **path) +{ + if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1) + return -1; + if (grantpt(*master) != 0) + return -1; + if (unlockpt(*master) != 0) + return -1; + if (ptsname_compat(*master, path) == -1) + return -1; + + return 0; +} + +static int +_internal_get_tty(int *slave, const char *path, + struct termios *termp, struct winsize *winp, int ctty) +{ + if (path != NULL) { + if ((*slave = open(path, O_RDWR|O_NOCTTY)) == -1) + return -1; + } +#ifdef TIOCSCTTY + if (ctty && ioctl(*slave, TIOCSCTTY, NULL) == -1) + return -1; +#endif +#ifdef I_PUSH + if (ioctl(*slave, I_PUSH, "ptem") == -1) + return -1; + if (ioctl(*slave, I_PUSH, "ldterm") == -1) + return -1; +#if defined __sun__ + if (ioctl(*slave, I_PUSH, "ttcompat") == -1) + return -1; +#endif +#endif + + if (termp != NULL) + tcsetattr(*slave, TCSAFLUSH, termp); + if (winp != NULL) + ioctl(*slave, TIOCSWINSZ, winp); + + return 0; +} + +static int +_internal_login_tty(int fd, const char *path, + struct termios *termp, struct winsize *winp) +{ + setsid(); + + if (_internal_get_tty(&fd, path, termp, winp, 1) != 0) + return -1; + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + close(fd); + return 0; + +} + +int +openpty(int *amaster, int *aslave, char *name, + struct termios *termp, struct winsize *winp) +{ + char *path = NULL; + int master = -1, slave = -1; + + if (amaster == NULL || aslave == NULL) + return -1; + + if (_internal_get_pty(&master, &path) != 0) + goto out; + if (_internal_get_tty(&slave, path, termp, winp, 0) != 0) + goto out; + if (name != NULL) + strcpy(name, path); + + *amaster = master; + *aslave = slave; + return 0; + +out: + if (master != -1) + close(master); + if (slave != -1) + close(slave); + return -1; +} + +int +forkpty(int *amaster, char *name, + struct termios *termp, struct winsize *winp) +{ + char *path; + int master = -1; + pid_t pid; + + if (amaster == NULL) + return -1; + + if (_internal_get_pty(&master, &path) != 0) + goto out; + if (name != NULL) + strcpy(name, path); + + if ((pid = fork()) == -1) + goto out; + if (pid == 0) { + close(master); + + if (_internal_login_tty(-1, path, termp, winp) != 0) + _exit(EXIT_FAILURE); + + return 0; + } + + *amaster = master; + return pid; + +out: + if (master != -1) + close(master); + return -1; +} + +int +login_tty(int fd) +{ + return _internal_login_tty(fd, NULL, NULL, NULL); +} diff --git a/bundle/vimproc.vim/src/ptytty.h b/bundle/vimproc.vim/src/ptytty.h new file mode 100644 index 000000000..302f9a417 --- /dev/null +++ b/bundle/vimproc.vim/src/ptytty.h @@ -0,0 +1,10 @@ +#ifndef VP_PTYTTY_H_ +#define VP_PTYTTY_H_ + +#include + +int openpty(int *, int *, char *, struct termios *, struct winsize *); +int forkpty(int *, char *, struct termios *, struct winsize *); +int login_tty(int); + +#endif /* VP_PTYTTY_H_ */ diff --git a/bundle/vimproc.vim/src/vimstack.c b/bundle/vimproc.vim/src/vimstack.c new file mode 100644 index 000000000..99c466813 --- /dev/null +++ b/bundle/vimproc.vim/src/vimstack.c @@ -0,0 +1,295 @@ +/* 2006-06-23 + * vim:set sw=4 sts=4 et: + */ +#include +#include +#include +#include +#include +#include + +/* + * Function arguments and return values are stored in stack. Each value consists of DataSize, Data, + * and EOV. DataSize is a 32-bit integer encoded into a 5-byte string. + * Number should be stored as String. + * + * Return values not started with EOV are error message, except NULL + * which indicates no result. + * + * Successful Result: + * EOV | DataSize0, Data0, EOV | DataSize1, Data1, EOV | ... | NUL + * or + * NULL + * + * Error Result: + * String + */ + +/* End Of Value */ +#define VP_EOV '\xFF' +#define VP_EOV_STR "\xFF" + +#define VP_NUM_BUFSIZE 64 +#define VP_NUMFMT_BUFSIZE 16 +#define VP_INITIAL_BUFSIZE 512 +#define VP_ERRMSG_SIZE 512 +#define VP_HEADER_SIZE 5 + +#define VP_RETURN_IF_FAIL(expr) \ + do { \ + const char *vp_err = expr; \ + if (vp_err) return vp_err; \ + } while (0) + +/* buf:|EOV|var|var|top:free buffer|buf+size */ +typedef struct vp_stack_t { + size_t size; /* stack size */ + char *buf; /* stack buffer */ + char *top; /* stack top */ +} vp_stack_t; + +/* use for initialize */ +#define VP_STACK_NULL {0, NULL, NULL} + +static const char CHR2XD[0x100] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 - 0x0F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 - 0x1F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20 - 0x2F */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40 - 0x4F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50 - 0x5F */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60 - 0x6F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x8F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 - 0x9F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xAF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 - 0xBF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 - 0xCF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 - 0xDF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 - 0xEF */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xF0 - 0xFF */ +}; + +#if 0 +static const char *XD2CHR = + "00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "0A" "0B" "0C" "0D" "0E" "0F" + "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "1A" "1B" "1C" "1D" "1E" "1F" + "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "2A" "2B" "2C" "2D" "2E" "2F" + "30" "31" "32" "33" "34" "35" "36" "37" "38" "39" "3A" "3B" "3C" "3D" "3E" "3F" + "40" "41" "42" "43" "44" "45" "46" "47" "48" "49" "4A" "4B" "4C" "4D" "4E" "4F" + "50" "51" "52" "53" "54" "55" "56" "57" "58" "59" "5A" "5B" "5C" "5D" "5E" "5F" + "60" "61" "62" "63" "64" "65" "66" "67" "68" "69" "6A" "6B" "6C" "6D" "6E" "6F" + "70" "71" "72" "73" "74" "75" "76" "77" "78" "79" "7A" "7B" "7C" "7D" "7E" "7F" + "80" "81" "82" "83" "84" "85" "86" "87" "88" "89" "8A" "8B" "8C" "8D" "8E" "8F" + "90" "91" "92" "93" "94" "95" "96" "97" "98" "99" "9A" "9B" "9C" "9D" "9E" "9F" + "A0" "A1" "A2" "A3" "A4" "A5" "A6" "A7" "A8" "A9" "AA" "AB" "AC" "AD" "AE" "AF" + "B0" "B1" "B2" "B3" "B4" "B5" "B6" "B7" "B8" "B9" "BA" "BB" "BC" "BD" "BE" "BF" + "C0" "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" "C9" "CA" "CB" "CC" "CD" "CE" "CF" + "D0" "D1" "D2" "D3" "D4" "D5" "D6" "D7" "D8" "D9" "DA" "DB" "DC" "DD" "DE" "DF" + "E0" "E1" "E2" "E3" "E4" "E5" "E6" "E7" "E8" "E9" "EA" "EB" "EC" "ED" "EE" "EF" + "F0" "F1" "F2" "F3" "F4" "F5" "F6" "F7" "F8" "F9" "FA" "FB" "FC" "FD" "FE" "FF"; +#endif + +static void vp_stack_free(vp_stack_t *stack); +static const char *vp_stack_from_args(vp_stack_t *stack, char *args); +static const char *vp_stack_return(vp_stack_t *stack); +static const char *vp_stack_return_error(vp_stack_t *stack, const char *fmt, ...); +static const char *vp_stack_reserve(vp_stack_t *stack, size_t needsize); +static const char *vp_stack_pop_num(vp_stack_t *stack, const char *fmt, void *ptr); +static const char *vp_stack_pop_str(vp_stack_t *stack, char **str); +static const char *vp_stack_push_num(vp_stack_t *stack, const char *fmt, ...); +static const char *vp_stack_push_str(vp_stack_t *stack, const char *str); + +#define vp_stack_used(stack) ((stack)->top - (stack)->buf) + + +/* Encode a 32-bit integer into a 5-byte string. */ +static char * +vp_encode_size(unsigned int size, char *buf) +{ + if (buf == NULL) + return NULL; + buf[0] = ((size >> 28) & 0x7f) | 0x80; + buf[1] = ((size >> 21) & 0x7f) | 0x80; + buf[2] = ((size >> 14) & 0x7f) | 0x80; + buf[3] = ((size >> 7) & 0x7f) | 0x80; + buf[4] = ( size & 0x7f) | 0x80; + return buf; +} + +/* Decode a 32-bit integer from a 5-byte string. */ +unsigned int +vp_decode_size(const char *buf) +{ + if (buf == NULL) + return 0; + return ((unsigned int) (buf[0] & 0x7f) << 28) + + ((unsigned int) (buf[1] & 0x7f) << 21) + + ((unsigned int) (buf[2] & 0x7f) << 14) + + ((unsigned int) (buf[3] & 0x7f) << 7) + + ((unsigned int) (buf[4] & 0x7f)); +} + +static void +vp_stack_free(vp_stack_t *stack) +{ + if (stack->buf != NULL) { + free((void *)stack->buf); + stack->size = 0; + stack->buf = NULL; + stack->top = NULL; + } +} + +/* make readonly stack from arguments */ +static const char * +vp_stack_from_args(vp_stack_t *stack, char *args) +{ + if (args == NULL || args[0] == '\0') { + stack->size = 0; + stack->buf = NULL; + stack->top = NULL; + } else { + stack->size = strlen(args); /* don't count end of NUL. */ + stack->buf = args; + stack->top = stack->buf; + if (stack->top[0] != VP_EOV) + return "vp_stack_from_buf: no EOV"; + stack->top++; + } + return NULL; +} + +/* clear stack top and return stack buffer */ +static const char * +vp_stack_return(vp_stack_t *stack) +{ + size_t needsize; + const char *ret; + + /* add the last EOV and NUL */ + needsize = vp_stack_used(stack) + 1; + ret = vp_stack_reserve(stack, needsize); + if (ret != NULL) + return ret; + + stack->top[0] = VP_EOV; + stack->top[1] = '\0'; + + /* Clear the stack. */ + stack->top = stack->buf; + return stack->buf; +} + +/* push error message and return */ +static const char * +vp_stack_return_error(vp_stack_t *stack, const char *fmt, ...) +{ + va_list ap; + size_t needsize; + int ret; + + /* Initialize buffer */ + stack->top = stack->buf; + needsize = VP_ERRMSG_SIZE; + if (vp_stack_reserve(stack, needsize) != NULL) + return fmt; + + va_start(ap, fmt); + ret = vsnprintf(stack->top, stack->size, fmt, ap); + stack->top[ret] = '\0'; + va_end(ap); + /* Clear the stack. */ + stack->top = stack->buf; + return stack->buf; +} + +/* ensure stack buffer is needsize or more bytes */ +static const char * +vp_stack_reserve(vp_stack_t *stack, size_t needsize) +{ + if (needsize > stack->size) { + size_t newsize; + char *newbuf; + + newsize = (stack->size == 0) ? VP_INITIAL_BUFSIZE : (stack->size * 2); + while (needsize > newsize) { + newsize *= 2; + if (newsize <= stack->size) /* paranoid check */ + return "vp_stack_reserve: too big"; + } + if ((newbuf = (char *)realloc(stack->buf, newsize)) == NULL) + return "vp_stack_reserve: NOMEM"; + stack->top = newbuf + vp_stack_used(stack); + stack->buf = newbuf; + stack->size = newsize; + } + return NULL; +} + +static const char * +vp_stack_pop_num(vp_stack_t *stack, const char *fmt, void *ptr) +{ + char *str; + const char *ret; + + if ((size_t)vp_stack_used(stack) == stack->size) + return "vp_stack_pop_num: stack empty"; + + ret = vp_stack_pop_str(stack, &str); + if (ret != NULL) + return ret; + + if (sscanf(str, fmt, ptr) != 1) + return "vp_stack_pop_num: sscanf error"; + + return NULL; +} + +/* str will be invalid after vp_stack_push_*() */ +static const char * +vp_stack_pop_str(vp_stack_t *stack, char **str) +{ + unsigned int size; + + if ((size_t)vp_stack_used(stack) == stack->size) + return "vp_stack_pop_str: stack empty"; + + size = vp_decode_size(stack->top); + *str = stack->top + VP_HEADER_SIZE; + stack->top += VP_HEADER_SIZE + size + 1; + stack->top[-1] = '\0'; /* Overwrite EOV. */ + return NULL; +} + +static const char * +vp_stack_push_num(vp_stack_t *stack, const char *fmt, ...) +{ + va_list ap; + char buf[VP_NUM_BUFSIZE]; + + va_start(ap, fmt); + if (vsprintf(buf, fmt, ap) < 0) { + va_end(ap); + return "vp_stack_push_num: vsprintf error"; + } + va_end(ap); + return vp_stack_push_str(stack, buf); +} + +static const char * +vp_stack_push_str(vp_stack_t *stack, const char *str) +{ + size_t needsize; + unsigned int size; + + size = strlen(str); + needsize = vp_stack_used(stack) + 1 + VP_HEADER_SIZE + size + 1; + VP_RETURN_IF_FAIL(vp_stack_reserve(stack, needsize)); + stack->top[0] = VP_EOV; /* Set previous EOV. */ + sprintf(stack->top + 1 + VP_HEADER_SIZE, "%s", str); + vp_encode_size(size, stack->top + 1); + stack->top += 1 + VP_HEADER_SIZE + size; + stack->top[0] = '\0'; + return NULL; +} diff --git a/bundle/vimproc.vim/test/fopen.vim b/bundle/vimproc.vim/test/fopen.vim new file mode 100644 index 000000000..3de4b79dd --- /dev/null +++ b/bundle/vimproc.vim/test/fopen.vim @@ -0,0 +1,177 @@ +let s:suite = themis#suite('fopen') +let s:assert = themis#helper('assert') +call themis#helper('command').with(s:) + +let s:filename = 'test.txt' +let s:contents = ['foo', 'bar'] + +function! s:suite.before_each() abort + call writefile(s:contents, s:filename, 'b') +endfunction + +function! s:suite.after_each() abort + if filereadable(s:filename) + call delete(s:filename) + endif +endfunction + +function! s:suite.read() abort + let file = vimproc#fopen(s:filename) + let res = file.read() + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ split(res, '\r\n\|\r\|\n')) +endfunction + +function! s:suite.read_lines() abort + let file = vimproc#fopen(s:filename, 'r') + let res = file.read_lines() + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename, 'b'), res) +endfunction + +function! s:suite.read_line() abort + let file = vimproc#fopen(s:filename, 'r', 0) + let res = [] + while !file.eof + let res += [file.read_line()] + endwhile + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals(readfile(s:filename), res) +endfunction + +function! s:suite.write() abort + let file = vimproc#fopen(s:filename, 'w') + let res = "hello\nvimproc\n.vim" + + call s:assert.true(file.is_valid) + + call file.write(res) + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ split(res, '\r\n\|\r\|\n')) +endfunction + +function! s:suite.append() abort + let file = vimproc#fopen(s:filename, 'a') + let res = "\nhello\nvimproc\n.vim" + + call s:assert.true(file.is_valid) + + call file.write(res) + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ s:contents + split(res, '\r\n\|\r\|\n')) +endfunction + +function! s:suite.read_write() abort + let file = vimproc#fopen(s:filename, 'r+') + let res = file.read() + + call s:assert.equals( + \ readfile(s:filename), + \ split(res, '\r\n\|\r\|\n')) + + call s:assert.true(file.is_valid) + + let res = "\nhello\nvimproc\n.vim" + call file.write(res) + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ s:contents + split(res, '\r\n\|\r\|\n')) +endfunction + +function! s:suite.with_oflag() abort + let file = vimproc#fopen(s:filename, 'O_RDONLY') + let res = file.read() + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ split(res, '\r\n\|\r\|\n')) + + let file = vimproc#fopen(s:filename, 'O_WRONLY|O_TRUNC') + let res = "hello\nvimproc\n.vim" + call file.write(res) + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ split(res, '\r\n\|\r\|\n')) + + let file = vimproc#fopen(s:filename, 'O_RDWR|O_APPEND') + let res2 = "\nworld\n!" + call file.write(res2) + + call s:assert.true(file.is_valid) + + call file.close() + + call s:assert.false(file.is_valid) + + call s:assert.equals( + \ readfile(s:filename), + \ split(res . res2, '\r\n\|\r\|\n')) +endfunction + +function! s:suite.invalid_fmode() abort + let file = vimproc#fopen(s:filename, 'r') + + Throws /write() error/ file.write('foo') + + call file.close() + + call s:assert.equals(readfile(s:filename), s:contents) + + let file = vimproc#fopen(s:filename, 'w') + + Throws /read() error/ file.read() + + call file.close() + + call s:assert.true(empty(readfile(s:filename))) +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/functions.vim b/bundle/vimproc.vim/test/functions.vim new file mode 100644 index 000000000..f72ede1f4 --- /dev/null +++ b/bundle/vimproc.vim/test/functions.vim @@ -0,0 +1,10 @@ +let s:suite = themis#suite('functions') +let s:assert = themis#helper('assert') + +function! s:suite.functions() abort + let errmsg_save = v:exception + call s:assert.true(vimproc#kill(9999, 0)) + call s:assert.not_equals(errmsg_save, vimproc#get_last_errmsg()) +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/lexer.vim b/bundle/vimproc.vim/test/lexer.vim new file mode 100644 index 000000000..bb7014f9d --- /dev/null +++ b/bundle/vimproc.vim/test/lexer.vim @@ -0,0 +1,20 @@ +let s:suite = themis#suite('lexer') +let s:assert = themis#helper('assert') + +function! s:suite.token() abort + let lex = vimproc#lexer#init_lexer('1234 5678') + call s:assert.true(lex.advance()) + call s:assert.equals(lex.token(), g:vimproc#lexer#token_type.int) + call s:assert.true(lex.advance()) + call s:assert.equals(lex.token(), g:vimproc#lexer#token_type.int) +endfunction + +function! s:suite.value() abort + let lex = vimproc#lexer#init_lexer('1234 5678') + call s:assert.true(lex.advance()) + call s:assert.equals(lex.value(), 1234) + call s:assert.true(lex.advance()) + call s:assert.equals(lex.value(), 5678) +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/parser.vim b/bundle/vimproc.vim/test/parser.vim new file mode 100644 index 000000000..bb3b97203 --- /dev/null +++ b/bundle/vimproc.vim/test/parser.vim @@ -0,0 +1,97 @@ +let s:suite = themis#suite('parser') +let s:assert = themis#helper('assert') + +function! s:suite.escape() abort + call s:assert.equals( + \ vimproc#parser#split_args('echo "\""'), + \ ['echo', '"']) + call s:assert.equals( + \ vimproc#parser#split_args('echo "\`test\`"'), + \ ['echo', '`test`']) + call s:assert.equals(vimproc#shellescape('hoge'), "'hoge'") + call s:assert.equals(vimproc#shellescape('ho''ge'), "'ho''ge'") +endfunction + +function! s:suite.comment() abort + call s:assert.equals( + \ vimproc#parser#split_args('echo file#1.txt'), + \ ['echo', 'file#1.txt']) + call s:assert.equals( + \ vimproc#parser#split_args('echo file #1.txt'), + \ ['echo', 'file']) +endfunction + +function! s:suite.quote() abort + let is_catched = 0 + try + call vimproc#parser#split_args('echo "\"') + catch /^Exception: Quote/ + let is_catched = 1 + endtry + call s:assert.equals(is_catched, 1) +endfunction + +function! s:suite.join() abort + let is_catched = 0 + try + call vimproc#parser#split_args('echo \') + catch /^Exception: Join to next line/ + let is_catched = 1 + endtry + call s:assert.equals(is_catched, 1) +endfunction + +function! s:suite.parse_statements() abort + let statements = + \ vimproc#parser#split_statements( + \ '"/usr/bin/clang++" --std=c++0x `pkg-config'. + \ ' --libs opencv` "/home/me/opencv/capture.cpp"'. + \ ' -o "/home/me/opencv/capture" && "/home/me/opencv/capture"') + call s:assert.equals(statements, + \ ['"/usr/bin/clang++" --std=c++0x `pkg-config'. + \ ' --libs opencv` "/home/me/opencv/capture.cpp"'. + \ ' -o "/home/me/opencv/capture" ', ' "/home/me/opencv/capture"' + \ ]) +endfunction + +function! s:suite.backquote() abort + call s:assert.equals( + \ vimproc#parser#split_args('echo `echo "hoge" "piyo" "hogera"`'), + \ [ 'echo', 'hoge', 'piyo', 'hogera' ]) + call s:assert.equals( + \ vimproc#parser#split_args( + \ 'echo "`curl -fs https://gist.github.com/raw/4349265/sudden-vim.py`"'), + \ [ 'echo', system('curl -fs https://gist.github.com/raw/4349265/sudden-vim.py')]) +endfunction + +function! s:suite.slash_convertion() abort + " For Vital.DateTime + call s:assert.equals(vimproc#parser#split_args( + \ printf('reg query "%s" /v Bias', + \ 'HKLM\System\CurrentControlSet\Control\TimeZoneInformation')), + \ ['reg', 'query', + \ 'HKLM\System\CurrentControlSet\Control\TimeZoneInformation', + \ '/v', 'Bias']) +endfunction + +function! s:suite.block_convertion() abort + call s:assert.equals(vimproc#parser#parse_pipe( + \ 'grep -inH --exclude-dir={foo} -R vim .')[0].args, + \ ['grep', '-inH', + \ '--exclude-dir=f', '--exclude-dir=o', + \ '-R', 'vim', '.']) + call s:assert.equals(vimproc#parser#parse_pipe( + \ 'grep -inH --exclude-dir={foo,bar,baz} -R vim .')[0].args, + \ ['grep', '-inH', + \ '--exclude-dir=foo', '--exclude-dir=bar', '--exclude-dir=baz', + \ '-R', 'vim', '.']) +endfunction + +function! s:suite.parse_redirection() abort + call s:assert.equals(vimproc#parser#parse_pipe( + \ 'echo "foo" > hoge\piyo'), + \ [{ 'args' : ['echo', 'foo'], 'fd' : + \ { 'stdin' : '', 'stdout' : 'hogepiyo', 'stderr' : '' }}]) +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/popen.vim b/bundle/vimproc.vim/test/popen.vim new file mode 100644 index 000000000..01cd890af --- /dev/null +++ b/bundle/vimproc.vim/test/popen.vim @@ -0,0 +1,122 @@ +let s:suite = themis#suite('popen') +let s:assert = themis#helper('assert') + +function! s:suite.popen2() abort + if !vimproc#util#is_windows() && !executable('ls') + call s:assert.skip('ls command is not installed.') + return + endif + + if vimproc#util#is_windows() + let cmd = ['cmd', '/c', 'DIR', '/B'] + else + let cmd = ['ls'] + endif + let sub = vimproc#popen2(cmd) + let res = '' + while !sub.stdout.eof + let res .= sub.stdout.read() + endwhile + " Newline conversion. + let res = substitute(res, '\r\n', '\n', 'g') + + call s:assert.true(sub.is_valid) + + let [cond, status] = sub.waitpid() + + call s:assert.equals(cond, 'exit') + + call s:assert.equals(status, 0) + + call s:assert.false(sub.is_valid) + + call s:assert.equals(res, system(join(cmd))) + + unlet cmd + unlet sub + + if vimproc#util#is_windows() + let cmd = ['cmd', '/c', 'DIR', '/B', '/A'] + else + let cmd = ['ls', '-la'] + endif + let sub = vimproc#popen2(cmd) + let res = '' + while !sub.stdout.eof + let res .= sub.stdout.read() + endwhile + " Newline conversion. + let res = substitute(res, '\r\n', '\n', 'g') + + call s:assert.true(sub.is_valid) + + let [cond, status] = sub.waitpid() + + call s:assert.equals(cond, 'exit') + + call s:assert.equals(status, 0) + + call s:assert.false(sub.is_valid) + + call s:assert.equals(res, system(join(cmd))) + + unlet cmd + unlet sub +endfunction + +function! s:suite.popen3() abort + if vimproc#util#is_windows() + let cmd = ['cmd', '/c', 'DIR', '/B'] + else + let cmd = ['ls'] + endif + let sub = vimproc#popen3(cmd) + let res = '' + while !sub.stdout.eof + let res .= sub.stdout.read() + endwhile + " Newline conversion. + let res = substitute(res, '\r\n', '\n', 'g') + + call s:assert.true(sub.is_valid) + + let [cond, status] = sub.waitpid() + + call s:assert.equals(cond, 'exit') + + call s:assert.equals(status, 0) + + call s:assert.false(sub.is_valid) + + call s:assert.equals(res, system(join(cmd))) + + unlet cmd + unlet sub +endfunction + +function! s:suite.redirection1() abort + let output = vimproc#system('echo "foo" > test.txt | echo "bar"') + call s:assert.equals(output, "bar\n") + sleep 3 + call s:assert.equals(readfile('test.txt'), ['foo']) + if filereadable('test.txt') + call delete('test.txt') + endif +endfunction + +function! s:suite.redirection2() abort + let sub = vimproc#ptyopen('echo "foo" > test.txt | echo "bar"') + let res = '' + while !sub.stdout.eof + let res .= sub.stdout.read() + endwhile + " Newline conversion. + let res = substitute(res, '\r\n', '\n', 'g') + sleep 3 + call s:assert.equals(readfile('test.txt'), ['foo']) + if filereadable('test.txt') + call delete('test.txt') + endif +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/socket.vim b/bundle/vimproc.vim/test/socket.vim new file mode 100644 index 000000000..603116884 --- /dev/null +++ b/bundle/vimproc.vim/test/socket.vim @@ -0,0 +1,30 @@ +let s:suite = themis#suite('socket') +let s:assert = themis#helper('assert') + +function! s:suite.socket() abort + call s:assert.true(vimproc#host_exists( + \ 'www.yahoo.com')) + call s:assert.true(vimproc#host_exists( + \ 'https://www.yahoo.com')) + call s:assert.true(vimproc#host_exists( + \ 'https://www.yahoo.com/hoge/piyo')) + + let sock = vimproc#socket_open('www.yahoo.com', 80) + call sock.write("GET / HTTP/1.0\r\n\r\n", 100) + let res = '' + let out = sock.read(-1, 100) + while !sock.eof && out != '' + let out = sock.read(-1, 100) + let res .= out + endwhile + + call s:assert.true(sock.is_valid) + + call sock.close() + + call s:assert.false(sock.is_valid) + + echo res +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/test/system.vim b/bundle/vimproc.vim/test/system.vim new file mode 100644 index 000000000..48917cff4 --- /dev/null +++ b/bundle/vimproc.vim/test/system.vim @@ -0,0 +1,87 @@ +let s:suite = themis#suite('system') +let s:assert = themis#helper('assert') + +function! s:check_ls() abort + if !executable('ls') + call s:assert.skip('ls command is not installed.') + endif +endfunction + +function! s:suite.system1() abort + call s:check_ls() + call s:assert.equals(vimproc#system('ls'), system('ls')) +endfunction + +function! s:suite.system2() abort + call s:check_ls() + call s:assert.equals(vimproc#system(['ls']), system('ls')) +endfunction + +function! s:suite.cmd_system1() abort + call s:check_ls() + call s:assert.equals(vimproc#cmd#system('ls'), system('ls')) +endfunction + +function! s:suite.cmd_system2() abort + call s:check_ls() + call s:assert.equals(vimproc#cmd#system(['ls']), system('ls')) +endfunction + +function! s:suite.cmd_system3() abort + call s:assert.equals( + \ vimproc#cmd#system(['echo', '"Foo"']), + \ "\"Foo\"\n") +endfunction + +function! s:suite.system_passwd1() abort + if vimproc#util#is_windows() + call s:assert.skip('') + endif + call s:assert.equals( + \ vimproc#system_passwd('echo -n test'), + \ system('echo -n test')) +endfunction + +function! s:suite.system_passwd2() abort + if vimproc#util#is_windows() + call s:assert.skip('') + endif + call s:assert.equals( + \ vimproc#system_passwd(['echo', '-n', 'test']), + \ system('echo -n test')) +endfunction + +function! s:suite.system_and1() abort + if vimproc#util#is_windows() + call s:assert.skip('') + endif + call s:check_ls() + call s:assert.equals(vimproc#system('ls&'), '') +endfunction + +function! s:suite.system_and2() abort + if vimproc#util#is_windows() + call s:assert.skip('') + endif + call s:check_ls() + call s:assert.equals(vimproc#system('ls&'), + \ vimproc#system_bg('ls')) +endfunction + +function! s:suite.system_bg1() abort + call s:check_ls() + call s:assert.equals(vimproc#system_bg('ls'), '') +endfunction + +function! s:suite.system_bg2() abort + call s:check_ls() + call s:assert.equals(vimproc#system_bg(['ls']), '') +endfunction + +function! s:suite.password_pattern() abort + call s:assert.match( + \ 'Enter passphrase for key ''.ssh/id_rsa''', + \ g:vimproc_password_pattern) +endfunction + +" vim:foldmethod=marker:fen: diff --git a/bundle/vimproc.vim/tools/appveyor.bat b/bundle/vimproc.vim/tools/appveyor.bat new file mode 100644 index 000000000..b320358f2 --- /dev/null +++ b/bundle/vimproc.vim/tools/appveyor.bat @@ -0,0 +1,130 @@ +@echo off +:: Batch file for building/testing vimproc on AppVeyor + +cd %APPVEYOR_BUILD_FOLDER% +if /I "%1"=="test" ( + set _target=_test +) else ( + set _target= +) + +for %%i in (msvc mingw msys2 cygwin) do if "%compiler%"=="%%i" goto %compiler%%_target% + +echo Unknown build target. +exit 1 + +:msvc +:: ---------------------------------------------------------------------- +:: Using VC10 with nmake +::call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %ARCH% +call :install_vim +call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" %ENV% + +@echo on +nmake -f make_msvc.mak CPU=%CPU% cflags=/MD + +@echo off +goto :eof + +:msvc_test +set THEMIS_VIM=%APPVEYOR_BUILD_FOLDER%\vim-kaoriya\vim.exe +@echo on +themis\bin\themis + +@echo off +goto :eof + + +:mingw +:: ---------------------------------------------------------------------- +:: Using MinGW +call :install_vim +@echo on +path C:\MinGW\bin;C:\MinGW\msys\1.0\bin;%path% +make -f make_mingw32.mak + +@echo off +goto :eof + +:mingw_test +set THEMIS_VIM=%APPVEYOR_BUILD_FOLDER%\vim-kaoriya\vim.exe +@echo on +themis\bin\themis + +@echo off +goto :eof + + +:msys2 +:: ---------------------------------------------------------------------- +:: Using MSYS2 +call :install_vim +@echo on +PATH C:\%MSYS2_DIR%\%MSYSTEM%\bin;C:\%MSYS2_DIR%\usr\bin;%PATH% +set CHERE_INVOKING=yes +:: Install and update necessary packages +rem bash -lc "for i in {1..3}; do update-core && break || sleep 15; done" +rem bash -lc "for i in {1..3}; do pacman --noconfirm -Su mingw-w64-%MSYS2_ARCH%-{gcc,make} make && break || sleep 15; done" + +bash -lc "make" + +@echo off +goto :eof + +:msys2_test +set THEMIS_VIM=%APPVEYOR_BUILD_FOLDER%\vim-kaoriya\vim.exe +@echo on +themis\bin\themis + +@echo off +goto :eof + + +:cygwin +:: ---------------------------------------------------------------------- +:: Using Cygwin +@echo on +goto cygwin%BIT% + +:cygwin32 +@echo on +c:\cygwin\setup-x86.exe -qnNdO -R C:/cygwin -s http://cygwin.mirror.constant.com -l C:/cygwin/var/cache/setup -P vim +PATH c:\cygwin\bin;%PATH% +set CHERE_INVOKING=yes +bash -lc "" +bash -lc "make" + +@echo off +goto :eof + +:cygwin64 +@echo on +c:\cygwin64\setup-x86_64.exe -qnNdO -R C:/cygwin64 -s http://cygwin.mirror.constant.com -l C:/cygwin/var/cache/setup -P vim +PATH c:\cygwin64\bin;%PATH% +set CHERE_INVOKING=yes +bash -lc "" +bash -lc "make" + +@echo off +goto :eof + + +:cygwin_test +@echo on +rem bash -lc "git clone -q https://github.com/thinca/vim-themis.git themis --depth=1" +rem bash -lc "themis/bin/themis" + +@echo off +goto :eof + + +:install_vim +:: ---------------------------------------------------------------------- +:: Install Vim and themis +echo Downloading Vim +py tools\dl-kaoriya-vim.py --arch win%BIT% --filename vim.zip +echo Installing Vim +7z x vim.zip > nul +move vim??-kaoriya-win%BIT% vim-kaoriya +git clone -q https://github.com/thinca/vim-themis.git themis --depth=1 +exit /b diff --git a/bundle/vimproc.vim/tools/benchmark.vim b/bundle/vimproc.vim/tools/benchmark.vim new file mode 100644 index 000000000..a151d12d7 --- /dev/null +++ b/bundle/vimproc.vim/tools/benchmark.vim @@ -0,0 +1,17 @@ +let cnt = 25 + +let start = reltime() + +for i in range(1, cnt) + call system('ls') +endfor + +echomsg 'system() = ' . reltimestr(reltime(start)) + +let start = reltime() + +for i in range(1, cnt) + call vimproc#system('ls') +endfor + +echomsg 'vimproc#system() = ' . reltimestr(reltime(start)) diff --git a/bundle/vimproc.vim/tools/dl-kaoriya-vim.py b/bundle/vimproc.vim/tools/dl-kaoriya-vim.py new file mode 100644 index 000000000..c2e09e28a --- /dev/null +++ b/bundle/vimproc.vim/tools/dl-kaoriya-vim.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 + +# Download the latest KaoriYa Vim from the GitHub releases + +import argparse +import calendar +import io +import json +import os +import sys +import time +import urllib.request, urllib.error + +# Repository Name +repo_name = 'koron/vim-kaoriya' +gh_releases_url = 'https://api.github.com/repos/' + repo_name + '/releases' + +# Asset name checker +def does_skip_asset(asset): + return asset['name'].find('pdb') >= 0 + +# Arguments properties +arg_desc = 'Download the latest KaoriYa Vim from the GitHub releases' +arg_archs = ['all', 'win32', 'win64'] +arg_default_arch = 'all' +arg_allow_prerelease = False + + +# Parse arguments +def parse_args(): + global parser + parser = argparse.ArgumentParser(description=arg_desc) + parser.add_argument('-c', '--check', action='store_true', + help='only check the information of the latest release') + parser.add_argument('--noprogress', action='store_true', + help="Don't show the progress") + parser.add_argument('-f', '--force', action='store_true', + help='overwrite the download file') + parser.add_argument('-n', '--filename', type=str, action='store', + help='filename to save') + parser.add_argument('-p', '--prerelease', action='store_true', + default=arg_allow_prerelease, + help='Allow downloading prerelease') + parser.add_argument('-a', '--arch', type=str, action='store', + choices=arg_archs, default=arg_default_arch, + help='architecture to download') + parser.add_argument('--auth', type=str, action='store', + default=os.getenv('AUTH_TOKEN'), + metavar="TOKEN", help='GitHub API token (Environment variable AUTH_TOKEN can be also used.)') + return parser.parse_args() + +# Get information of GitHub release +# see: https://developer.github.com/v3/repos/releases/ +def get_rel_info(url, auth): + if auth: + # Unauthenticated requests are limited up to 60 requests per hour. + # Authenticated requests are allowed up to 5,000 requests per hour. + # See: https://developer.github.com/v3/#rate-limiting + request = urllib.request.Request(url) + request.add_header("Authorization", "token " + auth) + else: + request = url + try: + response = urllib.request.urlopen(request) + except urllib.error.HTTPError as err: + print('GitHub release not found. (%s)' % err.reason, file=sys.stderr) + exit(1) + return json.load(io.StringIO(str(response.read(), 'utf-8'))) + +# Show progress +def reporthook(count, blocksize, totalsize): + size = count * blocksize + if totalsize <= 0: + print("\r{:,}".format(size)) + else: + size = min(size, totalsize) + print("\r{:,} / {:,} ({:.1%})".format(size, totalsize, size / totalsize), end='') + +# Download the files +def download(args, rel_info): + for asset in rel_info['assets']: + if args.filename: + name = args.filename + else: + name = asset['name'] + if does_skip_asset(asset): + continue + if args.arch != 'all' and asset['name'].find(args.arch) < 0: + continue + if os.path.isfile(name) and not args.force: + print('File exists:', name) + continue + print('Downloading from:', asset['browser_download_url']) + print('Downloading to:', name) + if args.noprogress: + hook = None + else: + hook = reporthook + urllib.request.urlretrieve(asset['browser_download_url'], name, hook) + # Set timestamp + asset_time = time.strptime(asset['updated_at'], '%Y-%m-%dT%H:%M:%SZ') + os.utime(name, times=(time.time(), calendar.timegm(asset_time))) + if not args.noprogress: + print() + +def main(): + args = parse_args() + if args.filename and args.arch == 'all': + parser.error('-a must be specified when you specify -n.') + + if args.prerelease: + rels_info = get_rel_info(gh_releases_url, args.auth) + for rel in rels_info: + if rel['draft']: + continue + gh_release_url = rel['url'] + break + else: + print('GitHub release not found.', file=sys.stderr) + exit(1) + else: + gh_release_url = gh_releases_url + '/latest' + + rel_info = get_rel_info(gh_release_url, args.auth) + print('Last release:', rel_info['name']) + print('Created at:', rel_info['created_at']) + + if args.check: + exit(0) + + download(args, rel_info) + exit(0) + + +if __name__ == "__main__": + main() diff --git a/bundle/vimproc.vim/tools/fork.py b/bundle/vimproc.vim/tools/fork.py new file mode 100644 index 000000000..3f1280a19 --- /dev/null +++ b/bundle/vimproc.vim/tools/fork.py @@ -0,0 +1,16 @@ +import os +import sys +import time + +# Create new process +pid = os.fork() + +# Print text +c = 'p' if pid == 0 else 'c' + +if pid == 0: + sys.exit(0) + +while True: + time.sleep(1) + sys.stderr.write(c) diff --git a/bundle/vimproc.vim/tools/leak_check.vim b/bundle/vimproc.vim/tools/leak_check.vim new file mode 100644 index 000000000..0a9fe92dd --- /dev/null +++ b/bundle/vimproc.vim/tools/leak_check.vim @@ -0,0 +1,21 @@ +" Resource leak checker. + +let max = 2048 + +for i in range(1, max) + redraw + echo i.'/'.max + call vimproc#system('ls | head -20') +endfor + +for i in range(1, max) + redraw + echo i.'/'.max + + let process = vimproc#pgroup_open('ls') + while !process.stdout.eof + call process.stdout.read(-1) + endwhile + + let [_, status] = process.waitpid() +endfor diff --git a/bundle/vimproc.vim/tools/leak_check2.vim b/bundle/vimproc.vim/tools/leak_check2.vim new file mode 100644 index 000000000..f69989235 --- /dev/null +++ b/bundle/vimproc.vim/tools/leak_check2.vim @@ -0,0 +1,20 @@ +" Resource leak checker version2(for process group). + +let pwd = fnamemodify(expand(''), ':p:h') + +let process = vimproc#pgroup_open('python ' . pwd . '/fork.py') + +call process.waitpid() +" call process.kill() + +let process = vimproc#pgroup_open('ls && ls') +while !process.stdout.eof + call process.stdout.read(-1) +endwhile + +call process.waitpid() + +if executable('ps') + echomsg string(split(system('ps -eo pid,pgid,sid,args | grep defunct'), '\n')) + echomsg 'Current pid = ' . getpid() +endif diff --git a/bundle/vimproc.vim/tools/update-dll-mingw.bat b/bundle/vimproc.vim/tools/update-dll-mingw.bat new file mode 100644 index 000000000..e5cd24d26 --- /dev/null +++ b/bundle/vimproc.vim/tools/update-dll-mingw.bat @@ -0,0 +1,51 @@ +@echo off +rem Update the DLL using MinGW. +rem If the old DLL is in use, rename it to avoid compilation error. +rem +rem usage: update-dll-mingw [arch] [makeopts] +rem +rem [arch] is 32 or 64. If omitted, it is automatically detected from the +rem %PROCESSOR_ARCHITECTURE% environment. +rem [makeopts] is option(s) for mingw32-make. +rem +rem +rem Sample .vimrc: +rem +rem NeoBundle 'Shougo/vimproc.vim', { +rem \ 'build' : { +rem \ 'windows' : 'tools\\update-dll-mingw', +rem \ 'cygwin' : 'make -f make_cygwin.mak', +rem \ 'mac' : 'make -f make_mac.mak', +rem \ 'linux' : 'make', +rem \ 'unix' : 'gmake', +rem \ }, +rem \ } + +if "%1"=="32" ( + set vimproc_arch=%1 + shift +) else if "%1"=="64" ( + set vimproc_arch=%1 + shift +) else ( + if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + set vimproc_arch=64 + ) else ( + set vimproc_arch=32 + ) +) +set vimproc_dllname=vimproc_win%vimproc_arch%.dll + +where mingw32-make >nul 2>&1 +if ERRORLEVEL 1 ( + echo mingw32-make not found. + goto :EOF +) + +rem Try to delete old DLLs. +if exist lib\%vimproc_dllname%.old del lib\%vimproc_dllname%.old +if exist lib\%vimproc_dllname% del lib\%vimproc_dllname% +rem If the DLL couldn't delete (may be it is in use), rename it. +if exist lib\%vimproc_dllname% ren lib\%vimproc_dllname% %vimproc_dllname%.old + +mingw32-make -f make_mingw%vimproc_arch%.mak %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/bundle/vimproc.vim/tools/update-dll-msvc.bat b/bundle/vimproc.vim/tools/update-dll-msvc.bat new file mode 100644 index 000000000..b8c5c453c --- /dev/null +++ b/bundle/vimproc.vim/tools/update-dll-msvc.bat @@ -0,0 +1,67 @@ +@echo off +rem Update the DLL using MSVC. +rem If the old DLL is in use, rename it to avoid compilation error. +rem current support version of Visual C compiler is 2012 or later. +rem +rem usage: update-dll-msvc +rem +rem +rem Sample .vimrc: +rem +rem NeoBundle 'Shougo/vimproc.vim', { +rem \ 'build' : { +rem \ 'windows' : 'tools\\update-dll-msvc', +rem \ 'cygwin' : 'make -f make_cygwin.mak', +rem \ 'mac' : 'make -f make_mac.mak', +rem \ 'linux' : 'make', +rem \ 'unix' : 'gmake', +rem \ }, +rem \ } + +setlocal enabledelayedexpansion + +if "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + set vimproc_arch=64 + set msvc_arch=x86_amd64 + set cpu_arch=AMD64 +) else ( + set vimproc_arch=32 + set msvc_arch=x86 + set cpu_arch=i386 +) + +set vimproc_dllname=vimproc_win%vimproc_arch%.dll + +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" ( + REM found the lasted version of Visual C compiler + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do ( + set InstallDir=%%i + + if exist "!InstallDir!\VC\Auxiliary\Build\vcvars%vimproc_arch%.bat" ( + call "!InstallDir!\VC\Auxiliary\Build\vcvars%vimproc_arch%.bat" + ) + ) +) else if defined VS140COMNTOOLS ( + REM Microsoft Visual Studio 2015 installed + call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %msvc_arch% +) else if defined VS120COMNTOOLS ( + REM Microsoft Visual Studio 2013 installed + call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" %msvc_arch% +) else if defined VS110COMNTOOLS ( + REM Microsoft Visual Studio 2012 installed + call "%VS110COMNTOOLS%\..\..\VC\vcvarsall.bat" %msvc_arch% +) + +where nmake >nul 2>&1 +if errorlevel 1 ( + echo nmake not found. + goto :eof +) + +rem Try to delete old DLLs. +if exist lib\%vimproc_dllname%.old del lib\%vimproc_dllname%.old +if exist lib\%vimproc_dllname% del lib\%vimproc_dllname% +rem If the DLL couldn't delete (may be it is in use), rename it. +if exist lib\%vimproc_dllname% ren lib\%vimproc_dllname% %vimproc_dllname%.old + +nmake -f make_msvc.mak CPU=%cpu_arch%