summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAndrey Sobolev <andrey.sobolev@xored.com>2015-09-30 14:23:25 +0600
committerAndrey Sobolev <andrey.sobolev@xored.com>2015-09-30 14:23:25 +0600
commit4351c62161b884f93e6796a8df7695ac382dff27 (patch)
tree2e66349773cb8017e76070dac334c09bed2d70fc /lib
parent8b2c9964abf08b7746f6446cead4d4ac4e8c6c67 (diff)
parent980db2f4407a21b1ca59926a3318479aedfa7e37 (diff)
downloadNim-4351c62161b884f93e6796a8df7695ac382dff27.tar.gz
Merge remote-tracking branch 'nim-lang/devel' into emscripten-support
Diffstat (limited to 'lib')
-rw-r--r--lib/posix/kqueue.nim71
-rw-r--r--lib/pure/os.nim12
-rw-r--r--lib/pure/osproc.nim131
-rw-r--r--lib/pure/selectors.nim94
-rw-r--r--lib/pure/streams.nim12
-rw-r--r--lib/pure/unicode.nim3
-rw-r--r--lib/system/nimscript.nim2
-rw-r--r--lib/windows/winlean.nim32
8 files changed, 315 insertions, 42 deletions
diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim
new file mode 100644
index 000000000..511ada9ac
--- /dev/null
+++ b/lib/posix/kqueue.nim
@@ -0,0 +1,71 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Adam Strzelecki
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim:on.}
+
+from posix import Timespec
+
+# Filters:
+const
+  EVFILT_READ*     = -1
+  EVFILT_WRITE*    = -2
+  EVFILT_AIO*      = -3
+  EVFILT_VNODE*    = -4
+  EVFILT_PROC*     = -5
+  EVFILT_SIGNAL*   = -6
+  EVFILT_TIMER*    = -7
+  EVFILT_MACHPORT* = -8
+  EVFILT_FS*       = -9
+  EVFILT_USER*     = -10
+  # -11 is unused
+  EVFILT_VM*       = -12
+
+# Actions:
+const
+  EV_ADD*      = 0x0001 ## Add event to queue (implies enable).
+                        ## Re-adding an existing element modifies it.
+  EV_DELETE*   = 0x0002 ## Delete event from queue.
+  EV_ENABLE*   = 0x0004 ## Enable event.
+  EV_DISABLE*  = 0x0008 ## Disable event (not reported).
+
+# Flags:
+const
+  EV_ONESHOT*  = 0x0010 ## Only report one occurrence.
+  EV_CLEAR*    = 0x0020 ## Clear event state after reporting.
+  EV_RECEIPT*  = 0x0040 ## Force EV_ERROR on success, data == 0
+  EV_DISPATCH* = 0x0080 ## Disable event after reporting.
+
+# Return values:
+const
+  EV_EOF*      = 0x8000 ## EOF detected
+  EV_ERROR*    = 0x4000 ## Error, data contains errno
+
+type
+  KEvent* {.importc: "struct kevent",
+            header: "<sys/event.h>", pure, final.} = object
+    ident*: cuint    ## identifier for this event  (uintptr_t)
+    filter*: cshort  ## filter for event
+    flags*: cushort  ## general flags
+    fflags*: cuint   ## filter-specific flags
+    data*: cuint     ## filter-specific data  (intptr_t)
+    #udata*: ptr void ## opaque user data identifier
+
+proc kqueue*(): cint {.importc: "kqueue", header: "<sys/event.h>".}
+  ## Creates new queue and returns its descriptor.
+
+proc kevent*(kqFD: cint,
+             changelist: ptr KEvent, nchanges: cint,
+             eventlist: ptr KEvent, nevents: cint, timeout: ptr Timespec): cint
+     {.importc: "kevent", header: "<sys/event.h>".}
+  ## Manipulates queue for given ``kqFD`` descriptor.
+
+proc EV_SET*(event: ptr KEvent, ident: cuint, filter: cshort, flags: cushort,
+             fflags: cuint, data: cuint, udata: ptr void)
+     {.importc: "EV_SET", header: "<sys/event.h>".}
+  ## Fills event with given data.
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f413371cb..c01228563 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -810,11 +810,12 @@ type
 
 {.deprecated: [TPathComponent: PathComponent].}
 
-iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
+iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {.
   tags: [ReadDirEffect].} =
   ## walks over the directory `dir` and yields for each directory or file in
   ## `dir`. The component type and full path for each item is returned.
-  ## Walking is not recursive.
+  ## Walking is not recursive. If ``relative`` is true the resulting path is
+  ## shortened to be relative to ``dir``.
   ## Example: This directory structure::
   ##   dirA / dirB / fileB1.txt
   ##        / dirC
@@ -843,7 +844,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
             k = pcDir
           if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
             k = succ(k)
-          yield (k, dir / extractFilename(getFilename(f)))
+          let xx = if relative: extractFilename(getFilename(f))
+                   else: dir / extractFilename(getFilename(f))
+          yield (k, xx)
         if findNextFile(h, f) == 0'i32: break
       findClose(h)
   else:
@@ -855,7 +858,8 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
         var y = $x.d_name
         if y != "." and y != "..":
           var s: Stat
-          y = dir / y
+          if not relative:
+            y = dir / y
           var k = pcFile
 
           when defined(linux) or defined(macosx) or defined(bsd):
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 7431be702..bc73f7119 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -24,6 +24,20 @@ when defined(linux):
   import linux
 
 type
+  ProcessOption* = enum ## options that can be passed `startProcess`
+    poEchoCmd,           ## echo the command before execution
+    poUsePath,           ## Asks system to search for executable using PATH environment
+                         ## variable.
+                         ## On Windows, this is the default.
+    poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
+                         ## Use it only if `command` comes from trused source.
+    poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
+    poParentStreams,     ## use the parent's streams
+    poInteractive        ## optimize the buffer handling for responsiveness for
+                         ## UI applications. Currently this only affects
+                         ## Windows: Named pipes are used so that you can peek
+                         ## at the process' output streams.
+
   ProcessObj = object of RootObj
     when defined(windows):
       fProcessHandle: Handle
@@ -34,18 +48,10 @@ type
       inStream, outStream, errStream: Stream
       id: Pid
     exitCode: cint
+    options: set[ProcessOption]
 
   Process* = ref ProcessObj ## represents an operating system process
 
-  ProcessOption* = enum ## options that can be passed `startProcess`
-    poEchoCmd,           ## echo the command before execution
-    poUsePath,           ## Asks system to search for executable using PATH environment
-                         ## variable.
-                         ## On Windows, this is the default.
-    poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
-                         ## Use it only if `command` comes from trused source.
-    poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
-    poParentStreams      ## use the parent's streams
 
 {.deprecated: [TProcess: ProcessObj, PProcess: Process,
   TProcessOption: ProcessOption].}
@@ -302,7 +308,7 @@ proc execProcesses*(cmds: openArray[string],
       result = max(waitForExit(p), result)
       close(p)
 
-proc select*(readfds: var seq[Process], timeout = 500): int
+proc select*(readfds: var seq[Process], timeout = 500): int {.benign.}
   ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
   ## Specify -1 for no timeout. Returns the number of processes that are
   ## ready to read from. The processes that are ready to be read from are
@@ -394,13 +400,68 @@ when defined(Windows) and not defined(useNimRtl):
   #var
   #  O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
   #  O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
+  proc myDup(h: Handle; inherit: WinBool=1): Handle =
+    let thisProc = getCurrentProcess()
+    if duplicateHandle(thisProc, h,
+                       thisProc, addr result,0,inherit,
+                       DUPLICATE_SAME_ACCESS) == 0:
+      raiseOSError(osLastError())
+
+  proc createAllPipeHandles(si: var STARTUPINFO;
+                            stdin, stdout, stderr: var Handle) =
+    var sa: SECURITY_ATTRIBUTES
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
+    sa.lpSecurityDescriptor = nil
+    sa.bInheritHandle = 1
+    let pipeOutName = newWideCString(r"\\.\pipe\stdout")
+    let pipeInName = newWideCString(r"\\.\pipe\stdin")
+    let pipeOut = createNamedPipe(pipeOutName,
+      dwOpenMode=PIPE_ACCESS_INBOUND or FILE_FLAG_WRITE_THROUGH,
+      dwPipeMode=PIPE_NOWAIT,
+      nMaxInstances=1,
+      nOutBufferSize=1024, nInBufferSize=1024,
+      nDefaultTimeOut=0,addr sa)
+    if pipeOut == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+    let pipeIn = createNamedPipe(pipeInName,
+      dwOpenMode=PIPE_ACCESS_OUTBOUND or FILE_FLAG_WRITE_THROUGH,
+      dwPipeMode=PIPE_NOWAIT,
+      nMaxInstances=1,
+      nOutBufferSize=1024, nInBufferSize=1024,
+      nDefaultTimeOut=0,addr sa)
+    if pipeIn == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+
+    si.hStdOutput = createFileW(pipeOutName,
+        FILE_WRITE_DATA or SYNCHRONIZE, 0, addr sa,
+        OPEN_EXISTING, # very important flag!
+        FILE_ATTRIBUTE_NORMAL,
+        0 # no template file for OPEN_EXISTING
+      )
+    if si.hStdOutput == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+    si.hStdError = myDup(si.hStdOutput)
+    si.hStdInput = createFileW(pipeInName,
+        FILE_READ_DATA or SYNCHRONIZE, 0, addr sa,
+        OPEN_EXISTING, # very important flag!
+        FILE_ATTRIBUTE_NORMAL,
+        0 # no template file for OPEN_EXISTING
+      )
+    if si.hStdOutput == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+
+    stdin = myDup(pipeIn, 0)
+    stdout = myDup(pipeOut, 0)
+    discard closeHandle(pipeIn)
+    discard closeHandle(pipeOut)
+    stderr = stdout
 
   proc createPipeHandles(rdHandle, wrHandle: var Handle) =
-    var piInheritablePipe: SECURITY_ATTRIBUTES
-    piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
-    piInheritablePipe.lpSecurityDescriptor = nil
-    piInheritablePipe.bInheritHandle = 1
-    if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
+    var sa: SECURITY_ATTRIBUTES
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
+    sa.lpSecurityDescriptor = nil
+    sa.bInheritHandle = 1
+    if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32:
       raiseOSError(osLastError())
 
   proc fileClose(h: Handle) {.inline.} =
@@ -417,16 +478,20 @@ when defined(Windows) and not defined(useNimRtl):
       success: int
       hi, ho, he: Handle
     new(result)
+    result.options = options
     si.cb = sizeof(si).cint
     if poParentStreams notin options:
       si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
-      createPipeHandles(si.hStdInput, hi)
-      createPipeHandles(ho, si.hStdOutput)
-      if poStdErrToStdOut in options:
-        si.hStdError = si.hStdOutput
-        he = ho
+      if poInteractive notin options:
+        createPipeHandles(si.hStdInput, hi)
+        createPipeHandles(ho, si.hStdOutput)
+        if poStdErrToStdOut in options:
+          si.hStdError = si.hStdOutput
+          he = ho
+        else:
+          createPipeHandles(he, si.hStdError)
       else:
-        createPipeHandles(he, si.hStdError)
+        createAllPipeHandles(si, hi, ho, he)
       result.inHandle = FileHandle(hi)
       result.outHandle = FileHandle(ho)
       result.errHandle = FileHandle(he)
@@ -469,6 +534,7 @@ when defined(Windows) and not defined(useNimRtl):
 
     if e != nil: dealloc(e)
     if success == 0:
+      if poInteractive in result.options: close(result)
       const errInvalidParameter = 87.int
       const errFileNotFound = 2.int
       if lastError.int in {errInvalidParameter, errFileNotFound}:
@@ -482,12 +548,12 @@ when defined(Windows) and not defined(useNimRtl):
     result.id = procInfo.dwProcessId
 
   proc close(p: Process) =
-    when false:
-      # somehow this does not work on Windows:
+    if poInteractive in p.options:
+      # somehow this is not always required on Windows:
       discard closeHandle(p.inHandle)
       discard closeHandle(p.outHandle)
       discard closeHandle(p.errHandle)
-      discard closeHandle(p.FProcessHandle)
+      #discard closeHandle(p.FProcessHandle)
 
   proc suspend(p: Process) =
     discard suspendThread(p.fProcessHandle)
@@ -564,7 +630,7 @@ when defined(Windows) and not defined(useNimRtl):
     assert readfds.len <= MAXIMUM_WAIT_OBJECTS
     var rfds: WOHandleArray
     for i in 0..readfds.len()-1:
-      rfds[i] = readfds[i].fProcessHandle
+      rfds[i] = readfds[i].outHandle #fProcessHandle
 
     var ret = waitForMultipleObjects(readfds.len.int32,
                                      addr(rfds), 0'i32, timeout.int32)
@@ -578,6 +644,11 @@ when defined(Windows) and not defined(useNimRtl):
       readfds.del(i)
       return 1
 
+  proc hasData*(p: Process): bool =
+    var x: int32
+    if peekNamedPipe(p.outHandle, lpTotalBytesAvail=addr x):
+      result = x > 0
+
 elif not defined(useNimRtl):
   const
     readIdx = 0
@@ -635,6 +706,7 @@ elif not defined(useNimRtl):
     var
       pStdin, pStdout, pStderr: array [0..1, cint]
     new(result)
+    result.options = options
     result.exitCode = -3 # for ``waitForExit``
     if poParentStreams notin options:
       if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
@@ -960,6 +1032,15 @@ elif not defined(useNimRtl):
 
     pruneProcessSet(readfds, (rd))
 
+  proc hasData*(p: Process): bool =
+    var rd: TFdSet
+
+    FD_ZERO(rd)
+    let m = max(0, int(p.outHandle))
+    FD_SET(cint(p.outHandle), rd)
+
+    result = int(select(cint(m+1), addr(rd), nil, nil, nil)) == 1
+
 
 proc execCmdEx*(command: string, options: set[ProcessOption] = {
                 poStdErrToStdOut, poUsePath}): tuple[
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index bfc393a96..ca969c761 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -13,6 +13,8 @@ import os, unsigned, hashes
 
 when defined(linux):
   import posix, epoll
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  import posix, kqueue, times
 elif defined(windows):
   import winlean
 else:
@@ -79,7 +81,6 @@ when defined(nimdoc):
   proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
     ## Retrieves the selector key for ``fd``.
 
-
 elif defined(linux):
   type
     Selector* = object
@@ -99,15 +100,13 @@ elif defined(linux):
     result.data.fd = fd.cint
 
   proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
-      data: SelectorData) =
+                 data: SelectorData) =
     var event = createEventStruct(events, fd)
     if events != {}:
       if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
         raiseOSError(osLastError())
 
-    var key = SelectorKey(fd: fd, events: events, data: data)
-
-    s.fds[fd] = key
+    s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
 
   proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
     if s.fds[fd].events != events:
@@ -154,11 +153,6 @@ elif defined(linux):
       raiseOSError(err)
 
   proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
-    ##
-    ## The ``events`` field of the returned ``key`` contains the original events
-    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
-    ## of the ``TReadyInfo`` tuple which determines which events are ready
-    ## on the ``fd``.
     result = @[]
     let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
     if evNum < 0:
@@ -204,6 +198,86 @@ elif defined(linux):
     ## Retrieves the selector key for ``fd``.
     return s.fds[fd]
 
+elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  type
+    Selector* = object
+      kqFD: cint
+      events: array[64, KEvent]
+      when MultiThreaded:
+        fds: SharedTable[SocketHandle, SelectorKey]
+      else:
+        fds: Table[SocketHandle, SelectorKey]
+
+  template modifyKQueue(kqFD: cint, fd: SocketHandle, event: Event,
+                        op: cushort) =
+    var kev = KEvent(ident:  fd.cuint,
+                     filter: if event == EvRead: EVFILT_READ else: EVFILT_WRITE,
+                     flags:  op)
+    if kevent(kqFD, addr kev, 1, nil, 0, nil) == -1:
+      raiseOSError(osLastError())
+
+  proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
+                 data: SelectorData) =
+    for event in events:
+      modifyKQueue(s.kqFD, fd, event, EV_ADD)
+    s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
+
+  proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
+    let previousEvents = s.fds[fd].events
+    if previousEvents != events:
+      for event in events-previousEvents:
+        modifyKQueue(s.kqFD, fd, event, EV_ADD)
+      for event in previousEvents-events:
+        modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+      s.fds.mget(fd).events = events
+
+  proc unregister*(s: var Selector, fd: SocketHandle) =
+    for event in s.fds[fd].events:
+      modifyKQueue(s.kqFD, fd, event, EV_DELETE)
+    s.fds.del(fd)
+
+  proc close*(s: var Selector) =
+    when MultiThreaded: deinitSharedTable(s.fds)
+    if s.kqFD.close() != 0: raiseOSError(osLastError())
+
+  proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
+    result = @[]
+    var tv = Timespec(tv_sec: timeout.Time, tv_nsec: 0)
+    let evNum = kevent(s.kqFD, nil, 0, addr s.events[0], 64.cint, addr tv)
+    if evNum < 0:
+      let err = osLastError()
+      if err.cint == EINTR:
+        return @[]
+      raiseOSError(err)
+    if evNum == 0: return @[]
+    for i in 0 .. <evNum:
+      let fd = s.events[i].ident.SocketHandle
+
+      var evSet: set[Event] = {}
+      if  (s.events[i].flags and EV_EOF) != 0: evSet = evSet + {EvError}
+      if   s.events[i].filter == EVFILT_READ:  evSet = evSet + {EvRead}
+      elif s.events[i].filter == EVFILT_WRITE: evSet = evSet + {EvWrite}
+      let selectorKey = s.fds[fd]
+      assert selectorKey.fd != 0.SocketHandle
+      result.add((selectorKey, evSet))
+
+  proc newSelector*(): Selector =
+    result.kqFD = kqueue()
+    if result.kqFD < 0:
+      raiseOSError(osLastError())
+    when MultiThreaded:
+      result.fds = initSharedTable[SocketHandle, SelectorKey]()
+    else:
+      result.fds = initTable[SocketHandle, SelectorKey]()
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    s.fds.hasKey(fd) # and s.fds[fd].events != {}
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
 elif not defined(nimdoc):
   # TODO: kqueue for bsd/mac os x.
   type
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 406a0ec6e..68f31e9fe 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -101,6 +101,18 @@ proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
   result = s.readDataImpl(s, buffer, bufLen)
 
+proc readAll*(s: Stream): string =
+  ## Reads all available data.
+  result = newString(1000)
+  var r = 0
+  while true:
+    let readBytes = readData(s, addr(result[r]), 1000)
+    if readBytes < 1000:
+      setLen(result, r+readBytes)
+      break
+    inc r, 1000
+    setLen(result, r+1000)
+
 proc readData*(s, unused: Stream, buffer: pointer,
                bufLen: int): int {.deprecated.} =
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index d3dc77909..b059a7315 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -1340,10 +1340,9 @@ proc lastRune*(s: string; last: int): (Rune, int) =
   else:
     var L = 0
     while last-L >= 0 and ord(s[last-L]) shr 6 == 0b10: inc(L)
-    inc(L)
     var r: Rune
     fastRuneAt(s, last-L, r, false)
-    result = (r, L)
+    result = (r, L+1)
 
 when isMainModule:
   let
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index 4841749a9..a93c65dd4 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -56,7 +56,7 @@ proc getCommand*(): string =
   ## "c", "js", "build", "help".
   builtin
 
-proc setCommand*(cmd: string) =
+proc setCommand*(cmd: string; project="") =
   ## Sets the Nim command that should be continued with after this Nimscript
   ## has finished.
   builtin
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 84dac6d79..e6a119e15 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -108,6 +108,13 @@ const
 
   CREATE_UNICODE_ENVIRONMENT* = 1024'i32
 
+  PIPE_ACCESS_DUPLEX* = 0x00000003'i32
+  PIPE_ACCESS_INBOUND* = 1'i32
+  PIPE_ACCESS_OUTBOUND* = 2'i32
+  PIPE_NOWAIT* = 0x00000001'i32
+  SYNCHRONIZE* = 0x00100000'i32
+  FILE_FLAG_WRITE_THROUGH* = 0x80000000'i32
+
 proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "CloseHandle".}
 
@@ -125,6 +132,19 @@ proc createPipe*(hReadPipe, hWritePipe: var Handle,
                  nSize: int32): WINBOOL{.
     stdcall, dynlib: "kernel32", importc: "CreatePipe".}
 
+proc createNamedPipe*(lpName: WideCString,
+                     dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize,
+                     nInBufferSize, nDefaultTimeOut: int32,
+                     lpSecurityAttributes: ptr SECURITY_ATTRIBUTES): Handle {.
+    stdcall, dynlib: "kernel32", importc: "CreateNamedPipeW".}
+
+proc peekNamedPipe*(hNamedPipe: Handle, lpBuffer: pointer=nil,
+                    nBufferSize: int32 = 0,
+                    lpBytesRead: ptr int32 = nil,
+                    lpTotalBytesAvail: ptr int32 = nil,
+                    lpBytesLeftThisMessage: ptr int32 = nil): bool {.
+    stdcall, dynlib: "kernel32", importc: "PeekNamedPipe".}
+
 when useWinUnicode:
   proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
                      lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
@@ -615,12 +635,24 @@ const
 
   FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
   FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'i32
+  DUPLICATE_SAME_ACCESS* = 2
+  FILE_READ_DATA* = 0x00000001 # file & pipe
+  FILE_WRITE_DATA* = 0x00000002 # file & pipe
 
 # Error Constants
 const
   ERROR_ACCESS_DENIED* = 5
   ERROR_HANDLE_EOF* = 38
 
+proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE,
+                      hTargetProcessHandle: HANDLE,
+                      lpTargetHandle: ptr HANDLE,
+                      dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,
+                      dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",
+    importc: "DuplicateHandle".}
+proc getCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32",
+                                   importc: "GetCurrentProcess".}
+
 when useWinUnicode:
   proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
                     lpSecurityAttributes: pointer,