summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/httpclient.nim5
-rw-r--r--lib/pure/marshal.nim2
-rw-r--r--lib/pure/math.nim68
-rw-r--r--lib/pure/net.nim10
-rw-r--r--lib/pure/os.nim18
-rw-r--r--lib/pure/parsexml.nim4
-rw-r--r--lib/pure/rawsockets.nim16
-rw-r--r--lib/pure/securehash.nim199
-rw-r--r--lib/pure/selectors.nim3
-rw-r--r--lib/pure/sockets.nim14
-rw-r--r--lib/pure/times.nim25
-rw-r--r--lib/pure/unicode.nim59
-rw-r--r--lib/pure/unittest.nim4
13 files changed, 345 insertions, 82 deletions
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 2ca2098b3..e6b8088c5 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -834,11 +834,12 @@ proc post*(client: AsyncHttpClient, url: string, body = "", multipart: Multipart
     else:
       x
   var xb = mpBody.withNewLine() & body
-  client.headers["Content-Type"] = mpHeader.split(": ")[1]
+  if multipart != nil:
+    client.headers["Content-Type"] = mpHeader.split(": ")[1]
   client.headers["Content-Length"] = $len(xb)
 
   result = await client.request(url, httpPOST, xb)
-      
+
 when not defined(testing) and isMainModule:
   when true:
     # Async
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index 49f049e46..173cd1e81 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -17,7 +17,7 @@
 ## .. code-block:: nim
 ##
 ##   type
-##     A = object
+##     A = object of RootObj
 ##     B = object of A
 ##       f: int
 ##
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index d3f1f3814..821ab738b 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -56,7 +56,7 @@ type
     fcNegInf     ## value is negative infinity
 
 proc classify*(x: float): FloatClass =
-  ## classifies a floating point value. Returns `x`'s class as specified by
+  ## Classifies a floating point value. Returns `x`'s class as specified by
   ## `FloatClass`.
 
   # JavaScript and most C compilers have no classify:
@@ -74,7 +74,7 @@ proc classify*(x: float): FloatClass =
 
 
 proc binom*(n, k: int): int {.noSideEffect.} =
-  ## computes the binomial coefficient
+  ## Computes the binomial coefficient
   if k <= 0: return 1
   if 2*k > n: return binom(n, n-k)
   result = n
@@ -82,18 +82,18 @@ proc binom*(n, k: int): int {.noSideEffect.} =
     result = (result * (n + 1 - i)) div i
 
 proc fac*(n: int): int {.noSideEffect.} =
-  ## computes the faculty/factorial function.
+  ## Computes the faculty/factorial function.
   result = 1
   for i in countup(2, n):
     result = result * i
 
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
-  ## returns true, if `x` is a power of two, false otherwise.
+  ## Returns true, if `x` is a power of two, false otherwise.
   ## Zero and negative numbers are not a power of two.
   return (x > 0) and ((x and (x - 1)) == 0)
 
 proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
-  ## returns `x` rounded up to the nearest power of two.
+  ## Returns `x` rounded up to the nearest power of two.
   ## Zero and negative numbers get rounded up to 1.
   result = x - 1
   when defined(cpu64):
@@ -108,28 +108,28 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
   result += 1 + ord(x<=0)
 
 proc countBits32*(n: int32): int {.noSideEffect.} =
-  ## counts the set bits in `n`.
+  ## Counts the set bits in `n`.
   var v = n
   v = v -% ((v shr 1'i32) and 0x55555555'i32)
   v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
   result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32
 
 proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
-  ## computes the sum of the elements in `x`.
+  ## Computes the sum of the elements in `x`.
   ## If `x` is empty, 0 is returned.
   for i in items(x): result = result + i
 
 template toFloat(f: float): float = f
 
 proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
-  ## computes the mean of the elements in `x`, which are first converted to floats.
+  ## Computes the mean of the elements in `x`, which are first converted to floats.
   ## If `x` is empty, NaN is returned.
   ## ``toFloat(x: T): float`` must be defined.
   for i in items(x): result = result + toFloat(i)
   result = result / toFloat(len(x))
 
 proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
-  ## computes the variance of the elements in `x`.
+  ## Computes the variance of the elements in `x`.
   ## If `x` is empty, NaN is returned.
   ## ``toFloat(x: T): float`` must be defined.
   result = 0.0
@@ -140,41 +140,43 @@ proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
   result = result / toFloat(len(x))
 
 proc random*(max: int): int {.benign.}
-  ## returns a random number in the range 0..max-1. The sequence of
+  ## Returns a random number in the range 0..max-1. The sequence of
   ## random number is always the same, unless `randomize` is called
   ## which initializes the random number generator with a "random"
   ## number, i.e. a tickcount.
 
 proc random*(max: float): float {.benign.}
-  ## returns a random number in the range 0..<max. The sequence of
+  ## Returns a random number in the range 0..<max. The sequence of
   ## random number is always the same, unless `randomize` is called
   ## which initializes the random number generator with a "random"
   ## number, i.e. a tickcount. This has a 16-bit resolution on windows
   ## and a 48-bit resolution on other platforms.
 
 proc randomize*() {.benign.}
-  ## initializes the random number generator with a "random"
+  ## Initializes the random number generator with a "random"
   ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
 
 proc randomize*(seed: int) {.benign.}
-  ## initializes the random number generator with a specific seed.
+  ## Initializes the random number generator with a specific seed.
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
 
 {.push noSideEffect.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
-    ## computes the square root of `x`.
+    ## Computes the square root of `x`.
   proc cbrt*(x: float): float {.importc: "cbrt", header: "<math.h>".}
-    ## computes the cubic root of `x`
+    ## Computes the cubic root of `x`
 
   proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
-    ## computes ln(x).
+    ## Computes the natural log of `x`
   proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
+    ## Computes the common logarithm (base 10) of `x`
   proc log2*(x: float): float = return ln(x) / ln(2.0)
+    ## Computes the binary logarithm (base 2) of `x`
   proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
-    ## computes e**x.
+    ## Computes the exponential function of `x` (pow(E, x))
 
   proc frexp*(x: float, exponent: var int): float {.
     importc: "frexp", header: "<math.h>".}
@@ -185,11 +187,14 @@ when not defined(JS):
     ## m.
 
   proc round*(x: float): int {.importc: "lrint", header: "<math.h>".}
-    ## converts a float to an int by rounding.
+    ## Converts a float to an int by rounding.
 
   proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
+    ## Computes the arc cosine of `x`
   proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
+    ## Computes the arc sine of `x`
   proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
+    ## Calculate the arc tangent of `y` / `x`
   proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
     ## Calculate the arc tangent of `y` / `x`.
     ## `atan2` returns the arc tangent of `y` / `x`; it produces correct
@@ -197,16 +202,23 @@ when not defined(JS):
     ## (`x` near 0).
 
   proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
+    ## Computes the cosine of `x`
   proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
+    ## Computes the hyperbolic cosine of `x`
   proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".}
-    ## same as ``sqrt(x*x + y*y)``.
+    ## Computes the hypotenuse of a right-angle triangle with `x` and
+    ## `y` as its base and height. Equivalent to ``sqrt(x*x + y*y)``.
 
   proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
+    ## Computes the hyperbolic sine of `x`
   proc sin*(x: float): float {.importc: "sin", header: "<math.h>".}
+    ## Computes the sine of `x`
   proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
+    ## Computes the tangent of `x`
   proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
+    ## Computes the hyperbolic tangent of `x`
   proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
-    ## computes x to power raised of y.
+    ## Computes `x` to power of `y`.
 
   proc erf*(x: float): float {.importc: "erf", header: "<math.h>".}
     ## The error function
@@ -269,10 +281,26 @@ when not defined(JS):
     result = int(rand()) mod max
 
   proc trunc*(x: float): float {.importc: "trunc", header: "<math.h>".}
+    ## Truncates `x` to the decimal point
+    ##
+    ## .. code-block:: nim
+    ##  echo trunc(PI) # 3.0
   proc floor*(x: float): float {.importc: "floor", header: "<math.h>".}
+    ## Computes the floor function (i.e., the largest integer not greater than `x`)
+    ##
+    ## .. code-block:: nim
+    ##  echo floor(-3.5) ## -4.0
   proc ceil*(x: float): float {.importc: "ceil", header: "<math.h>".}
+    ## Computes the ceiling function (i.e., the smallest integer not less than `x`)
+    ##
+    ## .. code-block:: nim
+    ##  echo ceil(-2.1) ## -2.0
 
   proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".}
+    ## Computes the remainder of `x` divided by `y`
+    ##
+    ## .. code-block:: nim
+    ##  echo fmod(-2.5, 0.3) ## -0.1
 
 else:
   proc mathrandom(): float {.importc: "Math.random", nodecl.}
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index d9f4845f3..141543c70 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -294,7 +294,7 @@ proc getSocketError*(socket: Socket): OSErrorCode =
   if result == 0.OSErrorCode:
     result = socket.lastError
   if result == 0.OSErrorCode:
-    raise newException(OSError, "No valid socket error code available")
+    raiseOSError(result, "No valid socket error code available")
 
 proc socketError*(socket: Socket, err: int = -1, async = false,
                   lastError = (-1).OSErrorCode) =
@@ -332,10 +332,8 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
           else:
             let errStr = $ErrErrorString(sslErr, nil)
             raiseSSLError(errStr & ": " & errStr)
-          let osMsg = osErrorMsg osLastError()
-          if osMsg != "":
-            errStr.add ". The OS reports: " & osMsg
-          raise newException(OSError, errStr)
+          let osErr = osLastError()
+          raiseOSError(osErr, errStr)
         of SSL_ERROR_SSL:
           raiseSSLError()
         else: raiseSSLError("Unknown Error")
@@ -921,7 +919,7 @@ proc send*(socket: Socket, data: string,
     socketError(socket, lastError = lastError)
 
   if sent != data.len:
-    raise newException(OSError, "Could not send all data.")
+    raiseOSError(osLastError(), "Could not send all data.")
 
 proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
   ## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 59a56a1ab..48d255dca 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -621,6 +621,20 @@ proc parentDir*(path: string): string {.
   else:
     result = ""
 
+proc tailDir*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Returns the tail part of `path`..
+  ##
+  ## | Example: ``tailDir("/usr/local/bin") == "local/bin"``.
+  ## | Example: ``tailDir("usr/local/bin/") == "local/bin"``.
+  ## | Example: ``tailDir("bin") == ""``.
+  var q = 1
+  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
+  for i in 0..len(path)-q:
+    if path[i] in {DirSep, AltSep}:
+      return substr(path, i+1)
+  result = ""
+
 proc isRootDir*(path: string): bool {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Checks whether a given `path` is a root directory
@@ -1022,7 +1036,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
       if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
   else:
     if c_rename(source, dest) != 0'i32:
-      raise newException(OSError, $strerror(errno))
+      raiseOSError(osLastError(), $strerror(errno))
 
 when not declared(ENOENT) and not defined(Windows):
   when NoFakeVars:
@@ -1057,7 +1071,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
           raiseOSError(osLastError())
   else:
     if c_remove(file) != 0'i32 and errno != ENOENT:
-      raise newException(OSError, $strerror(errno))
+      raiseOSError(osLastError(), $strerror(errno))
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   tags: [ExecIOEffect].} =
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index e1abb0a4f..f8b2c3d8d 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -535,6 +535,10 @@ proc parseAttribute(my: var XmlParser) =
         pos = lexbase.handleLF(my, pos)
         buf = my.buf
         pendingSpace = true
+      of '/':
+        pos = lexbase.handleRefillChar(my, pos)
+        buf = my.buf
+        add(my.b, '/')
       else:
         if buf[pos] == quote:
           inc(pos)
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index 349b0d97a..7873e7226 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -207,7 +207,7 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
     when useWinVersion:
       raiseOSError(osLastError())
     else:
-      raise newException(OSError, $gai_strerror(gaiResult))
+      raiseOSError(osLastError(), $gai_strerror(gaiResult))
 
 proc dealloc*(ai: ptr AddrInfo) =
   freeaddrinfo(ai)
@@ -251,7 +251,7 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
     var s = winlean.getservbyname(name, proto)
   else:
     var s = posix.getservbyname(name, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
+  if s == nil: raiseOSError(osLastError(), "Service not found.")
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = Port(s.s_port)
@@ -267,7 +267,7 @@ proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].}
     var s = winlean.getservbyport(ze(int16(port)).cint, proto)
   else:
     var s = posix.getservbyport(ze(int16(port)).cint, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
+  if s == nil: raiseOSError(osLastError(), "Service not found.")
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = Port(s.s_port)
@@ -286,7 +286,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
     var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen,
                                 cint(posix.AF_INET))
     if s == nil:
-      raise newException(OSError, $hstrerror(h_errno))
+      raiseOSError(osLastError(), $hstrerror(h_errno))
 
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
@@ -298,7 +298,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrtype = AF_INET6
     else:
-      raise newException(OSError, "unknown h_addrtype")
+      raiseOSError(osLastError(), "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -319,7 +319,7 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrtype = AF_INET6
     else:
-      raise newException(OSError, "unknown h_addrtype")
+      raiseOSError(osLastError(), "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -335,7 +335,7 @@ proc getSockDomain*(socket: SocketHandle): Domain =
   elif name.sa_family == rawAfInet6:
     result = AF_INET6
   else:
-    raise newException(OSError, "unknown socket family in getSockFamily")
+    raiseOSError(osLastError(), "unknown socket family in getSockFamily")
 
 
 proc getAddrString*(sockAddr: ptr SockAddr): string =
@@ -353,7 +353,7 @@ proc getAddrString*(sockAddr: ptr SockAddr): string =
       if posix.IN6_IS_ADDR_V4MAPPED(addr6) != 0:
         result = result.substr("::ffff:".len)
   else:
-    raise newException(OSError, "unknown socket family in getAddrString")
+    raiseOSError(osLastError(), "unknown socket family in getAddrString")
 
 
 proc getSockName*(socket: SocketHandle): Port =
diff --git a/lib/pure/securehash.nim b/lib/pure/securehash.nim
new file mode 100644
index 000000000..8ac6acb0e
--- /dev/null
+++ b/lib/pure/securehash.nim
@@ -0,0 +1,199 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Nim Contributers
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  strutils, unsigned
+
+const Sha1DigestSize = 20
+
+type
+  Sha1Digest = array[0 .. Sha1DigestSize-1, uint8]
+  SecureHash* = distinct Sha1Digest
+
+proc sha1(src: string) : Sha1Digest
+
+proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
+proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
+proc `$`*(self: SecureHash): string =
+  result = ""
+  for v in Sha1Digest(self):
+    result.add(toHex(int(v), 2))
+
+proc parseSecureHash*(hash: string): SecureHash =
+  for i in 0.. <Sha1DigestSize:
+    Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
+
+proc `==`*(a, b: SecureHash): bool =
+  # Not a constant-time comparison, but that's acceptable in this context
+  Sha1Digest(a) == Sha1Digest(b)
+
+
+when isMainModule:
+  let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]")
+  doAssert hash1 == hash1
+  doAssert parseSecureHash($hash1) == hash1
+
+
+# Copyright (c) 2011, Micael Hildenborg
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# * Neither the name of Micael Hildenborg nor the
+#   names of its contributors may be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Ported to Nim by Erik O'Leary
+
+type
+  Sha1State = array[0 .. 5-1, uint32]
+  Sha1Buffer = array[0 .. 80-1, uint32]
+
+template clearBuffer(w: Sha1Buffer, len = 16) =
+  zeroMem(addr(w), len * sizeof(uint32))
+
+proc init(result: var Sha1State) =
+  result[0] = 0x67452301'u32
+  result[1] = 0xefcdab89'u32
+  result[2] = 0x98badcfe'u32
+  result[3] = 0x10325476'u32
+  result[4] = 0xc3d2e1f0'u32
+
+proc innerHash(state: var Sha1State, w: var Sha1Buffer) =
+  var
+    a = state[0]
+    b = state[1]
+    c = state[2]
+    d = state[3]
+    e = state[4]
+
+  var round = 0
+
+  template rot(value, bits: uint32): uint32 {.immediate.} =
+    (value shl bits) or (value shr (32 - bits))
+
+  template sha1(fun, val: uint32): stmt =
+    let t = rot(a, 5) + fun + e + val + w[round]
+    e = d
+    d = c
+    c = rot(b, 30)
+    b = a
+    a = t
+
+  template process(body: stmt): stmt =
+    w[round] = rot(w[round - 3] xor w[round - 8] xor w[round - 14] xor w[round - 16], 1)
+    body
+    inc(round)
+
+  template wrap(dest, value: expr): stmt {.immediate.} =
+    let v = dest + value
+    dest = v
+
+  while round < 16:
+    sha1((b and c) or (not b and d), 0x5a827999'u32)
+    inc(round)
+
+  while round < 20:
+    process:
+      sha1((b and c) or (not b and d), 0x5a827999'u32)
+
+  while round < 40:
+    process:
+      sha1(b xor c xor d, 0x6ed9eba1'u32)
+
+  while round < 60:
+    process:
+      sha1((b and c) or (b and d) or (c and d), 0x8f1bbcdc'u32)
+
+  while round < 80:
+    process:
+      sha1(b xor c xor d, 0xca62c1d6'u32)
+
+  wrap state[0], a
+  wrap state[1], b
+  wrap state[2], c
+  wrap state[3], d
+  wrap state[4], e
+
+template computeInternal(src: expr): stmt {.immediate.} =
+  #Initialize state
+  var state: Sha1State
+  init(state)
+
+  #Create w buffer
+  var w: Sha1Buffer
+
+  #Loop through all complete 64byte blocks.
+  let byteLen         = src.len
+  let endOfFullBlocks = byteLen - 64
+  var endCurrentBlock = 0
+  var currentBlock    = 0
+
+  while currentBlock <= endOfFullBlocks:
+    endCurrentBlock = currentBlock + 64
+
+    var i = 0
+    while currentBlock < endCurrentBlock:
+      w[i] = uint32(src[currentBlock+3]) or
+             uint32(src[currentBlock+2]) shl 8'u32 or
+             uint32(src[currentBlock+1]) shl 16'u32 or
+             uint32(src[currentBlock])   shl 24'u32
+      currentBlock += 4
+      inc(i)
+
+    innerHash(state, w)
+
+  #Handle last and not full 64 byte block if existing
+  endCurrentBlock = byteLen - currentBlock
+  clearBuffer(w)
+  var lastBlockBytes = 0
+
+  while lastBlockBytes < endCurrentBlock:
+
+    var value = uint32(src[lastBlockBytes + currentBlock]) shl
+                ((3'u32 - (lastBlockBytes and 3)) shl 3)
+
+    w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or value
+    inc(lastBlockBytes)
+
+  w[lastBlockBytes shr 2] = w[lastBlockBytes shr 2] or (
+    0x80'u32 shl ((3'u32 - (lastBlockBytes and 3)) shl 3)
+  )
+
+  if endCurrentBlock >= 56:
+    innerHash(state, w)
+    clearBuffer(w)
+
+  w[15] = uint32(byteLen) shl 3
+  innerHash(state, w)
+
+  # Store hash in result pointer, and make sure we get in in the correct order
+  # on both endian models.
+  for i in 0 .. Sha1DigestSize-1:
+    result[i] = uint8((int(state[i shr 2]) shr ((3-(i and 3)) * 8)) and 255)
+
+proc sha1(src: string) : Sha1Digest =
+  ## Calculate SHA1 from input string
+  computeInternal(src)
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index aa8ad39d1..bfc393a96 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -295,7 +295,8 @@ proc contains*(s: Selector, key: SelectorKey): bool =
   ## ensures that the keys are equal. File descriptors may not always be
   ## unique especially when an fd is closed and then a new one is opened,
   ## the new one may have the same value.
-  return key.fd in s and s.fds[key.fd] == key
+  when not defined(nimdoc):
+    return key.fd in s and s.fds[key.fd] == key
 
 {.deprecated: [TEvent: Event, PSelectorKey: SelectorKey,
    TReadyInfo: ReadyInfo, PSelector: Selector].}
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index a10255e5b..18b2ab1e9 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -441,7 +441,7 @@ template gaiNim(a, p, h, list: expr): stmt =
       when defined(windows):
         raiseOSError(osLastError())
       else:
-        raise newException(OSError, $gai_strerror(gaiResult))
+        raiseOSError(osLastError(), $gai_strerror(gaiResult))
 
 proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
   tags: [ReadIOEffect].} =
@@ -671,7 +671,7 @@ proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
     var s = winlean.getservbyname(name, proto)
   else:
     var s = posix.getservbyname(name, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
+  if s == nil: raiseOSError(osLastError(), "Service not found.")
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = Port(s.s_port)
@@ -687,7 +687,7 @@ proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].}
     var s = winlean.getservbyport(ze(int16(port)).cint, proto)
   else:
     var s = posix.getservbyport(ze(int16(port)).cint, proto)
-  if s == nil: raise newException(OSError, "Service not found.")
+  if s == nil: raiseOSError(osLastError(), "Service not found.")
   result.name = $s.s_name
   result.aliases = cstringArrayToSeq(s.s_aliases)
   result.port = Port(s.s_port)
@@ -706,7 +706,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
     var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, 
                                 cint(posix.AF_INET))
     if s == nil:
-      raise newException(OSError, $hstrerror(h_errno))
+      raiseOSError(osLastError(), $hstrerror(h_errno))
   
   result.name = $s.h_name
   result.aliases = cstringArrayToSeq(s.h_aliases)
@@ -718,7 +718,7 @@ proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrtype = AF_INET6
     else:
-      raise newException(OSError, "unknown h_addrtype")
+      raiseOSError(osLastError(), "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -739,7 +739,7 @@ proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
     elif s.h_addrtype == posix.AF_INET6:
       result.addrtype = AF_INET6
     else:
-      raise newException(OSError, "unknown h_addrtype")
+      raiseOSError(osLastError(), "unknown h_addrtype")
   result.addrList = cstringArrayToSeq(s.h_addr_list)
   result.length = int(s.h_length)
 
@@ -1594,7 +1594,7 @@ proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} =
     raiseOSError(osLastError())
 
   if sent != data.len:
-    raise newException(OSError, "Could not send all data.")
+    raiseOSError(osLastError(), "Could not send all data.")
 
 proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
   ## sends data to a non-blocking socket.
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index e4d3f7494..f1315a9fd 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -789,7 +789,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     of "sat":
       info.weekday = dSat
     else:
-      raise newException(ValueError, "invalid day of week ")
+      raise newException(ValueError,
+        "Couldn't parse day of week (ddd), got: " & value[j..j+2])
     j += 3
   of "dddd":
     if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
@@ -814,7 +815,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
       info.weekday = dSat
       j += 8
     else:
-      raise newException(ValueError, "invalid day of week ")
+      raise newException(ValueError,
+        "Couldn't parse day of week (dddd), got: " & value)
   of "h", "H":
     var pd = parseInt(value[j..j+1], sv)
     info.hour = sv
@@ -865,7 +867,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     of "dec":
       info.month =  mDec
     else:
-      raise newException(ValueError, "invalid month")
+      raise newException(ValueError,
+        "Couldn't parse month (MMM), got: " & value)
     j += 3
   of "MMMM":
     if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
@@ -905,7 +908,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
       info.month =  mDec
       j += 8
     else:
-      raise newException(ValueError, "invalid month")
+      raise newException(ValueError,
+        "Couldn't parse month (MMMM), got: " & value)
   of "s":
     var pd = parseInt(value[j..j+1], sv)
     info.second = sv
@@ -936,7 +940,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     elif value[j] == '-':
       info.timezone = 0-parseInt($value[j+1])
     else:
-      raise newException(ValueError, "Sign for timezone " & value[j])
+      raise newException(ValueError,
+        "Couldn't parse timezone offset (z), got: " & value[j])
     j += 2
   of "zz":
     if value[j] == '+':
@@ -944,7 +949,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     elif value[j] == '-':
       info.timezone = 0-value[j+1..j+2].parseInt()
     else:
-      raise newException(ValueError, "Sign for timezone " & value[j])
+      raise newException(ValueError,
+        "Couldn't parse timezone offset (zz), got: " & value[j])
     j += 3
   of "zzz":
     if value[j] == '+':
@@ -952,7 +958,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
     elif value[j] == '-':
       info.timezone = 0-value[j+1..j+2].parseInt()
     else:
-      raise newException(ValueError, "Sign for timezone " & value[j])
+      raise newException(ValueError,
+        "Couldn't parse timezone offset (zzz), got: " & value[j])
     j += 6
   of "ZZZ":
     info.tzname = value[j..j+2].toUpper()
@@ -1020,10 +1027,10 @@ proc parse*(value, layout: string): TimeInfo =
       # These are literals in both the layout and the value string
       if layout[i] == '\'':
         inc(i)
-        inc(j)
         while layout[i] != '\'' and layout.len-1 > i:
           inc(i)
           inc(j)
+        inc(i)
       else:
         inc(i)
         inc(j)
@@ -1112,6 +1119,8 @@ when isMainModule:
   s = "2006-01-12T15:04:05Z-07:00"
   f = "yyyy-MM-ddTHH:mm:ssZzzz"
   assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  f = "yyyy-MM-dd'T'HH:mm:ss'Z'zzz"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
   # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
   s = "2006-01-12T15:04:05.999999999Z-07:00"
   f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 4446eaa0c..5e20db32b 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -27,7 +27,7 @@ proc `==`*(a, b: Rune): bool = return int(a) == int(b)
 template ones(n: expr): expr = ((1 shl n)-1)
 
 proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
-  ## returns the number of Unicode characters of the string `s`.
+  ## Returns the number of Unicode characters of the string ``s``
   var i = 0
   while i < len(s):
     if ord(s[i]) <=% 127: inc(i)
@@ -40,7 +40,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
     inc(result)
 
 proc runeLenAt*(s: string, i: Natural): int =
-  ## returns the number of bytes the rune starting at ``s[i]`` takes.
+  ## Returns the number of bytes the rune starting at ``s[i]`` takes
   if ord(s[i]) <=% 127: result = 1
   elif ord(s[i]) shr 5 == 0b110: result = 2
   elif ord(s[i]) shr 4 == 0b1110: result = 3
@@ -50,8 +50,8 @@ proc runeLenAt*(s: string, i: Natural): int =
   else: result = 1
 
 template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
-  ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
-  ## `i` is incremented by the number of bytes that have been processed.
+  ## Returns the Unicode character ``s[i]`` in ``result``. If ``doInc == true``
+  ## ``i`` is incremented by the number of bytes that have been processed.
   bind ones
   if ord(s[i]) <=% 127:
     result = Rune(ord(s[i]))
@@ -106,8 +106,8 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     when doInc: inc(i)
 
 proc validateUtf8*(s: string): int =
-  ## returns the position of the invalid byte in ``s`` if the string ``s`` does
-  ## not hold valid UTF-8 data. Otherwise -1 is returned.
+  ## Returns the position of the invalid byte in ``s`` if the string ``s`` does
+  ## not hold valid UTF-8 data. Otherwise ``-1`` is returned.
   var i = 0
   let L = s.len
   while i < L:
@@ -131,11 +131,11 @@ proc validateUtf8*(s: string): int =
   return -1
 
 proc runeAt*(s: string, i: Natural): Rune =
-  ## returns the unicode character in `s` at byte index `i`
+  ## Returns the unicode character in ``s`` at byte index ``i``
   fastRuneAt(s, i, result, false)
 
 proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
-  ## converts a rune into its UTF8 representation
+  ## Converts a rune into its UTF-8 representation
   var i = RuneImpl(c)
   if i <=% 127:
     result = newString(1)
@@ -174,11 +174,11 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
     discard # error, exception?
 
 proc `$`*(rune: Rune): string =
-  ## converts a rune to a string
+  ## Converts a Rune to a string
   rune.toUTF8
 
 proc `$`*(runes: seq[Rune]): string =
-  ## converts a sequence of runes to a string
+  ## Converts a sequence of Runes to a string
   result = ""
   for rune in runes: result.add(rune.toUTF8)
 
@@ -1163,8 +1163,8 @@ proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int
   return -1
 
 proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
-  ## Converts `c` into lower case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`.
+  ## Converts ``c`` into lower case. This works for any Unicode character.
+  ## If possible, prefer ``toLower`` over ``toUpper``.
   var c = RuneImpl(c)
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
   if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
@@ -1175,8 +1175,8 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
-  ## Converts `c` into upper case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`.
+  ## Converts ``c`` into upper case. This works for any Unicode character.
+  ## If possible, prefer ``toLower`` over ``toUpper``.
   var c = RuneImpl(c)
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
   if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
@@ -1187,6 +1187,7 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+  ## Converts ``c`` to title case
   var c = RuneImpl(c)
   var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
   if p >= 0 and c == toTitleSinglets[p]:
@@ -1194,8 +1195,8 @@ proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   return Rune(c)
 
 proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## returns true iff `c` is a lower case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`.
+  ## Returns true iff ``c`` is a lower case Unicode character.
+  ## If possible, prefer ``isLower`` over ``isUpper``.
   var c = RuneImpl(c)
   # Note: toUpperRanges is correct here!
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
@@ -1206,8 +1207,8 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## returns true iff `c` is a upper case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`.
+  ## Returns true iff ``c`` is a upper case Unicode character.
+  ## If possible, prefer ``isLower`` over ``isUpper``.
   var c = RuneImpl(c)
   # Note: toLowerRanges is correct here!
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
@@ -1218,7 +1219,7 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
+  ## Returns true iff ``c`` is an *alpha* Unicode character (i.e., a letter)
   if isUpper(c) or isLower(c):
     return true
   var c = RuneImpl(c)
@@ -1230,17 +1231,18 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     return true
 
 proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## Returns true iff ``c`` is a Unicode titlecase character
   return isUpper(c) and isLower(c)
 
 proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## returns true iff `c` is a Unicode whitespace character
+  ## Returns true iff ``c`` is a Unicode whitespace character
   var c = RuneImpl(c)
   var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
   if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
     return true
 
 proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
-  ## returns true iff `c` is a Unicode combining character
+  ## Returns true iff ``c`` is a Unicode combining character
   var c = RuneImpl(c)
 
   # Optimized to return false immediately for ASCII
@@ -1251,7 +1253,7 @@ proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     (c >= 0xfe20 and c <= 0xfe2f))
 
 iterator runes*(s: string): Rune =
-  ## iterates over any unicode character of the string `s`.
+  ## Iterates over any unicode character of the string ``s``
   var
     i = 0
     result: Rune
@@ -1259,8 +1261,14 @@ iterator runes*(s: string): Rune =
     fastRuneAt(s, i, result, true)
     yield result
 
+proc toRunes*(s: string): seq[Rune] =
+  ## Obtains a sequence containing the Runes in ``s``
+  result = newSeq[Rune]()
+  for r in s.runes:
+    result.add(r)
+
 proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
-  ## compares two UTF8 strings and ignores the case. Returns:
+  ## Compares two UTF-8 strings and ignores the case. Returns:
   ##
   ## | 0 iff a == b
   ## | < 0 iff a < b
@@ -1277,8 +1285,8 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
   result = a.len - b.len
 
 proc reversed*(s: string): string =
-  ## returns the reverse of `s`, interpreting it as unicode characters. Unicode
-  ## combining characters are correctly interpreted as well:
+  ## Returns the reverse of ``s``, interpreting it as Unicode characters. 
+  ## Unicode combining characters are correctly interpreted as well:
   ##
   ## .. code-block:: nim
   ##
@@ -1322,3 +1330,4 @@ when isMainModule:
   assert reversed("先秦兩漢") == "漢兩秦先"
   assert reversed("as⃝df̅") == "f̅ds⃝a"
   assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+  assert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅")
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index 70b314e63..c459023a9 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -105,10 +105,10 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
   ##  [OK] 2 + 2 = 4
   ##  [OK] (2 + -2) != 4
   block:
-    template setup*(setupBody: stmt): stmt {.immediate, dirty.} =
+    template setup(setupBody: stmt): stmt {.immediate, dirty.} =
       template testSetupIMPL: stmt {.immediate, dirty.} = setupBody
 
-    template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} =
+    template teardown(teardownBody: stmt): stmt {.immediate, dirty.} =
       template testTeardownIMPL: stmt {.immediate, dirty.} = teardownBody
 
     body