summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/asyncio.nim11
-rw-r--r--lib/pure/os.nim179
-rw-r--r--lib/pure/osproc.nim5
-rw-r--r--lib/pure/scgi.nim15
-rw-r--r--lib/pure/sockets.nim134
-rw-r--r--lib/pure/terminal.nim666
-rw-r--r--lib/windows/winlean.nim2
-rw-r--r--lib/wrappers/gtk/glib2.nim8
-rw-r--r--lib/wrappers/gtk/gtk2.nim2
-rw-r--r--tools/nimgrep.nim2
10 files changed, 560 insertions, 464 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 403401ff1..4ff6e0ced 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -167,7 +167,7 @@ proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
   result = newAsyncSocket()
   result.socket = socket(domain, typ, protocol, buffered)
   result.proto = protocol
-  if result.socket == InvalidSocket: OSError()
+  if result.socket == InvalidSocket: OSError(OSLastError())
   result.socket.setBlocking(false)
 
 proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
@@ -349,7 +349,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
     client.sslNeedAccept = false
     client.info = SockConnected
 
-  if c == InvalidSocket: OSError()
+  if c == InvalidSocket: SocketError(server.socket)
   c.setBlocking(false) # TODO: Needs to be tested.
   
   # deleg.open is set in ``toDelegate``.
@@ -423,6 +423,10 @@ proc isConnecting*(s: PAsyncSocket): bool =
 proc isClosed*(s: PAsyncSocket): bool =
   ## Determines whether ``s`` has been closed.
   return s.info == SockClosed
+proc isSendDataBuffered*(s: PAsyncSocket): bool =
+  ## Determines whether ``s`` has data waiting to be sent, i.e. whether this
+  ## socket's sendBuffer contains data. 
+  return s.sendBuffer.len != 0
 
 proc setHandleWrite*(s: PAsyncSocket,
     handleWrite: proc (s: PAsyncSocket) {.closure.}) =
@@ -638,8 +642,7 @@ when isMainModule:
   proc testRead(s: PAsyncSocket, no: int) =
     echo("Reading! " & $no)
     var data = ""
-    if not s.readLine(data):
-      OSError()
+    if not s.readLine(data): return
     if data == "":
       echo("Closing connection. " & $no)
       s.close()
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index bf00afed2..eaa22d351 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -39,6 +39,8 @@ type
   FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
                                   ## the directory structure
 
+  TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
+
 const
   doslike = defined(windows) or defined(OS2) or defined(DOS)
     # DOS-like filesystem
@@ -171,10 +173,13 @@ const
     ## The character which separates the base filename from the extension;
     ## for example, the '.' in ``os.nim``.
 
-proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
+proc OSErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
   ## Retrieves the operating system's error flag, ``errno``.
   ## On Windows ``GetLastError`` is checked before ``errno``.
   ## Returns "" if no error occured.
+  ##
+  ## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc.
+  
   result = ""
   when defined(Windows):
     var err = GetLastError()
@@ -194,17 +199,89 @@ proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
   if errno != 0'i32:
     result = $os.strerror(errno)
 
-proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
+{.push warning[deprecated]: off.}
+proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
   ## raises an EOS exception with the given message ``msg``.
   ## If ``msg == ""``, the operating system's error flag
   ## (``errno``) is converted to a readable error message. On Windows
   ## ``GetLastError`` is checked before ``errno``.
   ## If no error flag is set, the message ``unknown OS error`` is used.
+  ##
+  ## **Deprecated since version 0.9.4**: use the other ``OSError`` proc.
   if len(msg) == 0:
     var m = OSErrorMsg()
     raise newException(EOS, if m.len > 0: m else: "unknown OS error")
   else:
     raise newException(EOS, msg)
+{.pop.}
+
+proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.}
+proc `$`*(err: TOSErrorCode): string {.borrow.}
+
+proc OSErrorMsg*(errorCode: TOSErrorCode): string =
+  ## Converts an OS error code into a human readable string.
+  ##
+  ## The error code can be retrieved using the ``OSLastError`` proc.
+  ##
+  ## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
+  ## returned.
+  ##
+  ## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to
+  ## make this procedure use the non-unicode Win API calls to retrieve the
+  ## message.
+  result = ""
+  when defined(Windows):
+    if errorCode != TOSErrorCode(0'i32):
+      when useWinUnicode:
+        var msgbuf: widecstring
+        if FormatMessageW(0x00000100 or 0x00001000 or 0x00000200,
+                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: LocalFree(cast[pointer](msgbuf))
+      else:
+        var msgbuf: cstring
+        if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
+                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: LocalFree(msgbuf)
+  else:
+    if errorCode != TOSErrorCode(0'i32):
+      result = $os.strerror(errorCode.int32)
+
+proc OSError*(errorCode: TOSErrorCode) =
+  ## Raises an ``EOS`` exception. The ``errorCode`` will determine the
+  ## message, ``OSErrorMsg`` will be used to get this message.
+  ##
+  ## The error code can be retrieved using the ``OSLastError`` proc.
+  ##
+  ## If the error code is ``0`` or an error message could not be retrieved,
+  ## the message ``unknown OS error`` will be used.
+  let msg = OSErrorMsg(errorCode)
+  if msg == "":
+    raise newException(EOS, "unknown OS error")
+  else:
+    raise newException(EOS, msg)
+
+{.push stackTrace:off.}
+proc OSLastError*(): TOSErrorCode =
+  ## Retrieves the last operating system error code.
+  ##
+  ## This procedure is useful in the event when an OS call fails. In that case
+  ## this procedure will return the error code describing the reason why the
+  ## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert
+  ## this code into a string.
+  ##
+  ## **Warning**:
+  ## The behaviour of this procedure varies between Windows and POSIX systems.
+  ## On Windows some OS calls can reset the error code to ``0`` causing this
+  ## procedure to return ``0``. It is therefore advised to call this procedure
+  ## immediately after an OS call fails. On POSIX systems this is not a problem.
+  
+  when defined(windows):
+    result = TOSErrorCode(GetLastError())
+  else:
+    result = TOSErrorCode(errno)
+{.pop.}
 
 proc UnixToNativePath*(path: string): string {.
   noSideEffect, rtl, extern: "nos$1".} =
@@ -311,12 +388,12 @@ proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s last modification time.
   when defined(posix):
     var res: TStat
-    if stat(file, res) < 0'i32: OSError()
+    if stat(file, res) < 0'i32: OSError(OSLastError())
     return res.st_mtime
   else:
     var f: TWIN32_Find_Data
     var h = findfirstFile(file, f)
-    if h == -1'i32: OSError()
+    if h == -1'i32: OSError(OSLastError())
     result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
     findclose(h)
 
@@ -324,12 +401,12 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s last read or write access time.
   when defined(posix):
     var res: TStat
-    if stat(file, res) < 0'i32: OSError()
+    if stat(file, res) < 0'i32: OSError(OSLastError())
     return res.st_atime
   else:
     var f: TWIN32_Find_Data
     var h = findfirstFile(file, f)
-    if h == -1'i32: OSError()
+    if h == -1'i32: OSError(OSLastError())
     result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
     findclose(h)
 
@@ -337,12 +414,12 @@ proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
   ## Returns the `file`'s creation time.
   when defined(posix):
     var res: TStat
-    if stat(file, res) < 0'i32: OSError()
+    if stat(file, res) < 0'i32: OSError(OSLastError())
     return res.st_ctime
   else:
     var f: TWIN32_Find_Data
     var h = findfirstFile(file, f)
-    if h == -1'i32: OSError()
+    if h == -1'i32: OSError(OSLastError())
     result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
     findclose(h)
 
@@ -358,30 +435,30 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
     when useWinUnicode:
       var res = newWideCString("", bufsize)
       var L = GetCurrentDirectoryW(bufsize, res)
-      if L == 0'i32: OSError()
+      if L == 0'i32: OSError(OSLastError())
       result = res$L
     else:
       result = newString(bufsize)
       var L = GetCurrentDirectoryA(bufsize, result)
-      if L == 0'i32: OSError()
+      if L == 0'i32: OSError(OSLastError())
       setLen(result, L)
   else:
     result = newString(bufsize)
     if getcwd(result, bufsize) != nil:
       setlen(result, c_strlen(result))
     else:
-      OSError()
+      OSError(OSLastError())
 
 proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
   ## Sets the `current working directory`:idx:; `EOS` is raised if
   ## `newDir` cannot been set.
   when defined(Windows):
     when useWinUnicode:
-      if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError()
+      if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError())
     else:
-      if SetCurrentDirectoryA(newDir) == 0'i32: OSError()
+      if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError())
   else:
-    if chdir(newDir) != 0'i32: OSError()
+    if chdir(newDir) != 0'i32: OSError(OSLastError())
 
 proc JoinPath*(head, tail: string): string {.
   noSideEffect, rtl, extern: "nos$1".} =
@@ -571,23 +648,23 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
       var res = newWideCString("", bufsize div 2)
       var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
       if L <= 0'i32 or L >= bufsize: 
-        OSError()
+        OSError(OSLastError())
       result = res$L
     else:
       var unused: cstring
       result = newString(bufsize)
       var L = GetFullPathNameA(filename, bufsize, result, unused)
-      if L <= 0'i32 or L >= bufsize: OSError()
+      if L <= 0'i32 or L >= bufsize: OSError(OSLastError())
       setLen(result, L)
   elif defined(macosx) or defined(bsd):
     # On Mac OS X 10.5, realpath does not allocate the buffer on its own
     var pathBuffer: cstring = newString(pathMax)
     var resultBuffer = realpath(filename, pathBuffer)
-    if resultBuffer == nil: OSError()
+    if resultBuffer == nil: OSError(OSLastError())
     result = $resultBuffer
   else:
     var res = realpath(filename, nil)
-    if res == nil: OSError()
+    if res == nil: OSError(OSLastError())
     result = $res
     c_free(res)
  
@@ -677,6 +754,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
       var f1 = OpenHandle(path1)
       var f2 = OpenHandle(path2)
 
+    var lastErr: TOSErrorCode
     if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
       var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
 
@@ -685,17 +763,21 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
         result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
                  fi1.nFileIndexHigh == fi2.nFileIndexHigh and
                  fi1.nFileIndexLow == fi2.nFileIndexLow
-      else: success = false
-    else: success = false
+      else:
+        lastErr = OSLastError()
+        success = false
+    else:
+      lastErr = OSLastError()
+      success = false
 
     discard CloseHandle(f1)
     discard CloseHandle(f2)
 
-    if not success: OSError()
+    if not success: OSError(lastErr)
   else:
     var a, b: TStat
     if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
-      OSError()
+      OSError(OSLastError())
     else:
       result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
 
@@ -738,17 +820,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
     when useWinUnicode:
       let s = newWideCString(source)
       let d = newWideCString(dest)
-      if CopyFileW(s, d, 0'i32) == 0'i32: OSError()
+      if CopyFileW(s, d, 0'i32) == 0'i32: OSError(OSLastError())
     else:
-      if CopyFileA(source, dest, 0'i32) == 0'i32: OSError()
+      if CopyFileA(source, dest, 0'i32) == 0'i32: OSError(OSLastError())
   else:
     # generic version of copyFile which works for any platform:
     const bufSize = 8000 # better for memory manager
     var d, s: TFile
-    if not open(s, source): OSError()
+    if not open(s, source): OSError(OSLastError())
     if not open(d, dest, fmWrite):
       close(s)
-      OSError()
+      OSError(OSLastError())
     var buf = alloc(bufsize)
     while True:
       var bytesread = readBuffer(s, buf, bufsize)
@@ -758,7 +840,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
           dealloc(buf)
           close(s)
           close(d)
-          OSError()
+          OSError(OSLastError())
       if bytesread != bufSize: break
     dealloc(buf)
     close(s)
@@ -767,7 +849,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
 proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", 
   tags: [FReadIO, FWriteIO].} =
   ## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
-  if crename(source, dest) != 0'i32: OSError()
+  if crename(source, dest) != 0'i32:
+    raise newException(EOS, $strerror(errno))
 
 when not defined(ENOENT):
   var ENOENT {.importc, header: "<errno.h>".}: cint
@@ -775,7 +858,8 @@ when not defined(ENOENT):
 proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
   ## Removes the `file`. If this fails, `EOS` is raised. This does not fail
   ## if the file never existed in the first place.
-  if cremove(file) != 0'i32 and errno != ENOENT: OSError()
+  if cremove(file) != 0'i32 and errno != ENOENT:
+    raise newException(EOS, $strerror(errno))
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", 
   tags: [FExecIO].} =
@@ -907,14 +991,14 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
     indx = high(environment)
   when defined(unix):
     if cputenv(environment[indx]) != 0'i32:
-      OSError()
+      OSError(OSLastError())
   else:
     when useWinUnicode:
       var k = newWideCString(key)
       var v = newWideCString(val)
-      if SetEnvironmentVariableW(k, v) == 0'i32: OSError()
+      if SetEnvironmentVariableW(k, v) == 0'i32: OSError(OSLastError())
     else:
-      if SetEnvironmentVariableA(key, val) == 0'i32: OSError()
+      if SetEnvironmentVariableA(key, val) == 0'i32: OSError(OSLastError())
 
 iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
   ## Iterate over all `environments variables`:idx:. In the first component 
@@ -1044,10 +1128,12 @@ proc rawRemoveDir(dir: string) =
       wrapUnary(res, RemoveDirectoryW, dir)
     else:
       var res = RemoveDirectoryA(dir)
-    if res == 0'i32 and GetLastError() != 3'i32 and 
-        GetLastError() != 18'i32: OSError()
+    let lastError = OSLastError()
+    if res == 0'i32 and lastError.int32 != 3'i32 and 
+        lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
+      OSError(lastError)
   else:
-    if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
+    if rmdir(dir) != 0'i32 and errno != ENOENT: OSError(OSLastError())
 
 proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
   FWriteDir, FReadDir].} =
@@ -1065,14 +1151,14 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
 proc rawCreateDir(dir: string) =
   when defined(unix):
     if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
-      OSError()
+      OSError(OSLastError())
   else:
     when useWinUnicode:
       wrapUnary(res, CreateDirectoryW, dir)
     else:
       var res = CreateDirectoryA(dir)
     if res == 0'i32 and GetLastError() != 183'i32:
-      OSError()
+      OSError(OSLastError())
 
 proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
   ## Creates the `directory`:idx: `dir`.
@@ -1213,7 +1299,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
   ## permission is available in any case.
   when defined(posix):
     var a: TStat
-    if stat(filename, a) < 0'i32: OSError()
+    if stat(filename, a) < 0'i32: OSError(OSLastError())
     result = {}
     if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
     if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
@@ -1231,7 +1317,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
       wrapUnary(res, GetFileAttributesW, filename)
     else:
       var res = GetFileAttributesA(filename)
-    if res == -1'i32: OSError()
+    if res == -1'i32: OSError(OSLastError())
     if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
       result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, 
                 fpOthersExec, fpOthersRead}
@@ -1257,13 +1343,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
     if fpOthersWrite in permissions: p = p or S_IWOTH
     if fpOthersExec in permissions: p = p or S_IXOTH
     
-    if chmod(filename, p) != 0: OSError()
+    if chmod(filename, p) != 0: OSError(OSLastError())
   else:
     when useWinUnicode:
       wrapUnary(res, GetFileAttributesW, filename)
     else:
       var res = GetFileAttributesA(filename)
-    if res == -1'i32: OSError()
+    if res == -1'i32: OSError(OSLastError())
     if fpUserWrite in permissions: 
       res = res and not FILE_ATTRIBUTE_READONLY
     else:
@@ -1272,7 +1358,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
       wrapBinary(res2, SetFileAttributesW, filename, res)
     else:
       var res2 = SetFileAttributesA(filename, res)
-    if res2 == - 1'i32: OSError()
+    if res2 == - 1'i32: OSError(OSLastError())
   
 proc inclFilePermissions*(filename: string, 
                           permissions: set[TFilePermission]) {.
@@ -1368,6 +1454,9 @@ when defined(macosx):
 
 proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
   ## Returns the filename of the application's executable.
+  ##
+  ## This procedure will resolve symlinks.
+  ##
   ## **Note**: This does not work reliably on BSD.
 
   # Linux: /proc/<pid>/exe
@@ -1397,6 +1486,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
     result = newString(int(size))
     if getExecPath2(result, size):
       result = "" # error!
+    if result.len > 0:
+      result = result.expandFilename
   else:
     # little heuristic that may work on other POSIX-like systems:
     result = string(getEnv("_"))
@@ -1443,7 +1534,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
   when defined(windows):
     var a: TWin32FindData
     var resA = findfirstFile(file, a)
-    if resA == -1: OSError()
+    if resA == -1: OSError(OSLastError())
     result = rdFileSize(a)
     findclose(resA)
   else:
@@ -1451,7 +1542,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
     if open(f, file): 
       result = getFileSize(f)
       close(f)
-    else: OSError()
+    else: OSError(OSLastError())
 
 proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} = 
   ## Searches for `exe` in the current working directory and then
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index aa4fbe32d..48a559c4e 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -370,6 +370,7 @@ when defined(Windows) and not defined(useNimRtl):
     else:
       success = winlean.CreateProcessA(nil,
         cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
+    let lastError = OSLastError()
 
     if poParentStreams notin options:
       FileClose(si.hStdInput)
@@ -379,7 +380,7 @@ when defined(Windows) and not defined(useNimRtl):
 
     if e != nil: dealloc(e)
     dealloc(cmdl)
-    if success == 0: OSError()
+    if success == 0: OSError(lastError)
     # Close the handle now so anyone waiting is woken:
     discard closeHandle(procInfo.hThread)
     result.FProcessHandle = procInfo.hProcess
@@ -450,7 +451,7 @@ when defined(Windows) and not defined(useNimRtl):
       var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
         NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
     if res == 0:
-      OSError()
+      OSError(OSLastError())
     else:
       Process = ProcInfo.hProcess
       discard CloseHandle(ProcInfo.hThread)
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index 57fa0b144..8e45032c8 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -175,6 +175,15 @@ proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult =
   if ret == L:
     return ReadFullLine
 
+proc checkCloseSocket(client: PAsyncClient) =
+  if not client.c.isClosed:
+    if client.c.isSendDataBuffered:
+      client.c.setHandleWrite do (s: PAsyncSocket):
+        if not s.isClosed and not s.isSendDataBuffered:
+          s.close()
+          s.delHandleWrite()
+    else: client.c.close()
+    
 proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
   case client.mode
   of ClientReadChar:
@@ -206,7 +215,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
         client.mode = ClientReadContent
       else:
         s.handleRequest(client.c, client.input, client.headers)
-        if not client.c.isClosed: client.c.close()
+        checkCloseSocket(client)
     of ReadPartialLine, ReadDisconnected, ReadNone: return
   of ClientReadContent:
     let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
@@ -215,11 +224,11 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) =
       case ret
       of ReadFullLine:
         s.handleRequest(client.c, client.input, client.headers)
-        if not client.c.isClosed: client.c.close()
+        checkCloseSocket(client)
       of ReadPartialLine, ReadDisconnected, ReadNone: return
     else:
       s.handleRequest(client.c, client.input, client.headers)
-      if not client.c.isClosed: client.c.close()
+      checkCloseSocket(client)
 
 proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
   var client: PAsyncSocket
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 603fd612b..33df72d38 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -231,7 +231,7 @@ when defined(ssl):
     if err == 0:
       raise newException(ESSL, "No error reported.")
     if err == -1:
-      OSError()
+      OSError(OSLastError())
     var errStr = ErrErrorString(err, nil)
     raise newException(ESSL, $errStr)
 
@@ -347,24 +347,23 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
         else: SSLError("Unknown Error")
   
   if err == -1 and not (when defined(ssl): socket.isSSL else: false):
+    let lastError = OSLastError()
     if async:
       when defined(windows):
-        # TODO: Test on Windows
-        var err = WSAGetLastError()
-        if err == WSAEWOULDBLOCK:
+        if lastError.int32 == WSAEWOULDBLOCK:
           return
-        else: OSError()
+        else: OSError(lastError)
       else:
-        if errno == EAGAIN or errno == EWOULDBLOCK:
+        if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
           return
-        else: OSError()
-    else: OSError()
+        else: OSError(lastError)
+    else: OSError(lastError)
 
 proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
   ## Marks ``socket`` as accepting connections. 
   ## ``Backlog`` specifies the maximum length of the 
   ## queue of pending connections.
-  if listen(socket.fd, cint(backlog)) < 0'i32: OSError()
+  if listen(socket.fd, cint(backlog)) < 0'i32: OSError(OSLastError())
 
 proc invalidIp4(s: string) {.noreturn, noinline.} =
   raise newException(EInvalidValue, "invalid ip4 address: " & s)
@@ -403,7 +402,7 @@ template gaiNim(a, p, h, list: expr): stmt =
     var gaiResult = getAddrInfo(a, $p, addr(h), list)
     if gaiResult != 0'i32:
       when defined(windows):
-        OSError()
+        OSError(OSLastError())
       else:
         OSError($gai_strerror(gaiResult))
 
@@ -423,7 +422,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
     name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
     if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
                   sizeof(name).TSockLen) < 0'i32:
-      OSError()
+      OSError(OSLastError())
   else:
     var hints: TAddrInfo
     var aiList: ptr TAddrInfo = nil
@@ -432,21 +431,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
     hints.ai_protocol = toInt(IPPROTO_TCP)
     gaiNim(address, port, hints, aiList)
     if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
-      OSError()
-
-when false:
-  proc bindAddr*(socket: TSocket, port = TPort(0)) =
-    ## binds a port number to a socket.
-    var name: Tsockaddr_in
-    when defined(Windows):
-      name.sin_family = int16(ord(AF_INET))
-    else:
-      name.sin_family = posix.AF_INET
-    name.sin_port = sockets.htons(int16(port))
-    name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
-    if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)),
-                  sizeof(name).TSockLen) < 0'i32:
-      OSError()
+      OSError(OSLastError())
   
 proc getSockName*(socket: TSocket): TPort = 
   ## returns the socket's associated port number.
@@ -460,7 +445,7 @@ proc getSockName*(socket: TSocket): TPort =
   var namelen = sizeof(name).TSockLen
   if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
                  addr(namelen)) == -1'i32:
-    OSError()
+    OSError(OSLastError())
   result = TPort(sockets.ntohs(name.sin_port))
 
 template acceptAddrPlain(noClientRet, successRet: expr, 
@@ -472,26 +457,25 @@ template acceptAddrPlain(noClientRet, successRet: expr,
                     addr(addrLen))
   
   if sock < 0:
-    # TODO: Test on Windows.
+    let err = OSLastError()
     when defined(windows):
-      var err = WSAGetLastError()
-      if err == WSAEINPROGRESS:
+      if err.int32 == WSAEINPROGRESS:
         client = InvalidSocket
         address = ""
         when noClientRet.int == -1:
           return
         else:
           return noClientRet
-      else: OSError()
+      else: OSError(err)
     else:
-      if errno == EAGAIN or errno == EWOULDBLOCK:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
         client = InvalidSocket
         address = ""
         when noClientRet.int == -1:
           return
         else:
           return noClientRet
-      else: OSError()
+      else: OSError(err)
   else:
     client.fd = sock
     client.isBuffered = server.isBuffered
@@ -644,7 +628,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
     var s = winlean.getservbyname(name, proto)
   else:
     var s = posix.getservbyname(name, proto)
-  if s == nil: OSError()
+  if s == nil: OSError(OSLastError())
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = TPort(s.s_port)
@@ -656,7 +640,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
     var s = winlean.getservbyport(ze(int16(port)).cint, proto)
   else:
     var s = posix.getservbyport(ze(int16(port)).cint, proto)
-  if s == nil: OSError()
+  if s == nil: OSError(OSLastError())
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = TPort(s.s_port)
@@ -670,7 +654,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
   when defined(windows):
     var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
                                   cint(sockets.AF_INET))
-    if s == nil: OSError()
+    if s == nil: OSError(OSLastError())
   else:
     var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen, 
                                 cint(posix.AF_INET))
@@ -687,7 +671,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrType = AF_INET6
     else:
-      OSError("unknown h_addrtype")
+      raise newException(EOS, "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -697,7 +681,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
     var s = winlean.gethostbyname(name)
   else:
     var s = posix.gethostbyname(name)
-  if s == nil: OSError()
+  if s == nil: OSError(OSLastError())
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
   when defined(windows): 
@@ -708,7 +692,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrType = AF_INET6
     else:
-      OSError("unknown h_addrtype")
+      raise newException(EOS, "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -719,7 +703,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
   var size = sizeof(res).TSockLen
   if getsockopt(socket.fd, cint(level), cint(optname), 
                 addr(res), addr(size)) < 0'i32:
-    OSError()
+    OSError(OSLastError())
   result = int(res)
 
 proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
@@ -728,7 +712,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
   var value = cint(optval)
   if setsockopt(socket.fd, cint(level), cint(optname), addr(value),  
                 sizeof(value).TSockLen) < 0'i32:
-    OSError()
+    OSError(OSLastError())
 
 proc connect*(socket: TSocket, address: string, port = TPort(0), 
               af: TDomain = AF_INET) {.tags: [FReadIO].} =
@@ -746,15 +730,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
   gaiNim(address, port, hints, aiList)
   # try all possibilities:
   var success = false
+  var lastError: TOSErrorCode
   var it = aiList
   while it != nil:
     if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
       success = true
       break
+    else: lastError = OSLastError()
     it = it.ai_next
 
   freeaddrinfo(aiList)
-  if not success: OSError()
+  if not success: OSError(lastError)
   
   when defined(ssl):
     if socket.isSSL:
@@ -807,6 +793,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
   gaiNim(name, port, hints, aiList)
   # try all possibilities:
   var success = false
+  var lastError: TOSErrorCode
   var it = aiList
   while it != nil:
     var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
@@ -814,22 +801,21 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
       success = true
       break
     else:
-      # TODO: Test on Windows.
+      lastError = OSLastError()
       when defined(windows):
-        var err = WSAGetLastError()
         # Windows EINTR doesn't behave same as POSIX.
-        if err == WSAEWOULDBLOCK:
+        if lastError.int32 == WSAEWOULDBLOCK:
           success = true
           break
       else:
-        if errno == EINTR or errno == EINPROGRESS:
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
           success = true
           break
         
     it = it.ai_next
 
   freeaddrinfo(aiList)
-  if not success: OSError()
+  if not success: OSError(lastError)
   when defined(ssl):
     if socket.isSSL:
       socket.sslNoHandshake = true
@@ -1110,7 +1096,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
     var s = @[socket]
     var startTime = epochTime()
     let selRet = select(s, timeout - int(waited * 1000.0))
-    if selRet < 0: OSError()
+    if selRet < 0: OSError(OSLastError())
     if selRet != 1:
       raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
     waited += (epochTime() - startTime)
@@ -1259,14 +1245,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
     var c: char
     discard waitFor(socket, waited, timeout, 1, "readLine")
     var n = recv(socket, addr(c), 1)
-    if n < 0: OSError()
+    if n < 0: OSError(OSLastError())
     elif n == 0: return
     if c == '\r':
       discard waitFor(socket, waited, timeout, 1, "readLine")
       n = peekChar(socket, c)
       if n > 0 and c == '\L':
         discard recv(socket, addr(c), 1)
-      elif n <= 0: OSError()
+      elif n <= 0: OSError(OSLastError())
       addNlIfEmpty()
       return
     elif c == '\L': 
@@ -1326,6 +1312,7 @@ proc readLineAsync*(socket: TSocket,
   while true:
     var c: char
     var n = recv(socket, addr(c), 1)
+    #echo(n)
     if n < 0:
       if line.len == 0: errorOrNone else: return ReadPartialLine
     elif n == 0: 
@@ -1352,7 +1339,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
   var pos = 0
   while true:
     var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
-    if bytesRead == -1: OSError()
+    if bytesRead == -1: OSError(OSLastError())
     setLen(result.string, pos + bytesRead)
     if bytesRead != bufSize-1: break
     # increase capacity:
@@ -1364,7 +1351,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
     while true:
       var bytesRead = recv(socket, cstring(buf), bufSize-1)
       # Error
-      if bytesRead == -1: OSError()
+      if bytesRead == -1: OSError(OSLastError())
       
       buf[bytesRead] = '\0' # might not be necessary
       setLen(buf, bytesRead)
@@ -1421,16 +1408,15 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
           else: SSLError("Unknown Error")
           
     if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
+      let err = OSLastError()
       when defined(windows):
-        # TODO: Test on Windows
-        var err = WSAGetLastError()
-        if err == WSAEWOULDBLOCK:
+        if err.int32 == WSAEWOULDBLOCK:
           return False
-        else: OSError()
+        else: OSError(err)
       else:
-        if errno == EAGAIN or errno == EWOULDBLOCK:
+        if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
           return False
-        else: OSError()
+        else: OSError(err)
 
     setLen(s.string, pos + bytesRead)
     if bytesRead != bufSize-1: break
@@ -1475,16 +1461,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
   result = true
   var callRes = recvFrom(socket, data, length, address, port, flags)
   if callRes < 0:
+    let err = OSLastError()
     when defined(windows):
-      # TODO: Test on Windows
-      var err = WSAGetLastError()
-      if err == WSAEWOULDBLOCK:
+      if err.int32 == WSAEWOULDBLOCK:
         return False
-      else: OSError()
+      else: OSError(err)
     else:
-      if errno == EAGAIN or errno == EWOULDBLOCK:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
         return False
-      else: OSError()
+      else: OSError(err)
 
 proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
   ## skips all the data that is pending for the socket
@@ -1531,7 +1516,7 @@ proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
       if socket.isSSL:
         SSLError()
     
-    OSError()
+    OSError(OSLastError())
 
 proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
   ## sends data to a non-blocking socket.
@@ -1561,16 +1546,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
       else:
         return
   if result == -1:
+    let err = OSLastError()
     when defined(windows):
-      var err = WSAGetLastError()
-      # TODO: Test on windows.
-      if err == WSAEINPROGRESS:
+      if err.int32 == WSAEINPROGRESS:
         return 0
-      else: OSError()
+      else: OSError(err)
     else:
-      if errno == EAGAIN or errno == EWOULDBLOCK:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
         return 0
-      else: OSError()
+      else: OSError(err)
   
 
 proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
@@ -1626,15 +1610,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
   when defined(Windows):
     var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
     if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
-      OSError()
+      OSError(OSLastError())
   else: # BSD sockets
     var x: int = fcntl(s.fd, F_GETFL, 0)
     if x == -1:
-      OSError()
+      OSError(OSLastError())
     else:
       var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
       if fcntl(s.fd, F_SETFL, mode) == -1:
-        OSError()
+        OSError(OSLastError())
   s.nonblocking = not blocking
   
 proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
@@ -1665,6 +1649,6 @@ proc getFD*(socket: TSocket): cint = return socket.fd
 
 when defined(Windows):
   var wsa: TWSADATA
-  if WSAStartup(0x0101'i16, wsa) != 0: OSError()
+  if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
 
 
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 3be6088ed..9b69bbaa4 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -1,312 +1,310 @@
-#

-#

-#            Nimrod's Runtime Library

-#        (c) Copyright 2012 Andreas Rumpf

-#

-#    See the file "copying.txt", included in this

-#    distribution, for details about the copyright.

-#

-

-## This module contains a few procedures to control the *terminal*

-## (also called *console*). On UNIX, the implementation simply uses ANSI escape

-## sequences and does not depend on any other module, on Windows it uses the

-## Windows API.

-## Changing the style is permanent even after program termination! Use the

-## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.

-

-import macros

-

-when defined(windows):

-  import windows, os

-

-  var

-    conHandle: THandle

-  # = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)

-

-  block:

-    var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)

-    if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),

-                       addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:

-      OSError()

-

-  proc getCursorPos(): tuple [x,y: int] =

-    var c: TCONSOLE_SCREEN_BUFFER_INFO

-    if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError()

-    return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))

-

-  proc getAttributes(): int16 =

-    var c: TCONSOLE_SCREEN_BUFFER_INFO

-    # workaround Windows bugs: try several times

-    if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:

-      return c.wAttributes

-    else:

-      OSError()

-    return 0x70'i16 # ERROR: return white background, black text

-

-  var

-    oldAttr = getAttributes()

-

-proc setCursorPos*(x, y: int) =

-  ## sets the terminal's cursor to the (x,y) position. (0,0) is the

-  ## upper left of the screen.

-  when defined(windows):

-    var c: TCoord

-    c.x = int16(x)

-    c.y = int16(y)

-    if SetConsoleCursorPosition(conHandle, c) == 0: OSError()

-  else:

-    stdout.write("\e[" & $y & ';' & $x & 'f')

-

-proc setCursorXPos*(x: int) =

-  ## sets the terminal's cursor to the x position. The y position is

-  ## not changed.

-  when defined(windows):

-    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO

-    var hStdout = conHandle

-    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()

-    var origin = scrbuf.dwCursorPosition

-    origin.x = int16(x)

-    if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()

-  else:

-    stdout.write("\e[" & $x & 'G')

-

-when defined(windows):

-  proc setCursorYPos*(y: int) =

-    ## sets the terminal's cursor to the y position. The x position is

-    ## not changed. **Warning**: This is not supported on UNIX!

-    when defined(windows):

-      var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO

-      var hStdout = conHandle

-      if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()

-      var origin = scrbuf.dwCursorPosition

-      origin.y = int16(y)

-      if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()

-    else:

-      nil

-

-proc CursorUp*(count=1) =

-  ## Moves the cursor up by `count` rows.

-  when defined(windows):

-    var p = getCursorPos()

-    dec(p.y, count)

-    setCursorPos(p.x, p.y)

-  else:

-    stdout.write("\e[" & $count & 'A')

-

-proc CursorDown*(count=1) =

-  ## Moves the cursor down by `count` rows.

-  when defined(windows):

-    var p = getCursorPos()

-    inc(p.y, count)

-    setCursorPos(p.x, p.y)

-  else:

-    stdout.write("\e[" & $count & 'B')

-

-proc CursorForward*(count=1) =

-  ## Moves the cursor forward by `count` columns.

-  when defined(windows):

-    var p = getCursorPos()

-    inc(p.x, count)

-    setCursorPos(p.x, p.y)

-  else:

-    stdout.write("\e[" & $count & 'C')

-

-proc CursorBackward*(count=1) =

-  ## Moves the cursor backward by `count` columns.

-  when defined(windows):

-    var p = getCursorPos()

-    dec(p.x, count)

-    setCursorPos(p.x, p.y)

-  else:

-    stdout.write("\e[" & $count & 'D')

-

-when true:

-  nil

-else:

-  proc EraseLineEnd* =

-    ## Erases from the current cursor position to the end of the current line.

-    when defined(windows):

-      nil

-    else:

-      stdout.write("\e[K")

-

-  proc EraseLineStart* =

-    ## Erases from the current cursor position to the start of the current line.

-    when defined(windows):

-      nil

-    else:

-      stdout.write("\e[1K")

-

-  proc EraseDown* =

-    ## Erases the screen from the current line down to the bottom of the screen.

-    when defined(windows):

-      nil

-    else:

-      stdout.write("\e[J")

-

-  proc EraseUp* =

-    ## Erases the screen from the current line up to the top of the screen.

-    when defined(windows):

-      nil

-    else:

-      stdout.write("\e[1J")

-

-proc EraseLine* =

-  ## Erases the entire current line.

-  when defined(windows):

-    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO

-    var numwrote: DWORD

-    var hStdout = conHandle

-    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()

-    var origin = scrbuf.dwCursorPosition

-    origin.x = 0'i16

-    if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()

-    var ht = scrbuf.dwSize.Y - origin.Y

-    var wt = scrbuf.dwSize.X - origin.X

-    if FillConsoleOutputCharacter(hStdout,' ', ht*wt,

-                                  origin, addr(numwrote)) == 0:

-      OSError()

-    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,

-                                  scrbuf.dwCursorPosition, addr(numwrote)) == 0:

-      OSError()

-  else:

-    stdout.write("\e[2K")

-    setCursorXPos(0)

-

-proc EraseScreen* =

-  ## Erases the screen with the background colour and moves the cursor to home.

-  when defined(windows):

-    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO

-    var numwrote: DWORD

-    var origin: TCoord # is inititalized to 0, 0

-    var hStdout = conHandle

-    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()

-    if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,

-                                  origin, addr(numwrote)) == 0:

-      OSError()

-    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,

-                                  scrbuf.dwSize.X * scrbuf.dwSize.Y,

-                                  origin, addr(numwrote)) == 0:

-      OSError()

-    setCursorXPos(0)

-  else:

-    stdout.write("\e[2J")

-

-proc ResetAttributes* {.noconv.} =

-  ## resets all attributes; it is advisable to register this as a quit proc

-  ## with ``system.addQuitProc(resetAttributes)``.

-  when defined(windows):

-    discard SetConsoleTextAttribute(conHandle, oldAttr)

-  else:

-    stdout.write("\e[0m")

-

-type

-  TStyle* = enum         ## different styles for text output

-    styleBright = 1,     ## bright text

-    styleDim,            ## dim text

-    styleUnknown,        ## unknown

-    styleUnderscore = 4, ## underscored text

-    styleBlink,          ## blinking/bold text

-    styleReverse = 7,    ## unknown

-    styleHidden          ## hidden text

-

-when not defined(windows):

-  var

-    # XXX: These better be thread-local

-    gFG = 0

-    gBG = 0

-

-proc setStyle*(style: set[TStyle]) =

-  ## sets the terminal style

-  when defined(windows):

-    var a = 0'i16

-    if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)

-    if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)

-    if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO

-    if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE

-    discard SetConsoleTextAttribute(conHandle, a)

-  else:

-    for s in items(style):

-      stdout.write("\e[" & $ord(s) & 'm')

-

-proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =

-  ## writes the text `txt` in a given `style`.

-  when defined(windows):

-    var old = getAttributes()

-    setStyle(style)

-    stdout.write(txt)

-    discard SetConsoleTextAttribute(conHandle, old)

-  else:

-    setStyle(style)

-    stdout.write(txt)

-    resetAttributes()

-    if gFG != 0:

-      stdout.write("\e[" & $ord(gFG) & 'm')

-    if gBG != 0:

-      stdout.write("\e[" & $ord(gBG) & 'm')

-

-type

-  TForegroundColor* = enum ## terminal's foreground colors

-    fgBlack = 30,          ## black

-    fgRed,                 ## red

-    fgGreen,               ## green

-    fgYellow,              ## yellow

-    fgBlue,                ## blue

-    fgMagenta,             ## magenta

-    fgCyan,                ## cyan

-    fgWhite                ## white

-

-  TBackgroundColor* = enum ## terminal's background colors

-    bgBlack = 40,          ## black

-    bgRed,                 ## red

-    bgGreen,               ## green

-    bgYellow,              ## yellow

-    bgBlue,                ## blue

-    bgMagenta,             ## magenta

-    bgCyan,                ## cyan

-    bgWhite                ## white

-

-proc setForegroundColor*(fg: TForegroundColor, bright=false) =

-  ## sets the terminal's foreground color

-  when defined(windows):

-    var old = getAttributes() and not 0x0007

-    if bright:

-      old = old or FOREGROUND_INTENSITY

-    const lookup: array [TForegroundColor, int] = [

-      0,

-      (FOREGROUND_RED),

-      (FOREGROUND_GREEN),

-      (FOREGROUND_RED or FOREGROUND_GREEN),

-      (FOREGROUND_BLUE),

-      (FOREGROUND_RED or FOREGROUND_BLUE),

-      (FOREGROUND_BLUE or FOREGROUND_GREEN),

-      (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]

-    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))

-  else:

-    gFG = ord(fg)

-    if bright: inc(gFG, 60)

-    stdout.write("\e[" & $gFG & 'm')

-

-proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =

-  ## sets the terminal's background color

-  when defined(windows):

-    var old = getAttributes() and not 0x0070

-    if bright:

-      old = old or BACKGROUND_INTENSITY

-    const lookup: array [TBackgroundColor, int] = [

-      0,

-      (BACKGROUND_RED),

-      (BACKGROUND_GREEN),

-      (BACKGROUND_RED or BACKGROUND_GREEN),

-      (BACKGROUND_BLUE),

-      (BACKGROUND_RED or BACKGROUND_BLUE),

-      (BACKGROUND_BLUE or BACKGROUND_GREEN),

-      (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]

-    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))

-  else:

-    gBG = ord(bg)

-    if bright: inc(gBG, 60)

-    stdout.write("\e[" & $gBG & 'm')

+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains a few procedures to control the *terminal*
+## (also called *console*). On UNIX, the implementation simply uses ANSI escape
+## sequences and does not depend on any other module, on Windows it uses the
+## Windows API.
+## Changing the style is permanent even after program termination! Use the
+## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.
+
+import macros
+
+when defined(windows):
+  import windows, os
+
+  var
+    conHandle: THandle
+  # = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
+
+  block:
+    var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
+    if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
+                       addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      OSError()
+
+  proc getCursorPos(): tuple [x,y: int] =
+    var c: TCONSOLE_SCREEN_BUFFER_INFO
+    if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError()
+    return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
+
+  proc getAttributes(): int16 =
+    var c: TCONSOLE_SCREEN_BUFFER_INFO
+    # workaround Windows bugs: try several times
+    if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
+      return c.wAttributes
+    return 0x70'i16 # ERROR: return white background, black text
+
+  var
+    oldAttr = getAttributes()
+
+proc setCursorPos*(x, y: int) =
+  ## sets the terminal's cursor to the (x,y) position. (0,0) is the
+  ## upper left of the screen.
+  when defined(windows):
+    var c: TCoord
+    c.x = int16(x)
+    c.y = int16(y)
+    if SetConsoleCursorPosition(conHandle, c) == 0: OSError()
+  else:
+    stdout.write("\e[" & $y & ';' & $x & 'f')
+
+proc setCursorXPos*(x: int) =
+  ## sets the terminal's cursor to the x position. The y position is
+  ## not changed.
+  when defined(windows):
+    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
+    var hStdout = conHandle
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
+    var origin = scrbuf.dwCursorPosition
+    origin.x = int16(x)
+    if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
+  else:
+    stdout.write("\e[" & $x & 'G')
+
+when defined(windows):
+  proc setCursorYPos*(y: int) =
+    ## sets the terminal's cursor to the y position. The x position is
+    ## not changed. **Warning**: This is not supported on UNIX!
+    when defined(windows):
+      var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
+      var hStdout = conHandle
+      if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
+      var origin = scrbuf.dwCursorPosition
+      origin.y = int16(y)
+      if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
+    else:
+      nil
+
+proc CursorUp*(count=1) =
+  ## Moves the cursor up by `count` rows.
+  when defined(windows):
+    var p = getCursorPos()
+    dec(p.y, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'A')
+
+proc CursorDown*(count=1) =
+  ## Moves the cursor down by `count` rows.
+  when defined(windows):
+    var p = getCursorPos()
+    inc(p.y, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'B')
+
+proc CursorForward*(count=1) =
+  ## Moves the cursor forward by `count` columns.
+  when defined(windows):
+    var p = getCursorPos()
+    inc(p.x, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'C')
+
+proc CursorBackward*(count=1) =
+  ## Moves the cursor backward by `count` columns.
+  when defined(windows):
+    var p = getCursorPos()
+    dec(p.x, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'D')
+
+when true:
+  nil
+else:
+  proc EraseLineEnd* =
+    ## Erases from the current cursor position to the end of the current line.
+    when defined(windows):
+      nil
+    else:
+      stdout.write("\e[K")
+
+  proc EraseLineStart* =
+    ## Erases from the current cursor position to the start of the current line.
+    when defined(windows):
+      nil
+    else:
+      stdout.write("\e[1K")
+
+  proc EraseDown* =
+    ## Erases the screen from the current line down to the bottom of the screen.
+    when defined(windows):
+      nil
+    else:
+      stdout.write("\e[J")
+
+  proc EraseUp* =
+    ## Erases the screen from the current line up to the top of the screen.
+    when defined(windows):
+      nil
+    else:
+      stdout.write("\e[1J")
+
+proc EraseLine* =
+  ## Erases the entire current line.
+  when defined(windows):
+    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
+    var numwrote: DWORD
+    var hStdout = conHandle
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
+    var origin = scrbuf.dwCursorPosition
+    origin.x = 0'i16
+    if SetConsoleCursorPosition(conHandle, origin) == 0: OSError()
+    var ht = scrbuf.dwSize.Y - origin.Y
+    var wt = scrbuf.dwSize.X - origin.X
+    if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
+                                  origin, addr(numwrote)) == 0:
+      OSError()
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
+                                  scrbuf.dwCursorPosition, addr(numwrote)) == 0:
+      OSError()
+  else:
+    stdout.write("\e[2K")
+    setCursorXPos(0)
+
+proc EraseScreen* =
+  ## Erases the screen with the background colour and moves the cursor to home.
+  when defined(windows):
+    var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
+    var numwrote: DWORD
+    var origin: TCoord # is inititalized to 0, 0
+    var hStdout = conHandle
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError()
+    if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
+                                  origin, addr(numwrote)) == 0:
+      OSError()
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
+                                  scrbuf.dwSize.X * scrbuf.dwSize.Y,
+                                  origin, addr(numwrote)) == 0:
+      OSError()
+    setCursorXPos(0)
+  else:
+    stdout.write("\e[2J")
+
+proc ResetAttributes* {.noconv.} =
+  ## resets all attributes; it is advisable to register this as a quit proc
+  ## with ``system.addQuitProc(resetAttributes)``.
+  when defined(windows):
+    discard SetConsoleTextAttribute(conHandle, oldAttr)
+  else:
+    stdout.write("\e[0m")
+
+type
+  TStyle* = enum         ## different styles for text output
+    styleBright = 1,     ## bright text
+    styleDim,            ## dim text
+    styleUnknown,        ## unknown
+    styleUnderscore = 4, ## underscored text
+    styleBlink,          ## blinking/bold text
+    styleReverse = 7,    ## unknown
+    styleHidden          ## hidden text
+
+when not defined(windows):
+  var
+    # XXX: These better be thread-local
+    gFG = 0
+    gBG = 0
+
+proc setStyle*(style: set[TStyle]) =
+  ## sets the terminal style
+  when defined(windows):
+    var a = 0'i16
+    if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)
+    if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)
+    if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO
+    if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE
+    discard SetConsoleTextAttribute(conHandle, a)
+  else:
+    for s in items(style):
+      stdout.write("\e[" & $ord(s) & 'm')
+
+proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =
+  ## writes the text `txt` in a given `style`.
+  when defined(windows):
+    var old = getAttributes()
+    setStyle(style)
+    stdout.write(txt)
+    discard SetConsoleTextAttribute(conHandle, old)
+  else:
+    setStyle(style)
+    stdout.write(txt)
+    resetAttributes()
+    if gFG != 0:
+      stdout.write("\e[" & $ord(gFG) & 'm')
+    if gBG != 0:
+      stdout.write("\e[" & $ord(gBG) & 'm')
+
+type
+  TForegroundColor* = enum ## terminal's foreground colors
+    fgBlack = 30,          ## black
+    fgRed,                 ## red
+    fgGreen,               ## green
+    fgYellow,              ## yellow
+    fgBlue,                ## blue
+    fgMagenta,             ## magenta
+    fgCyan,                ## cyan
+    fgWhite                ## white
+
+  TBackgroundColor* = enum ## terminal's background colors
+    bgBlack = 40,          ## black
+    bgRed,                 ## red
+    bgGreen,               ## green
+    bgYellow,              ## yellow
+    bgBlue,                ## blue
+    bgMagenta,             ## magenta
+    bgCyan,                ## cyan
+    bgWhite                ## white
+
+proc setForegroundColor*(fg: TForegroundColor, bright=false) =
+  ## sets the terminal's foreground color
+  when defined(windows):
+    var old = getAttributes() and not 0x0007
+    if bright:
+      old = old or FOREGROUND_INTENSITY
+    const lookup: array [TForegroundColor, int] = [
+      0,
+      (FOREGROUND_RED),
+      (FOREGROUND_GREEN),
+      (FOREGROUND_RED or FOREGROUND_GREEN),
+      (FOREGROUND_BLUE),
+      (FOREGROUND_RED or FOREGROUND_BLUE),
+      (FOREGROUND_BLUE or FOREGROUND_GREEN),
+      (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]
+    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))
+  else:
+    gFG = ord(fg)
+    if bright: inc(gFG, 60)
+    stdout.write("\e[" & $gFG & 'm')
+
+proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
+  ## sets the terminal's background color
+  when defined(windows):
+    var old = getAttributes() and not 0x0070
+    if bright:
+      old = old or BACKGROUND_INTENSITY
+    const lookup: array [TBackgroundColor, int] = [
+      0,
+      (BACKGROUND_RED),
+      (BACKGROUND_GREEN),
+      (BACKGROUND_RED or BACKGROUND_GREEN),
+      (BACKGROUND_BLUE),
+      (BACKGROUND_RED or BACKGROUND_BLUE),
+      (BACKGROUND_BLUE or BACKGROUND_GREEN),
+      (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]
+    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))
+  else:
+    gBG = ord(bg)
+    if bright: inc(gBG, 60)
+    stdout.write("\e[" & $gBG & 'm')
 
 proc isatty*(f: TFile): bool =
   ## returns true if `f` is associated with a terminal device.
@@ -318,33 +316,33 @@ proc isatty*(f: TFile): bool =
       importc: "_isatty", header: "<io.h>".}
   
   result = isatty(fileHandle(f)) != 0'i32
-

-proc styledEchoProcessArg(s: string)               = write stdout, s

-proc styledEchoProcessArg(style: TStyle)           = setStyle({style})

-proc styledEchoProcessArg(style: set[TStyle])      = setStyle style

-proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color

-proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color

-

+
+proc styledEchoProcessArg(s: string)               = write stdout, s
+proc styledEchoProcessArg(style: TStyle)           = setStyle({style})
+proc styledEchoProcessArg(style: set[TStyle])      = setStyle style
+proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
+proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
+
 macro styledEcho*(m: varargs[expr]): stmt =
   ## to be documented.
   let m = callsite()
-  result = newNimNode(nnkStmtList)

-

-  for i in countup(1, m.len - 1):

-    result.add(newCall(bindSym"styledEchoProcessArg", m[i]))

-

-  result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))

-  result.add(newCall(bindSym"resetAttributes"))

-

-when isMainModule:

-  system.addQuitProc(resetAttributes)

-  write(stdout, "never mind")

-  eraseLine()

-  #setCursorPos(2, 2)

-  writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})

-  setBackGroundColor(bgCyan, true)

-  setForeGroundColor(fgBlue)

-  writeln(stdout, "ordinary text")

-

+  result = newNimNode(nnkStmtList)
+
+  for i in countup(1, m.len - 1):
+    result.add(newCall(bindSym"styledEchoProcessArg", m[i]))
+
+  result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
+  result.add(newCall(bindSym"resetAttributes"))
+
+when isMainModule:
+  system.addQuitProc(resetAttributes)
+  write(stdout, "never mind")
+  eraseLine()
+  #setCursorPos(2, 2)
+  writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})
+  setBackGroundColor(bgCyan, true)
+  setForeGroundColor(fgBlue)
+  writeln(stdout, "ordinary text")
+
   styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) 
   
\ No newline at end of file
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index fa4925ee6..d448d2b10 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -489,7 +489,7 @@ proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
 proc FD_ZERO*(FDSet: var TFDSet) =
   FDSet.fd_count = 0
 
-proc WSAStartup*(wVersionRequired: int16, WSData: var TWSAData): cint {.
+proc WSAStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
   stdcall, importc: "WSAStartup", dynlib: ws2dll.}
 
 proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
diff --git a/lib/wrappers/gtk/glib2.nim b/lib/wrappers/gtk/glib2.nim
index 4151ba954..3fa672c85 100644
--- a/lib/wrappers/gtk/glib2.nim
+++ b/lib/wrappers/gtk/glib2.nim
@@ -27,7 +27,7 @@ type
   gshort* = cshort
   glong* = clong
   gint* = cint
-  gboolean* = bool
+  gboolean* = distinct gint
   guchar* = char
   gushort* = int16
   gulong* = int
@@ -173,6 +173,12 @@ type
   TGBoxedFreeFunc* = proc (boxed: gpointer){.cdecl.}
   PGsource = pointer          # I don't know and don't care
 
+converter gbool*(nimbool: bool): gboolean =
+  return ord(nimbool).gboolean
+
+converter toBool*(gbool: gboolean): bool =
+  return int(gbool) == 1
+
 const 
   G_TYPE_FUNDAMENTAL_SHIFT* = 2
   G_TYPE_FUNDAMENTAL_MAX* = 255 shl G_TYPE_FUNDAMENTAL_SHIFT
diff --git a/lib/wrappers/gtk/gtk2.nim b/lib/wrappers/gtk/gtk2.nim
index 6b418024e..63e69130a 100644
--- a/lib/wrappers/gtk/gtk2.nim
+++ b/lib/wrappers/gtk/gtk2.nim
@@ -2,6 +2,8 @@
 import 
   glib2, atk, pango, gdk2pixbuf, gdk2
 
+export gbool, toBool
+
 when defined(win32): 
   const 
     lib = "libgtk-win32-2.0-0.dll"
diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim
index fa14f9e8e..c7893fe78 100644
--- a/tools/nimgrep.nim
+++ b/tools/nimgrep.nim
@@ -32,6 +32,7 @@ Options:
   --ignoreCase, -i    be case insensitive
   --ignoreStyle, -y   be style insensitive
   --ext:EX1|EX2|...   only search the files with the given extension(s)
+  --nocolor           output will be given without any colours.
   --verbose           be verbose: list every processed file
   --help, -h          shows this help
   --version, -v       shows the version
@@ -291,6 +292,7 @@ for kind, key, val in getopt():
     of "ignorecase", "i": incl(options, optIgnoreCase)
     of "ignorestyle", "y": incl(options, optIgnoreStyle)
     of "ext": extensions = val.split('|')
+    of "nocolor": useWriteStyled = false
     of "verbose": incl(options, optVerbose)
     of "help", "h": writeHelp()
     of "version", "v": writeVersion()