1 To: vim_dev@googlegroups.com
4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
10 Note: I haven't verified this works or even compiles. Please send me a
11 patch if you see a problem and can fix it.
14 Problem: External commands can't use pipes on MS-Windows.
15 Solution: Implement pipes and use them when 'shelltemp' isn't set. (Vincent
17 Files: src/eval.c, src/ex_cmds.c, src/misc2.c, src/os_unix.c,
18 src/os_win32.c, src/proto/misc2.pro, src/ui.c
21 *** ../vim-7.3.239/src/eval.c 2011-06-19 02:55:32.000000000 +0200
22 --- src/eval.c 2011-07-07 15:44:56.000000000 +0200
25 #ifdef FEAT_SEARCHPATH
28 ! #if defined(UNIX) && !defined(USE_SYSTEM)
33 #ifdef FEAT_SEARCHPATH
36 ! #if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264)
40 *** ../vim-7.3.239/src/ex_cmds.c 2011-06-12 22:03:15.000000000 +0200
41 --- src/ex_cmds.c 2011-07-07 15:44:56.000000000 +0200
45 shell_flags |= SHELL_DOOUT;
47 ! #if !defined(USE_SYSTEM) && defined(UNIX)
48 if (!do_in && do_out && !p_stmp)
50 /* Use a pipe to fetch stdout of the command, do not use a temp file. */
53 shell_flags |= SHELL_DOOUT;
55 ! #if (!defined(USE_SYSTEM) && defined(UNIX)) || defined(WIN3264)
56 if (!do_in && do_out && !p_stmp)
58 /* Use a pipe to fetch stdout of the command, do not use a temp file. */
59 *** ../vim-7.3.239/src/misc2.c 2011-07-07 15:08:53.000000000 +0200
60 --- src/misc2.c 2011-07-07 15:55:42.000000000 +0200
67 + #if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264)
69 + * Append the text in "gap" below the cursor line and clear "gap".
75 + /* Remove trailing CR. */
78 + && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
80 + ga_append(gap, NUL);
81 + ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
86 /************************************************************************
87 * functions that use lookup tables for various things, generally to do with
89 *** ../vim-7.3.239/src/os_unix.c 2011-04-11 16:56:29.000000000 +0200
90 --- src/os_unix.c 2011-07-07 15:54:58.000000000 +0200
97 - static void append_ga_line __ARGS((garray_T *gap));
100 - * Append the text in "gap" below the cursor line and clear "gap".
103 - append_ga_line(gap)
106 - /* Remove trailing CR. */
107 - if (gap->ga_len > 0
108 - && !curbuf->b_p_bin
109 - && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
111 - ga_append(gap, NUL);
112 - ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
118 mch_call_shell(cmd, options)
121 *** ../vim-7.3.239/src/os_win32.c 2011-05-25 17:06:16.000000000 +0200
122 --- src/os_win32.c 2011-07-07 16:08:30.000000000 +0200
126 static PGNSECINFO pGetNamedSecurityInfo;
129 + typedef BOOL (WINAPI *PSETHANDLEINFORMATION)(HANDLE, DWORD, DWORD);
131 + static BOOL allowPiping = FALSE;
132 + static PSETHANDLEINFORMATION pSetHandleInformation;
135 * Set g_PlatformId to VER_PLATFORM_WIN32_NT (NT) or
136 * VER_PLATFORM_WIN32_WINDOWS (Win95).
144 + * If we are on windows NT, try to load the pipe functions, only
145 + * available from Win2K.
147 + if (g_PlatformId == VER_PLATFORM_WIN32_NT)
149 + HANDLE kernel32 = GetModuleHandle("kernel32");
150 + pSetHandleInformation = (PSETHANDLEINFORMATION)GetProcAddress(
151 + kernel32, "SetHandleInformation");
153 + allowPiping = pSetHandleInformation != NULL;
162 #if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \
163 ! __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400)
165 * Bad parameter handler.
170 #if ((defined(__MINGW32__) || defined (__CYGWIN32__)) && \
171 ! __MSVCRT_VERSION__ >= 0x800) || (defined(_MSC_VER) && _MSC_VER >= 1400)
173 * Bad parameter handler.
177 * 4. Prompt the user to press a key to close the console window
180 ! mch_system(char *cmd, int options)
183 PROCESS_INFORMATION pi;
185 * 4. Prompt the user to press a key to close the console window
188 ! mch_system_classic(char *cmd, int options)
191 PROCESS_INFORMATION pi;
200 + * Thread launched by the gui to send the current buffer data to the
201 + * process. This way avoid to hang up vim totally if the children
202 + * process take a long time to process the lines.
204 + static DWORD WINAPI
205 + sub_process_writer(LPVOID param)
207 + HANDLE g_hChildStd_IN_Wr = param;
208 + linenr_T lnum = curbuf->b_op_start.lnum;
211 + char_u *lp = ml_get(lnum);
217 + l = (DWORD)STRLEN(lp + written);
220 + else if (lp[written] == NL)
222 + /* NL -> NUL translation */
223 + WriteFile(g_hChildStd_IN_Wr, "", 1, &len, NULL);
227 + s = vim_strchr(lp + written, NL);
228 + WriteFile(g_hChildStd_IN_Wr, (char *)lp + written,
229 + s == NULL ? l : (DWORD)(s - (lp + written)),
234 + /* Finished a line, add a NL, unless this line should not have
236 + if (lnum != curbuf->b_op_end.lnum
237 + || !curbuf->b_p_bin
238 + || (lnum != curbuf->b_no_eol_lnum
239 + && (lnum != curbuf->b_ml.ml_line_count
240 + || curbuf->b_p_eol)))
242 + WriteFile(g_hChildStd_IN_Wr, "\n", 1, &ignored, NULL);
246 + if (lnum > curbuf->b_op_end.lnum)
256 + /* finished all the lines, close pipe */
257 + CloseHandle(g_hChildStd_IN_Wr);
262 + # define BUFLEN 100 /* length for buffer, stolen from unix version */
265 + * This function read from the children's stdout and write the
266 + * data on screen or in the buffer accordingly.
269 + dump_pipe(int options,
270 + HANDLE g_hChildStd_OUT_Rd,
275 + DWORD availableBytes = 0;
284 + /* we query the pipe to see if there is any data to read
285 + * to avoid to perform a blocking read */
286 + ret = PeekNamedPipe(g_hChildStd_OUT_Rd, /* pipe to query */
287 + NULL, /* optional buffer */
288 + 0, /* buffe size */
289 + NULL, /* number of read bytes */
290 + &availableBytes, /* available bytes total */
291 + NULL); /* byteLeft */
294 + /* We got real data in the pipe, read it */
295 + while (ret != 0 && availableBytes > 0 && availableBytes > 0)
300 + (DWORD)(BUFLEN - *buffer_off);
304 + toRead = availableBytes < toRead ? availableBytes : toRead;
305 + ReadFile(g_hChildStd_OUT_Rd, buffer
307 + + *buffer_off, toRead
313 + /* If we haven't read anything, there is a problem */
317 + availableBytes -= len;
319 + if (options & SHELL_READ)
321 + /* Do NUL -> NL translation, append NL separated
322 + * lines to the current buffer. */
323 + for (i = 0; i < len; ++i)
325 + if (buffer[i] == NL)
326 + append_ga_line(ga);
327 + else if (buffer[i] == NUL)
330 + ga_append(ga, buffer[i]);
334 + else if (has_mbyte)
338 + len += *buffer_off;
341 + /* Check if the last character in buffer[] is
342 + * incomplete, keep these bytes for the next
344 + for (p = buffer; p < buffer + len; p += l)
346 + l = mb_cptr2len(p);
348 + l = 1; /* NUL byte? */
349 + else if (MB_BYTE2LEN(*p) != l)
352 + if (p == buffer) /* no complete character */
354 + /* avoid getting stuck at an illegal byte */
366 + if (p < buffer + len)
369 + *buffer_off = (DWORD)((buffer + len) - p);
370 + mch_memmove(buffer, p, *buffer_off);
375 + # endif /* FEAT_MBYTE */
382 + windgoto(msg_row, msg_col);
389 + * Version of system to use for windows NT > 5.0 (Win2K), use pipe
390 + * for communication and doesn't open any new window.
393 + mch_system_piped(char *cmd, int options)
396 + PROCESS_INFORMATION pi;
399 + HANDLE g_hChildStd_IN_Rd = NULL;
400 + HANDLE g_hChildStd_IN_Wr = NULL;
401 + HANDLE g_hChildStd_OUT_Rd = NULL;
402 + HANDLE g_hChildStd_OUT_Wr = NULL;
404 + char_u buffer[BUFLEN + 1]; /* reading buffer + size */
407 + /* buffer used to receive keys */
408 + char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
409 + int ta_len = 0; /* valid bytes in ta_buf[] */
413 + int noread_cnt = 0;
417 + DWORD buffer_off = 0; /* valid bytes in buffer[] */
420 + SECURITY_ATTRIBUTES saAttr;
422 + /* Set the bInheritHandle flag so pipe handles are inherited. */
423 + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
424 + saAttr.bInheritHandle = TRUE;
425 + saAttr.lpSecurityDescriptor = NULL;
427 + if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)
428 + /* Ensure the read handle to the pipe for STDOUT is not inherited. */
429 + || ! pSetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)
430 + /* Create a pipe for the child process's STDIN. */
431 + || ! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)
432 + /* Ensure the write handle to the pipe for STDIN is not inherited. */
433 + || ! pSetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
435 + CloseHandle(g_hChildStd_IN_Rd);
436 + CloseHandle(g_hChildStd_IN_Wr);
437 + CloseHandle(g_hChildStd_OUT_Rd);
438 + CloseHandle(g_hChildStd_OUT_Wr);
439 + MSG_PUTS(_("\nCannot create pipes\n"));
442 + si.cb = sizeof(si);
443 + si.lpReserved = NULL;
444 + si.lpDesktop = NULL;
446 + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
448 + /* set-up our file redirection */
449 + si.hStdError = g_hChildStd_OUT_Wr;
450 + si.hStdOutput = g_hChildStd_OUT_Wr;
451 + si.hStdInput = g_hChildStd_IN_Rd;
452 + si.wShowWindow = SW_HIDE;
453 + si.cbReserved2 = 0;
454 + si.lpReserved2 = NULL;
456 + if (options & SHELL_READ)
457 + ga_init2(&ga, 1, BUFLEN);
459 + /* Now, run the command */
460 + CreateProcess(NULL, /* Executable name */
461 + cmd, /* Command to execute */
462 + NULL, /* Process security attributes */
463 + NULL, /* Thread security attributes */
465 + // this command can be litigeous, handle inheritence was
466 + // deactivated for pending temp file, but, if we deactivate
467 + // it, the pipes don't work for some reason.
468 + TRUE, /* Inherit handles, first deactivated,
470 + CREATE_DEFAULT_ERROR_MODE, /* Creation flags */
471 + NULL, /* Environment */
472 + NULL, /* Current directory */
473 + &si, /* Startup information */
474 + &pi); /* Process information */
477 + /* Close our unused side of the pipes */
478 + CloseHandle(g_hChildStd_IN_Rd);
479 + CloseHandle(g_hChildStd_OUT_Wr);
481 + if (options & SHELL_WRITE)
484 + CreateThread(NULL, /* security attributes */
485 + 0, /* default stack size */
486 + sub_process_writer, /* function to be executed */
487 + g_hChildStd_IN_Wr, /* parameter */
488 + 0, /* creation flag, start immediately */
489 + NULL); /* we don't care about thread id */
490 + CloseHandle(thread);
491 + g_hChildStd_IN_Wr = NULL;
494 + /* Keep updating the window while waiting for the shell to finish. */
499 + if (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
501 + TranslateMessage(&msg);
502 + DispatchMessage(&msg);
505 + /* write pipe information in the window */
506 + if ((options & (SHELL_READ|SHELL_WRITE))
513 + if (!(options & SHELL_EXPAND)
515 + (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
516 + != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
521 + && (ta_len > 0 || noread_cnt > 4))
525 + /* Get extra characters when we don't have any. Reset the
526 + * counter and timer. */
528 + # if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
529 + gettimeofday(&start_tv, NULL);
531 + len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
533 + if (ta_len > 0 || len > 0)
536 + * For pipes: Check for CTRL-C: send interrupt signal to
537 + * child. Check for CTRL-D: EOF, close pipe to child.
539 + if (len == 1 && cmd != NULL)
541 + if (ta_buf[ta_len] == Ctrl_C)
543 + /* Learn what exit code is expected, for
544 + * now put 9 as SIGKILL */
545 + TerminateProcess(pi.hProcess, 9);
547 + if (ta_buf[ta_len] == Ctrl_D)
549 + CloseHandle(g_hChildStd_IN_Wr);
550 + g_hChildStd_IN_Wr = NULL;
554 + /* replace K_BS by <BS> and K_DEL by <DEL> */
555 + for (i = ta_len; i < ta_len + len; ++i)
557 + if (ta_buf[i] == CSI && len - i > 2)
559 + c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
560 + if (c == K_DEL || c == K_KDEL || c == K_BS)
562 + mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
563 + (size_t)(len - i - 2));
564 + if (c == K_DEL || c == K_KDEL)
567 + ta_buf[i] = Ctrl_H;
571 + else if (ta_buf[i] == '\r')
575 + i += (*mb_ptr2len_len)(ta_buf + i,
576 + ta_len + len - i) - 1;
581 + * For pipes: echo the typed characters. For a pty this
582 + * does not seem to work.
584 + for (i = ta_len; i < ta_len + len; ++i)
586 + if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
587 + msg_putchar(ta_buf[i]);
589 + else if (has_mbyte)
591 + int l = (*mb_ptr2len)(ta_buf + i);
593 + msg_outtrans_len(ta_buf + i, l);
598 + msg_outtrans_len(ta_buf + i, 1);
600 + windgoto(msg_row, msg_col);
606 + * Write the characters to the child, unless EOF has been
607 + * typed for pipes. Write one character at a time, to
608 + * avoid losing too much typeahead. When writing buffer
609 + * lines, drop the typed characters (only check for
612 + if (options & SHELL_WRITE)
614 + else if (g_hChildStd_IN_Wr != NULL)
616 + WriteFile(g_hChildStd_IN_Wr, (char*)ta_buf,
618 + // if we are typing in, we want to keep things reactive
623 + mch_memmove(ta_buf, ta_buf + len, ta_len);
631 + ui_inchar_undo(ta_buf, ta_len);
633 + if (WaitForSingleObject(pi.hProcess, delay) != WAIT_TIMEOUT)
635 + dump_pipe(options, g_hChildStd_OUT_Rd,
636 + &ga, buffer, &buffer_off);
641 + dump_pipe(options, g_hChildStd_OUT_Rd,
642 + &ga, buffer, &buffer_off);
644 + /* We start waiting for a very short time and then increase it, so
645 + * that we respond quickly when the process is quick, and don't
646 + * consume too much overhead when it's slow. */
651 + /* Close the pipe */
652 + CloseHandle(g_hChildStd_OUT_Rd);
653 + if (g_hChildStd_IN_Wr != NULL)
654 + CloseHandle(g_hChildStd_IN_Wr);
656 + WaitForSingleObject(pi.hProcess, INFINITE);
658 + /* Get the command exit code */
659 + GetExitCodeProcess(pi.hProcess, &ret);
661 + if (options & SHELL_READ)
665 + append_ga_line(&ga);
666 + /* remember that the NL was missing */
667 + curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
670 + curbuf->b_no_eol_lnum = 0;
674 + /* Close the handles to the subprocess, so that it goes away */
675 + CloseHandle(pi.hThread);
676 + CloseHandle(pi.hProcess);
682 + mch_system(char *cmd, int options)
684 + /* if we can pipe and the shelltemp option is off */
685 + if (allowPiping && !p_stmp)
686 + return mch_system_piped(cmd, options);
688 + return mch_system_classic(cmd, options);
692 # define mch_system(c, o) system(c)
698 ! STRLEN(vimrun_path) +
700 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
706 ! (allowPiping && !p_stmp ? 0 : STRLEN(vimrun_path)) +
708 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
713 need_vimrun_warning = FALSE;
715 ! if (!s_dont_use_vimrun)
716 /* Use vimrun to execute the command. It opens a console
717 * window, which can be closed without killing Vim. */
718 vim_snprintf((char *)newcmd, cmdlen, "%s%s%s %s %s",
721 need_vimrun_warning = FALSE;
723 ! if (!s_dont_use_vimrun && (!allowPiping || p_stmp))
724 /* Use vimrun to execute the command. It opens a console
725 * window, which can be closed without killing Vim. */
726 vim_snprintf((char *)newcmd, cmdlen, "%s%s%s %s %s",
729 /* Print the return value, unless "vimrun" was used. */
730 if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent
731 #if defined(FEAT_GUI_W32)
732 ! && ((options & SHELL_DOOUT) || s_dont_use_vimrun)
737 /* Print the return value, unless "vimrun" was used. */
738 if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent
739 #if defined(FEAT_GUI_W32)
740 ! && ((options & SHELL_DOOUT) || s_dont_use_vimrun
741 ! || (allowPiping && !p_stmp))
745 *** ../vim-7.3.239/src/proto/misc2.pro 2011-07-07 15:08:53.000000000 +0200
746 --- src/proto/misc2.pro 2011-07-07 15:56:16.000000000 +0200
750 char_u *ga_concat_strings __ARGS((garray_T *gap));
751 void ga_concat __ARGS((garray_T *gap, char_u *s));
752 void ga_append __ARGS((garray_T *gap, int c));
753 + void append_ga_line __ARGS((garray_T *gap));
754 int name_to_mod_mask __ARGS((int c));
755 int simplify_key __ARGS((int key, int *modifiers));
756 int handle_x_keys __ARGS((int key));
757 *** ../vim-7.3.239/src/ui.c 2011-06-19 01:14:23.000000000 +0200
758 --- src/ui.c 2011-07-07 15:44:56.000000000 +0200
764 ! #if defined(UNIX) || defined(VMS) || defined(PROTO)
766 * When executing an external program, there may be some typed characters that
767 * are not consumed by it. Give them back to ui_inchar() and they are stored
772 ! #if defined(UNIX) || defined(VMS) || defined(PROTO) || defined(WIN3264)
774 * When executing an external program, there may be some typed characters that
775 * are not consumed by it. Give them back to ui_inchar() and they are stored
776 *** ../vim-7.3.239/src/version.c 2011-07-07 15:08:53.000000000 +0200
777 --- src/version.c 2011-07-07 16:14:20.000000000 +0200
781 { /* Add new patch number below this line */
787 hundred-and-one symptoms of being an internet addict:
788 257. Your "hundred-and-one" lists include well over 101 items, since you
789 automatically interpret all numbers in hexadecimal notation.
790 (hex 101 = decimal 257)
792 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
793 /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
794 \\\ an exciting new programming language -- http://www.Zimbu.org ///
795 \\\ help me help AIDS victims -- http://ICCF-Holland.org ///