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/asyncdispatch.nim4
-rw-r--r--lib/pure/asynchttpserver.nim2
-rw-r--r--lib/pure/asyncmacro.nim41
-rw-r--r--lib/pure/asyncnet.nim6
-rw-r--r--lib/pure/collections/tables.nim7
-rw-r--r--lib/pure/concurrency/cpuinfo.nim2
-rw-r--r--lib/pure/distros.nim2
-rw-r--r--lib/pure/hashes.nim11
-rw-r--r--lib/pure/httpclient.nim3
-rw-r--r--lib/pure/includes/asynccommon.nim2
-rw-r--r--lib/pure/json.nim23
-rw-r--r--lib/pure/math.nim36
-rw-r--r--lib/pure/os.nim46
-rw-r--r--lib/pure/ospaths.nim9
-rw-r--r--lib/pure/osproc.nim5
-rw-r--r--lib/pure/parsecfg.nim4
-rw-r--r--lib/pure/parseopt.nim45
-rw-r--r--lib/pure/parseopt2.nim45
-rw-r--r--lib/pure/pegs.nim2
-rw-r--r--lib/pure/random.nim3
-rw-r--r--lib/pure/streams.nim4
-rw-r--r--lib/pure/strutils.nim4
-rw-r--r--lib/pure/times.nim100
23 files changed, 259 insertions, 147 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 1697384e0..8c1cf6b18 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -163,8 +163,8 @@ include includes/asyncfutures
 
 type
   PDispatcherBase = ref object of RootRef
-    timers: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
-    callbacks: Deque[proc ()]
+    timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
+    callbacks*: Deque[proc ()]
 
 proc processTimers(p: PDispatcherBase) {.inline.} =
   #Process just part if timers at a step
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 8d059dbbc..a374e80e8 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   i.inc protocol.parseInt(result.minor, i)
 
 proc sendStatus(client: AsyncSocket, status: string): Future[void] =
-  client.send("HTTP/1.1 " & status & "\c\L")
+  client.send("HTTP/1.1 " & status & "\c\L\c\L") 
 
 proc processClient(client: AsyncSocket, address: string,
                    callback: proc (request: Request):
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index ce4c9a9c9..89b216b25 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -301,13 +301,13 @@ proc verifyReturnType(typeName: string) {.compileTime.} =
 proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   ## This macro transforms a single procedure into a closure iterator.
   ## The ``async`` macro supports a stmtList holding multiple async procedures.
-  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}:
+  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
       error("Cannot transform this node kind into an async proc." &
             " proc/method definition or lambda node expected.")
 
-  hint("Processing " & prc[0].getName & " as an async proc.")
+  let prcName = prc.name.getName
 
-  let returnType = prc[3][0]
+  let returnType = prc.params[0]
   var baseType: NimNode
   # Verify that the return type is a Future[T]
   if returnType.kind == nnkBracketExpr:
@@ -326,9 +326,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   let subtypeIsVoid = returnType.kind == nnkEmpty or
         (baseType.kind == nnkIdent and returnType[1].ident == !"void")
 
-  let futureVarIdents = getFutureVarIdents(prc[3])
+  let futureVarIdents = getFutureVarIdents(prc.params)
 
-  var outerProcBody = newNimNode(nnkStmtList, prc[6])
+  var outerProcBody = newNimNode(nnkStmtList, prc.body)
 
   # -> var retFuture = newFuture[T]()
   var retFutureSym = genSym(nskVar, "retFuture")
@@ -338,10 +338,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   outerProcBody.add(
     newVarStmt(retFutureSym,
       newCall(
-        newNimNode(nnkBracketExpr, prc[6]).add(
+        newNimNode(nnkBracketExpr, prc.body).add(
           newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
           subRetType),
-      newLit(prc[0].getName)))) # Get type from return type of this proc
+      newLit(prcName)))) # Get type from return type of this proc
 
   # -> iterator nameIter(): FutureBase {.closure.} =
   # ->   {.push warning[resultshadowed]: off.}
@@ -349,8 +349,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   # ->   {.pop.}
   # ->   <proc_body>
   # ->   complete(retFuture, result)
-  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
-  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid,
+  var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
+  var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
                                     futureVarIdents, nil)
   # don't do anything with forward bodies (empty)
   if procBody.kind != nnkEmpty:
@@ -362,7 +362,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
           newIdentNode("warning"), newIdentNode("resultshadowed")),
         newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
 
-      procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
+      procBody.insert(1, newNimNode(nnkVarSection, prc.body).add(
         newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
 
       procBody.insert(2, newNimNode(nnkPragma).add(
@@ -377,35 +377,32 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
 
     var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                   procBody, nnkIteratorDef)
-    closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
+    closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
+    closureIterator.addPragma(newIdentNode("closure"))
+    closureIterator.addPragma(newIdentNode("gcsafe"))
     outerProcBody.add(closureIterator)
 
     # -> createCb(retFuture)
     #var cbName = newIdentNode("cb")
     var procCb = getAst createCb(retFutureSym, iteratorNameSym,
-                         newStrLitNode(prc[0].getName),
+                         newStrLitNode(prcName),
                          createFutureVarCompletions(futureVarIdents, nil))
     outerProcBody.add procCb
 
     # -> return retFuture
-    outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
+    outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym)
 
   result = prc
 
-  # Remove the 'async' pragma.
-  for i in 0 .. <result[4].len:
-    if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
-      result[4].del(i)
-  result[4] = newEmptyNode()
   if subtypeIsVoid:
     # Add discardable pragma.
     if returnType.kind == nnkEmpty:
       # Add Future[void]
-      result[3][0] = parseExpr("Future[void]")
+      result.params[0] = parseExpr("Future[void]")
   if procBody.kind != nnkEmpty:
-    result[6] = outerProcBody
+    result.body = outerProcBody
   #echo(treeRepr(result))
-  #if prc[0].getName == "recvLineInto":
+  #if prcName == "recvLineInto":
   #  echo(toStrLit(result))
 
 macro async*(prc: untyped): untyped =
@@ -529,8 +526,6 @@ macro multisync*(prc: untyped): untyped =
   ##
   ## The generated async procedures use the ``async`` macro, whereas the
   ## generated synchronous procedures simply strip off the ``await`` calls.
-  hint("Processing " & prc[0].getName & " as a multisync proc.")
-
   let (sync, asyncPrc) = splitProc(prc)
   result = newStmtList()
   result.add(asyncSingleProc(asyncPrc))
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 9f73bc3cf..5de65efe0 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -533,15 +533,13 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
   else:
     var c = ""
     while true:
-      let recvFut = recv(socket, 1, flags)
-      c = recvFut.read()
+      c = await recv(socket, 1, flags)
       if c.len == 0:
         resString.mget.setLen(0)
         resString.complete()
         return
       if c == "\r":
-        let recvFut = recv(socket, 1, flags) # Skip \L
-        c = recvFut.read()
+        c = await recv(socket, 1, flags) # Skip \L
         assert c == "\L"
         addNLIfEmpty()
         resString.complete()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 323af5a38..5b6701a12 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -590,8 +590,11 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
   swap(t.data, n)
   while h >= 0:
     var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+    let eh = n[h].hcode
+    if isFilled(eh):
+      var j: Hash = eh and maxHash(t)
+      while isFilled(t.data[j].hcode):
+        j = nextTry(j, maxHash(t))
       rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
 
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index c3390573a..603fee080 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -69,4 +69,4 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     result = affinitySpaceTotal().int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
-  if result <= 0: result = 1
+  if result <= 0: result = 0
diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim
index 896497630..0adba5b1e 100644
--- a/lib/pure/distros.nim
+++ b/lib/pure/distros.nim
@@ -158,7 +158,7 @@ proc detectOsImpl(d: Distribution): bool =
   of Distribution.ArchLinux:
     result = "arch" in toLowerAscii(uname())
   of Distribution.OpenSUSE:
-    result = "suse" in toLowerAscii(uname())
+    result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release())
   of Distribution.GoboLinux:
     result = "-Gobo " in uname()
   of Distribution.OpenMandriva:
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index e8c8776c6..b015ed311 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -139,9 +139,14 @@ proc hash*(x: cstring): Hash =
   ## efficient hashing of null-terminated strings
   var h: Hash = 0
   var i = 0
-  while x[i] != 0.char:
-    h = h !& ord(x[i])
-    inc i
+  when defined(js):
+    while i < x.len:
+      h = h !& ord(x[i])
+      inc i
+  else:
+    while x[i] != 0.char:
+      h = h !& ord(x[i])
+      inc i
   result = !$h
 
 proc hash*(sBuf: string, sPos, ePos: int): Hash =
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 4f43177a8..909a2613f 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -62,7 +62,8 @@
 ##   let body = %*{
 ##       "data": "some text"
 ##   }
-##   echo client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   let response = client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   echo response.status
 ##
 ## Progress reporting
 ## ==================
diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
index a7d2f803f..8b760c66a 100644
--- a/lib/pure/includes/asynccommon.nim
+++ b/lib/pure/includes/asynccommon.nim
@@ -3,7 +3,7 @@ template newAsyncNativeSocketImpl(domain, sockType, protocol) =
   if handle == osInvalidSocket:
     raiseOSError(osLastError())
   handle.setBlocking(false)
-  when defined(macosx):
+  when defined(macosx) and not defined(nimdoc):
     handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
   result = handle.AsyncFD
   register(result)
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 564f952d3..e3d5191c6 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1001,7 +1001,7 @@ proc escapeJson*(s: string; result: var string) =
   result.add("\"")
   for x in runes(s):
     var r = int(x)
-    if r >= 32 and r <= 127:
+    if r >= 32 and r <= 126:
       var c = chr(r)
       case c
       of '"': result.add("\\\"")
@@ -1608,7 +1608,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
       result = processType(newIdentNode(typeName), obj, jsonNode, true)
     of "seq":
       let seqT = typeSym[1]
-      let forLoopI = newIdentNode("i")
+      let forLoopI = genSym(nskForVar, "i")
       let indexerNode = createJsonIndexer(jsonNode, forLoopI)
       let constructorNode = createConstructor(seqT, indexerNode)
 
@@ -1616,12 +1616,25 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
       result = quote do:
         (
           var list: `typeSym` = @[];
-          # if `jsonNode`.kind != JArray:
-          #   # TODO: Improve error message.
-          #   raise newException(ValueError, "Expected a list")
+          verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
           for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
           list
         )
+    of "array":
+      let arrayT = typeSym[2]
+      let forLoopI = genSym(nskForVar, "i")
+      let indexerNode = createJsonIndexer(jsonNode, forLoopI)
+      let constructorNode = createConstructor(arrayT, indexerNode)
+
+      # Create a statement expression containing a for loop.
+      result = quote do:
+        (
+          var list: `typeSym`;
+          verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
+          for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`;
+          list
+        )
+
     else:
       # Generic type.
       let obj = getType(typeSym)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index a8432b6f0..8037b31b0 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -235,7 +235,7 @@ when not defined(JS):
         x = x and (not (1'u64 shl (64'u64-12'u64-e) - 1'u64))
 
       result = cast[float64](x)
-    
+
     proc truncImpl(f: float32): float32 =
       const
         mask : uint32 = 0xFF
@@ -255,7 +255,7 @@ when not defined(JS):
         x = x and (not (1'u32 shl (32'u32-9'u32-e) - 1'u32))
 
       result = cast[float32](x)
-      
+
     proc trunc*(x: float64): float64 =
       if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x
       result = truncImpl(x)
@@ -395,6 +395,12 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from radians to degrees
   result = T(d) / RadPerDeg
 
+proc sgn*[T: SomeNumber](x: T): int {.inline.} =
+  ## Sign function. Returns -1 for negative numbers and `NegInf`, 1 for
+  ## positive numbers and `Inf`, and 0 for positive zero, negative zero and
+  ## `NaN`.
+  ord(T(0) < x) - ord(x < T(0))
+
 proc `mod`*[T: float32|float64](x, y: T): T =
   ## Computes the modulo operation for float operators. Equivalent
   ## to ``x - y * floor(x/y)``. Note that the remainder will always
@@ -407,10 +413,13 @@ proc `mod`*[T: float32|float64](x, y: T): T =
 {.pop.}
 {.pop.}
 
-proc `^`*[T](x, y: T): T =
+proc `^`*[T](x: T, y: Natural): T =
   ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>` for negative exponents.
-  assert y >= T(0)
+  when compiles(y >= T(0)):
+    assert y >= T(0)
+  else:
+    assert T(y) >= T(0)
   var (x, y) = (x, y)
   result = 1
 
@@ -447,6 +456,7 @@ when isMainModule and not defined(JS):
   assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
   assert(erf(6.0) > erf(5.0))
   assert(erfc(6.0) < erfc(5.0))
+
 when isMainModule:
   # Function for approximate comparison of floats
   proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
@@ -509,3 +519,21 @@ when isMainModule:
     doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
     doAssert(classify(trunc(f_nan.float32)) == fcNan)
     doAssert(classify(trunc(0.0'f32)) == fcZero)
+
+  block: # sgn() tests
+    assert sgn(1'i8) == 1
+    assert sgn(1'i16) == 1
+    assert sgn(1'i32) == 1
+    assert sgn(1'i64) == 1
+    assert sgn(1'u8) == 1
+    assert sgn(1'u16) == 1
+    assert sgn(1'u32) == 1
+    assert sgn(1'u64) == 1
+    assert sgn(-12342.8844'f32) == -1
+    assert sgn(123.9834'f64) == 1
+    assert sgn(0'i32) == 0
+    assert sgn(0'f32) == 0
+    assert sgn(NegInf) == -1
+    assert sgn(Inf) == 1
+    assert sgn(NaN) == 0
+
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 98b6aa309..f7bcfb60e 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -666,29 +666,38 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
     else:
       raiseOSError(osLastError(), $strerror(errno))
 
-proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect, WriteIOEffect].} =
-  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+proc tryMoveFSObject(source, dest: string): bool =
+  ## Moves a file or directory from `source` to `dest`. Returns false in case
+  ## of `EXDEV` error. In case of other errors `OSError` is raised. Returns
+  ## true in case of success.
   when defined(Windows):
     when useWinUnicode:
       let s = newWideCString(source)
       let d = newWideCString(dest)
-      if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
+      if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
     else:
-      if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
+      if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
   else:
     if c_rename(source, dest) != 0'i32:
       let err = osLastError()
       if err == EXDEV.OSErrorCode:
-        # Fallback to copy & del
-        copyFile(source, dest)
-        try:
-          removeFile(source)
-        except:
-          discard tryRemoveFile(dest)
-          raise
+        return false
       else:
         raiseOSError(err, $strerror(errno))
+  return true
+
+proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+  if not tryMoveFSObject(source, dest):
+    when not defined(windows):
+      # Fallback to copy & del
+      copyFile(source, dest)
+      try:
+        removeFile(source)
+      except:
+        discard tryRemoveFile(dest)
+        raise
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   tags: [ExecIOEffect].} =
@@ -1369,6 +1378,14 @@ proc exclFilePermissions*(filename: string,
   ##   setFilePermissions(filename, getFilePermissions(filename)-permissions)
   setFilePermissions(filename, getFilePermissions(filename)-permissions)
 
+proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised.
+  if not tryMoveFSObject(source, dest):
+    when not defined(windows):
+      # Fallback to copy & del
+      copyDir(source, dest)
+      removeDir(source)
+
 include ospaths
 
 proc expandSymlink*(symlinkPath: string): string =
@@ -1412,7 +1429,7 @@ when defined(nimdoc):
   proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
     ## Returns the `i`-th `command line argument`:idx: given to the application.
     ##
-    ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex`
+    ## `i` should be in the range `1..paramCount()`, the `IndexError`
     ## exception will be raised for invalid values.  Instead of iterating over
     ## `paramCount() <#paramCount>`_ with this proc you can call the
     ## convenience `commandLineParams() <#commandLineParams>`_.
@@ -1450,7 +1467,8 @@ elif defined(windows):
     tags: [ReadIOEffect].} =
     # Docstring in nimdoc block.
     if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
-    return TaintedString(ownArgv[i])
+    if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
+    raise newException(IndexError, "invalid index")
 
 elif not defined(createNimRtl) and
   not(defined(posix) and appType == "lib") and
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 7720fb2a6..fa5342fcf 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -516,7 +516,16 @@ when declared(getEnv) or defined(nimscript):
   proc getConfigDir*(): string {.rtl, extern: "nos$1",
     tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the config directory of the current user for applications.
+    ##
+    ## On non-Windows OSs, this proc conforms to the XDG Base Directory
+    ## spec. Thus, this proc returns the value of the XDG_CONFIG_DIR environment
+    ## variable if it is set, and returns the default configuration directory,
+    ## "~/.config/", otherwise.
+    ##
+    ## An OS-dependent trailing slash is always present at the end of the
+    ## returned string; `\\` on Windows and `/` on all other OSs.
     when defined(windows): return string(getEnv("APPDATA")) & "\\"
+    elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/"
     else: return string(getEnv("HOME")) & "/.config/"
 
   proc getTempDir*(): string {.rtl, extern: "nos$1",
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index c94a65a63..23c8546c4 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -863,18 +863,15 @@ elif not defined(useNimRtl):
       if data.workingDir.len > 0:
         setCurrentDir($data.workingDir)
       var pid: Pid
-      var err: OSErrorCode
 
       if data.optionPoUsePath:
         res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
-        if res != 0'i32: err = osLastError()
       else:
         res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
-        if res != 0'i32: err = osLastError()
 
       discard posix_spawn_file_actions_destroy(fops)
       discard posix_spawnattr_destroy(attr)
-      if res != 0'i32: raiseOSError(err)
+      if res != 0'i32: raiseOSError(OSErrorCode(res))
 
       return pid
   else:
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 28681a11f..5bdd3bc40 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -540,8 +540,8 @@ proc writeConfig*(dict: Config, filename: string) =
   ## Writes the contents of the table to the specified configuration file.
   ## Note: Comment statement will be ignored.
   let file = open(filename, fmWrite)
-  let fileStream = newFileStream(filename)
-  defer: fileStream.close()
+  defer: file.close()
+  let fileStream = newFileStream(file)
   dict.writeConfig(fileStream)
 
 proc getSectionValue*(dict: Config, section, key: string): string =
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 218f5ab81..23568edb9 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -149,26 +149,41 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
   ## retrieves the rest of the command line that has not been parsed yet.
   result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
 
+iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(initOptParser):
   iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 7fd9c60fe..2e8dbe140 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -123,26 +123,41 @@ type
 
 {.deprecated: [TGetoptResult: GetoptResult].}
 
+iterator getopt*(p: var OptParser): GetoptResult =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(paramCount):
   iterator getopt*(): GetoptResult =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 5c978a2f8..6a52e2cd5 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -371,7 +371,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   of '\a': result = "\\a"
   of '\\': result = "\\\\"
   of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
-  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c < ' ' or c >= '\127': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
 
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index 1f750edcd..8a32f7d9a 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -123,7 +123,8 @@ when not defined(nimscript):
       proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
       randomize(getMil times.getTime())
     else:
-      randomize(int times.getTime())
+      let time = int(times.epochTime() * 1_000_000_000)
+      randomize(time)
 
 {.pop.}
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index eea06f4ce..438b48beb 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -334,12 +334,16 @@ when not defined(js):
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
       inc(s.pos, result)
+    else:
+      result = 0
 
   proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
     var s = StringStream(s)
     result = min(bufLen, s.data.len - s.pos)
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
+    else:
+      result = 0
 
   proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
     var s = StringStream(s)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 458c22f3a..20b2657f6 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1643,7 +1643,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   ## * replaces any ``\`` by ``\\``
   ## * replaces any ``'`` by ``\'``
   ## * replaces any ``"`` by ``\"``
-  ## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}``
+  ## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}``
   ##   by ``\xHH`` where ``HH`` is its hexadecimal value.
   ## The procedure has been designed so that its output is usable for many
   ## different common syntaxes. The resulting string is prefixed with
@@ -1653,7 +1653,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   result.add(prefix)
   for c in items(s):
     case c
-    of '\0'..'\31', '\128'..'\255':
+    of '\0'..'\31', '\127'..'\255':
       add(result, "\\x")
       add(result, toHex(ord(c), 2))
     of '\\': add(result, "\\\\")
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index bad003a3e..1bda94d14 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -81,7 +81,7 @@ when defined(posix) and not defined(JS):
 elif defined(windows):
   import winlean
 
-  when defined(vcc) or defined(bcc):
+  when defined(vcc) or defined(bcc) or defined(icl):
     # newest version of Visual C++ defines time_t to be of 64 bits
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
     # visual c's c runtime exposes these under a different name
@@ -98,46 +98,47 @@ elif defined(windows):
 
 elif defined(JS):
   type
-    Time* = ref TimeObj
-    TimeObj {.importc.} = object
-      getDay: proc (): int {.tags: [], raises: [], benign.}
-      getFullYear: proc (): int {.tags: [], raises: [], benign.}
-      getHours: proc (): int {.tags: [], raises: [], benign.}
-      getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
-      getMinutes: proc (): int {.tags: [], raises: [], benign.}
-      getMonth: proc (): int {.tags: [], raises: [], benign.}
-      getSeconds: proc (): int {.tags: [], raises: [], benign.}
-      getTime: proc (): int {.tags: [], raises: [], noSideEffect, benign.}
-      getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
-      getDate: proc (): int {.tags: [], raises: [], benign.}
-      getUTCDate: proc (): int {.tags: [], raises: [], benign.}
-      getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
-      getUTCHours: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
-      getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
-      getUTCDay: proc (): int {.tags: [], raises: [], benign.}
-      getYear: proc (): int {.tags: [], raises: [], benign.}
-      parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
-      setDate: proc (x: int) {.tags: [], raises: [], benign.}
-      setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
-      setHours: proc (x: int) {.tags: [], raises: [], benign.}
-      setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
-      setMonth: proc (x: int) {.tags: [], raises: [], benign.}
-      setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setTime: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setYear: proc (x: int) {.tags: [], raises: [], benign.}
-      toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
-      toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
+    TimeBase = float
+    Time* = distinct TimeBase
+
+  proc getDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getTime(t: Time): int {.tags: [], raises: [], noSideEffect, benign, importcpp.}
+  proc getTimezoneOffset(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc parse(t: Time; s: cstring): Time {.tags: [], raises: [], benign, importcpp.}
+  proc setDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setTime(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc toGMTString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
+  proc toLocaleString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
 
 type
   TimeInfo* = object of RootObj ## represents a time in different parts
@@ -225,17 +226,26 @@ proc `-`*(a, b: Time): int64 {.
 proc `<`*(a, b: Time): bool {.
   rtl, extern: "ntLtTime", tags: [], raises: [], noSideEffect.} =
   ## returns true iff ``a < b``, that is iff a happened before b.
-  result = a - b < 0
+  when defined(js):
+    result = TimeBase(a) < TimeBase(b)
+  else:
+    result = a - b < 0
 
 proc `<=` * (a, b: Time): bool {.
   rtl, extern: "ntLeTime", tags: [], raises: [], noSideEffect.}=
   ## returns true iff ``a <= b``.
-  result = a - b <= 0
+  when defined(js):
+    result = TimeBase(a) <= TimeBase(b)
+  else:
+    result = a - b <= 0
 
 proc `==`*(a, b: Time): bool {.
   rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect.} =
   ## returns true if ``a == b``, that is if both times represent the same value
-  result = a - b == 0
+  when defined(js):
+    result = TimeBase(a) == TimeBase(b)
+  else:
+    result = a - b == 0
 
 proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
@@ -479,7 +489,7 @@ proc `-=`*(t: var Time, ti: TimeInterval) =
   t = toTime(getLocalTime(t) - ti)
 
 proc `-`*(t: Time, ti: TimeInterval): Time =
-  ## adds the interval `ti` to Time `t`
+  ## subtracts the interval `ti` from Time `t`
   ##
   ## ``echo getTime() - 1.day``
   result = toTime(getLocalTime(t) - ti)