summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2016-03-29 15:30:44 +0200
committerAraq <rumpf_a@web.de>2016-03-29 15:31:10 +0200
commitdb2b2156581ffaaa63e7ff9c0a07ced540006956 (patch)
tree341535aa355ef422ee886f7b14fda6fbfeae0523 /lib
parent8bf14b12a963980e71ad46e16a8a2e35c9465b8c (diff)
parentb4f1eef3a3b0ff56d0a68c15c43ffecb7778e939 (diff)
downloadNim-db2b2156581ffaaa63e7ff9c0a07ced540006956.tar.gz
resolved merge conflicts
Diffstat (limited to 'lib')
-rw-r--r--lib/core/locks.nim10
-rw-r--r--lib/deprecated/pure/sockets.nim16
-rw-r--r--lib/impure/db_odbc.nim202
-rw-r--r--lib/nimbase.h2
-rw-r--r--lib/posix/kqueue.nim134
-rw-r--r--lib/posix/posix.nim6
-rw-r--r--lib/pure/collections/sequtils.nim47
-rw-r--r--lib/pure/collections/sharedlist.nim95
-rw-r--r--lib/pure/collections/tableimpl.nim5
-rw-r--r--lib/pure/logging.nim13
-rw-r--r--lib/pure/math.nim1
-rw-r--r--lib/pure/nativesockets.nim66
-rw-r--r--lib/pure/net.nim2
-rw-r--r--lib/pure/os.nim25
-rw-r--r--lib/pure/rationals.nim2
-rw-r--r--lib/pure/ropes.nim13
-rw-r--r--lib/pure/strutils.nim26
-rw-r--r--lib/system.nim4
-rw-r--r--lib/system/atomics.nim47
-rw-r--r--lib/system/dyncalls.nim14
-rw-r--r--lib/system/gc_stack.nim382
-rw-r--r--lib/system/jssys.nim4
-rw-r--r--lib/system/mmdisp.nim2
-rw-r--r--lib/system/osalloc.nim4
-rw-r--r--lib/system/repr.nim17
-rw-r--r--lib/system/sysio.nim26
-rw-r--r--lib/windows/winlean.nim16
27 files changed, 974 insertions, 207 deletions
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
index f1a74876e..66e0ab520 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -54,3 +54,13 @@ proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
 proc signal*(cond: var Cond) {.inline.} =
   ## sends a signal to the condition variable `cond`.
   signalSysCond(cond)
+
+template withLock*(a: Lock, body: untyped) =
+  ## Acquires the given lock, executes the statements in body and
+  ## releases the lock after the statements finish executing.
+  a.acquire()
+  {.locks: [a].}:
+    try:
+      body
+    finally:
+      a.release()
\ No newline at end of file
diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim
index f7d0950d8..20e6d9364 100644
--- a/lib/deprecated/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -206,6 +206,18 @@ proc htons*(x: int16): int16 =
   ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
   result = sockets.ntohs(x)
 
+template ntohl(x: uint32): expr =
+  cast[uint32](sockets.ntohl(cast[int32](x)))
+
+template ntohs(x: uint16): expr =
+  cast[uint16](sockets.ntohs(cast[int16](x)))
+
+template htonl(x: uint32): expr =
+  sockets.ntohl(x)
+
+template htons(x: uint16): expr =
+  sockets.ntohs(x)
+
 when defined(Posix):
   proc toInt(domain: Domain): cint =
     case domain
@@ -451,7 +463,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
       name.sin_family = int16(ord(AF_INET))
     else:
       name.sin_family = posix.AF_INET
-    name.sin_port = sockets.htons(int16(port))
+    name.sin_port = sockets.htons(uint16(port))
     name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
     if bindSocket(socket.fd, cast[ptr SockAddr](addr(name)),
                   sizeof(name).SockLen) < 0'i32:
@@ -834,7 +846,7 @@ proc connect*(socket: Socket, address: string, port = Port(0),
   when false:
     var s: TSockAddrIn
     s.sin_addr.s_addr = inet_addr(address)
-    s.sin_port = sockets.htons(int16(port))
+    s.sin_port = sockets.htons(uint16(port))
     when defined(windows):
       s.sin_family = toU16(ord(af))
     else:
diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim
index 4f0b0469d..3a14e6304 100644
--- a/lib/impure/db_odbc.nim
+++ b/lib/impure/db_odbc.nim
@@ -38,7 +38,7 @@
 ##
 ## .. code-block:: Nim
 ##     import db_odbc
-##     let db = open("localhost", "user", "password", "dbname")
+##     var db = open("localhost", "user", "password", "dbname")
 ##     db.close()
 ##
 ## Creating a table
@@ -64,7 +64,7 @@
 ##
 ##  import db_odbc, math
 ##
-##  let theDb = open("localhost", "nim", "nim", "test")
+##  var theDb = open("localhost", "nim", "nim", "test")
 ##
 ##  theDb.exec(sql"Drop table if exists myTestTbl")
 ##  theDb.exec(sql("create table myTestTbl (" &
@@ -88,9 +88,7 @@
 ##
 ##  theDb.close()
 
-
 import strutils, odbcsql
-
 import db_common
 export db_common
 
@@ -169,11 +167,11 @@ proc dbError*(db: var DbConn) {.
     properFreeResult(SQL_HANDLE_ENV, db.env)
     raise e
 
-proc SqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} =
-  ## Wrapper that checks if ``resVal`` is not SQL_SUCCESS and if so, raises [EDb]
-  if resVal != SQL_SUCCESS: dbError(db)
+proc sqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} =
+  ## Wrapper that raises [EDb] if ``resVal`` is neither SQL_SUCCESS or SQL_NO_DATA
+  if resVal notIn [SQL_SUCCESS, SQL_NO_DATA]: dbError(db)
 
-proc SqlGetDBMS(db: var DbConn): string {.
+proc sqlGetDBMS(db: var DbConn): string {.
         tags: [ReadDbEffect, WriteDbEffect], raises: [] .} =
   ## Returns the ODBC SQL_DBMS_NAME string
   const
@@ -182,7 +180,7 @@ proc SqlGetDBMS(db: var DbConn): string {.
     sz: TSqlSmallInt = 0
   buf[0] = '\0'
   try:
-    db.SqlCheck(SQLGetInfo(db.hDb, SQL_DBMS_NAME, cast[SqlPointer](buf.addr),
+    db.sqlCheck(SQLGetInfo(db.hDb, SQL_DBMS_NAME, cast[SqlPointer](buf.addr),
                         4095.TSqlSmallInt, sz.addr))
   except: discard
   return $buf.cstring
@@ -212,7 +210,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string {.
       add(result, c)
 
 proc prepareFetch(db: var DbConn, query: SqlQuery,
-                args: varargs[string, `$`]) {.
+                args: varargs[string, `$`]) : TSqlSmallInt {.
                 tags: [ReadDbEffect, WriteDbEffect], raises: [DbError].} =
   # Prepare a statement, execute it and fetch the data to the driver
   # ready for retrieval of the data
@@ -220,11 +218,13 @@ proc prepareFetch(db: var DbConn, query: SqlQuery,
   # requires calling
   #      properFreeResult(SQL_HANDLE_STMT, db.stmt)
   # when finished
-  db.SqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt))
+  db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt))
   var q = dbFormat(query, args)
-  db.SqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
-  db.SqlCheck(SQLExecute(db.stmt))
-  db.SqlCheck(SQLFetch(db.stmt))
+  db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
+  db.sqlCheck(SQLExecute(db.stmt))
+  var retcode = SQLFetch(db.stmt)
+  db.sqlCheck(retcode)
+  result=retcode
 
 proc prepareFetchDirect(db: var DbConn, query: SqlQuery,
                 args: varargs[string, `$`]) {.
@@ -235,10 +235,10 @@ proc prepareFetchDirect(db: var DbConn, query: SqlQuery,
   # requires calling
   #      properFreeResult(SQL_HANDLE_STMT, db.stmt)
   # when finished
-  db.SqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt))
+  db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt))
   var q = dbFormat(query, args)
-  db.SqlCheck(SQLExecDirect(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
-  db.SqlCheck(SQLFetch(db.stmt))
+  db.sqlCheck(SQLExecDirect(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
+  db.sqlCheck(SQLFetch(db.stmt))
 
 proc tryExec*(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {.
   tags: [ReadDbEffect, WriteDbEffect], raises: [].} =
@@ -285,20 +285,30 @@ iterator fastRows*(db: var DbConn, query: SqlQuery,
     rowRes: Row
     sz: TSqlSmallInt = 0
     cCnt: TSqlSmallInt = 0.TSqlSmallInt
-    rCnt = -1
-
-  db.prepareFetch(query, args)
-  db.SqlCheck(SQLNumResultCols(db.stmt, cCnt))
-  db.SqlCheck(SQLRowCount(db.stmt, rCnt))
-  rowRes = newRow(cCnt)
-  for rNr in 1..rCnt:
-    for colId in 1..cCnt:
-      buf[0] = '\0'
-      db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
-                               cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
-      rowRes[colId-1] = $buf.cstring
-    db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1))
-    yield rowRes
+    res: TSqlSmallInt = 0.TSqlSmallInt
+    tempcCnt:TSqlSmallInt # temporary cCnt,Fix the field values to be null when the release schema is compiled.
+    # tempcCnt,A field to store the number of temporary variables, for unknown reasons, 
+    # after performing a sqlgetdata function and circulating variables cCnt value will be changed to 0,
+    # so the values of the temporary variable to store the cCnt. 
+    # After every cycle and specified to cCnt. To ensure the traversal of all fields.
+  res = db.prepareFetch(query, args)
+  if res == SQL_NO_DATA:
+    discard
+  elif res == SQL_SUCCESS:
+    res = SQLNumResultCols(db.stmt, cCnt)
+    rowRes = newRow(cCnt)
+    rowRes.setLen(max(cCnt,0))
+    tempcCnt = cCnt
+    while res == SQL_SUCCESS:
+      for colId in 1..cCnt:
+        buf[0] = '\0'
+        db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
+                                 cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
+        rowRes[colId-1] = $buf.cstring
+        cCnt = tempcCnt
+      yield rowRes
+      res = SQLFetch(db.stmt)
+  db.sqlCheck(res)
   properFreeResult(SQL_HANDLE_STMT, db.stmt)
 
 iterator instantRows*(db: var DbConn, query: SqlQuery,
@@ -310,19 +320,30 @@ iterator instantRows*(db: var DbConn, query: SqlQuery,
     rowRes: Row
     sz: TSqlSmallInt = 0
     cCnt: TSqlSmallInt = 0.TSqlSmallInt
-    rCnt = -1
-  db.prepareFetch(query, args)
-  db.SqlCheck(SQLNumResultCols(db.stmt, cCnt))
-  db.SqlCheck(SQLRowCount(db.stmt, rCnt))
-  rowRes = newRow(cCnt)
-  for rNr in 1..rCnt:
-    for colId in 1..cCnt:
-      buf[0] = '\0'
-      db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
-                               cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
-      rowRes[colId-1] = $buf.cstring
-    db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1))
-    yield (row: rowRes, len: cCnt.int)
+    res: TSqlSmallInt = 0.TSqlSmallInt
+    tempcCnt:TSqlSmallInt # temporary cCnt,Fix the field values to be null when the release schema is compiled.
+    # tempcCnt,A field to store the number of temporary variables, for unknown reasons, 
+    # after performing a sqlgetdata function and circulating variables cCnt value will be changed to 0,
+    # so the values of the temporary variable to store the cCnt. 
+    # After every cycle and specified to cCnt. To ensure the traversal of all fields.
+  res = db.prepareFetch(query, args)
+  if res == SQL_NO_DATA:
+    discard
+  elif res == SQL_SUCCESS:
+    res = SQLNumResultCols(db.stmt, cCnt)
+    rowRes = newRow(cCnt)
+    rowRes.setLen(max(cCnt,0))
+    tempcCnt = cCnt
+    while res == SQL_SUCCESS:
+      for colId in 1..cCnt:
+        buf[0] = '\0'
+        db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
+                                 cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
+        rowRes[colId-1] = $buf.cstring
+        cCnt = tempcCnt
+      yield (row: rowRes, len: cCnt.int)
+      res = SQLFetch(db.stmt)
+  db.sqlCheck(res)
   properFreeResult(SQL_HANDLE_STMT, db.stmt)
 
 proc `[]`*(row: InstantRow, col: int): string {.inline.} =
@@ -339,43 +360,68 @@ proc getRow*(db: var DbConn, query: SqlQuery,
   ## Retrieves a single row. If the query doesn't return any rows, this proc
   ## will return a Row with empty strings for each column.
   var
+    rowRes: Row
     sz: TSqlSmallInt = 0.TSqlSmallInt
     cCnt: TSqlSmallInt = 0.TSqlSmallInt
-    rCnt = -1
-  result = @[]
-  db.prepareFetch(query, args)
-  db.SqlCheck(SQLNumResultCols(db.stmt, cCnt))
-
-  db.SqlCheck(SQLRowCount(db.stmt, rCnt))
-  for colId in 1..cCnt:
-    db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
-                             cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
-    result.add($buf.cstring)
-  db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1))
+    res: TSqlSmallInt = 0.TSqlSmallInt
+    tempcCnt:TSqlSmallInt # temporary cCnt,Fix the field values to be null when the release schema is compiled.
+    ## tempcCnt,A field to store the number of temporary variables, for unknown reasons, 
+    ## after performing a sqlgetdata function and circulating variables cCnt value will be changed to 0,
+    ## so the values of the temporary variable to store the cCnt. 
+    ## After every cycle and specified to cCnt. To ensure the traversal of all fields.
+  res = db.prepareFetch(query, args)
+  if res == SQL_NO_DATA:
+    result = @[]
+  elif res == SQL_SUCCESS:
+    res = SQLNumResultCols(db.stmt, cCnt)
+    rowRes = newRow(cCnt)
+    rowRes.setLen(max(cCnt,0))
+    tempcCnt = cCnt
+    for colId in 1..cCnt:
+      buf[0] = '\0'
+      db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
+                               cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
+      rowRes[colId-1] = $buf.cstring
+      cCnt = tempcCnt
+    res = SQLFetch(db.stmt)
+    result = rowRes
+  db.sqlCheck(res)
   properFreeResult(SQL_HANDLE_STMT, db.stmt)
 
 proc getAllRows*(db: var DbConn, query: SqlQuery,
                  args: varargs[string, `$`]): seq[Row] {.
-           tags: [ReadDbEffect, WriteDbEffect], raises: [DbError].} =
+           tags: [ReadDbEffect, WriteDbEffect], raises: [DbError] .} =
   ## Executes the query and returns the whole result dataset.
   var
+    rows: seq[Row] = @[]
     rowRes: Row
     sz: TSqlSmallInt = 0
     cCnt: TSqlSmallInt = 0.TSqlSmallInt
-    rCnt = -1
-  db.prepareFetch(query, args)
-  db.SqlCheck(SQLNumResultCols(db.stmt, cCnt))
-  db.SqlCheck(SQLRowCount(db.stmt, rCnt))
-  result = @[]
-  for rNr in 1..rCnt:
-    rowRes = @[]
-    buf[0] = '\0'
-    for colId in 1..cCnt:
-      db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
-                               cast[SqlPointer](buf.addr), 4095.TSqlSmallInt, sz.addr))
-      rowRes.add($buf.cstring)
-    db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1))
-    result.add(rowRes)
+    res: TSqlSmallInt = 0.TSqlSmallInt
+    tempcCnt:TSqlSmallInt # temporary cCnt,Fix the field values to be null when the release schema is compiled.
+    ## tempcCnt,A field to store the number of temporary variables, for unknown reasons, 
+    ## after performing a sqlgetdata function and circulating variables cCnt value will be changed to 0,
+    ## so the values of the temporary variable to store the cCnt. 
+    ## After every cycle and specified to cCnt. To ensure the traversal of all fields.
+  res = db.prepareFetch(query, args)
+  if res == SQL_NO_DATA:
+    result = @[]
+  elif res == SQL_SUCCESS:
+    res = SQLNumResultCols(db.stmt, cCnt)
+    rowRes = newRow(cCnt)
+    rowRes.setLen(max(cCnt,0))
+    tempcCnt = cCnt
+    while res == SQL_SUCCESS:
+      for colId in 1..cCnt:
+        buf[0] = '\0'
+        db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR,
+                                 cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr))
+        rowRes[colId-1] = $buf.cstring
+        cCnt = tempcCnt
+      rows.add(rowRes)
+      res = SQLFetch(db.stmt)
+    result = rows
+    db.sqlCheck(res)
   properFreeResult(SQL_HANDLE_STMT, db.stmt)
 
 iterator rows*(db: var DbConn, query: SqlQuery,
@@ -407,10 +453,9 @@ proc tryInsertId*(db: var DbConn, query: SqlQuery,
   if not tryExec(db, query, args):
     result = -1'i64
   else:
-    echo "DBMS: ",SqlGetDBMS(db).toLower()
     result = -1'i64
     try:
-      case SqlGetDBMS(db).toLower():
+      case sqlGetDBMS(db).toLower():
       of "postgresql":
         result = getValue(db, sql"SELECT LASTVAL();", []).parseInt
       of "mysql":
@@ -438,15 +483,12 @@ proc execAffectedRows*(db: var DbConn, query: SqlQuery,
   ## Runs the query (typically "UPDATE") and returns the
   ## number of affected rows
   result = -1
-  var res = SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt.SqlHandle)
-  if res != SQL_SUCCESS: dbError(db)
+  db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt.SqlHandle))
   var q = dbFormat(query, args)
-  res = SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)
-  if res != SQL_SUCCESS: dbError(db)
+  db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt))
   rawExec(db, query, args)
   var rCnt = -1
-  result = SQLRowCount(db.hDb, rCnt)
-  if res != SQL_SUCCESS: dbError(db)
+  db.sqlCheck(SQLRowCount(db.hDb, rCnt))
   properFreeResult(SQL_HANDLE_STMT, db.stmt)
   result = rCnt
 
@@ -501,5 +543,5 @@ proc setEncoding*(connection: DbConn, encoding: string): bool {.
   ##
   ## Sets the encoding of a database connection, returns true for
   ## success, false for failure.
-  #result = set_character_set(connection, encoding) == 0
-  dbError("setEncoding() is currently not implemented by the db_odbc module")
+  ##result = set_character_set(connection, encoding) == 0
+  dbError("setEncoding() is currently not implemented by the db_odbc module")
\ No newline at end of file
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 266b84b09..5a4f403b6 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -108,6 +108,8 @@ __clang__
        defined __SUNPRO_C || \
        defined __xlC__
 #  define NIM_THREADVAR __thread
+#elif defined __TINYC__
+#  define NIM_THREADVAR
 #else
 #  error "Cannot define NIM_THREADVAR"
 #endif
diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim
index 511ada9ac..5c67d621e 100644
--- a/lib/posix/kqueue.nim
+++ b/lib/posix/kqueue.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2015 Adam Strzelecki
+#        (c) Copyright 2016 Eugene Kabanov
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -11,20 +11,35 @@
 
 from posix import Timespec
 
-# Filters:
-const
-  EVFILT_READ*     = -1
-  EVFILT_WRITE*    = -2
-  EVFILT_AIO*      = -3
-  EVFILT_VNODE*    = -4
-  EVFILT_PROC*     = -5
-  EVFILT_SIGNAL*   = -6
-  EVFILT_TIMER*    = -7
-  EVFILT_MACHPORT* = -8
-  EVFILT_FS*       = -9
-  EVFILT_USER*     = -10
-  # -11 is unused
-  EVFILT_VM*       = -12
+when defined(macosx) or defined(freebsd) or defined(openbsd):
+  const
+    EVFILT_READ*     = -1
+    EVFILT_WRITE*    = -2
+    EVFILT_AIO*      = -3 ## attached to aio requests
+    EVFILT_VNODE*    = -4 ## attached to vnodes
+    EVFILT_PROC*     = -5 ## attached to struct proc
+    EVFILT_SIGNAL*   = -6 ## attached to struct proc
+    EVFILT_TIMER*    = -7 ## timers
+elif defined(netbsd):
+  const
+    EVFILT_READ*     = 0
+    EVFILT_WRITE*    = 1
+    EVFILT_AIO*      = 2 ## attached to aio requests
+    EVFILT_VNODE*    = 3 ## attached to vnodes
+    EVFILT_PROC*     = 4 ## attached to struct proc
+    EVFILT_SIGNAL*   = 5 ## attached to struct proc
+    EVFILT_TIMER*    = 6 ## timers (in ms)
+when defined(macosx):
+  const
+    EVFILT_MACHPORT* = -8  ## Mach portsets
+    EVFILT_FS*       = -9  ## filesystem events
+    EVFILT_USER*     = -10 ## user events
+    EVFILT_VM        = -12 ## virtual memory events
+elif defined(freebsd):
+  const
+    EVFILT_FS*       = -9  ## filesystem events
+    EVFILT_LIO*      = -10 ## attached to lio requests
+    EVFILT_USER*     = -11 ## user events
 
 # Actions:
 const
@@ -40,21 +55,92 @@ const
   EV_CLEAR*    = 0x0020 ## Clear event state after reporting.
   EV_RECEIPT*  = 0x0040 ## Force EV_ERROR on success, data == 0
   EV_DISPATCH* = 0x0080 ## Disable event after reporting.
+  
+  EV_SYSFLAGS* = 0xF000 ## Reserved by system
+  EV_DROP*     = 0x1000 ## Not should be dropped
+  EV_FLAG1*    = 0x2000 ## Filter-specific flag
 
 # Return values:
 const
   EV_EOF*      = 0x8000 ## EOF detected
   EV_ERROR*    = 0x4000 ## Error, data contains errno
 
+
+when defined(macosx) or defined(freebsd):
+  # EVFILT_USER is not supported by OpenBSD and NetBSD
+  #
+  # data/hint flags/masks for EVFILT_USER, shared with userspace
+  #
+  # On input, the top two bits of fflags specifies how the lower twenty four
+  # bits should be applied to the stored value of fflags.
+  #
+  # On output, the top two bits will always be set to NOTE_FFNOP and the
+  # remaining twenty four bits will contain the stored fflags value.
+  const
+    NOTE_FFNOP*      = 0x00000000'u32 ## ignore input fflags
+    NOTE_FFAND*      = 0x40000000'u32 ## AND fflags
+    NOTE_FFOR*       = 0x80000000'u32 ## OR fflags
+    NOTE_FFCOPY*     = 0xc0000000'u32 ## copy fflags
+    NOTE_FFCTRLMASK* = 0xc0000000'u32 ## masks for operations 
+    NOTE_FFLAGSMASK* = 0x00ffffff'u32
+
+    NOTE_TRIGGER*    = 0x01000000'u32 ## Cause the event to be triggered 
+                                      ## for output.
+
+# data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
+const
+  NOTE_LOWAT*      = 0x0001 ## low water mark
+
+# data/hint flags for EVFILT_VNODE, shared with userspace
+const
+  NOTE_DELETE*     = 0x0001 ## vnode was removed
+  NOTE_WRITE*      = 0x0002 ## data contents changed
+  NOTE_EXTEND*     = 0x0004 ## size increased
+  NOTE_ATTRIB*     = 0x0008 ## attributes changed
+  NOTE_LINK*       = 0x0010 ## link count changed
+  NOTE_RENAME*     = 0x0020 ## vnode was renamed
+  NOTE_REVOKE*     = 0x0040 ## vnode access was revoked
+
+# data/hint flags for EVFILT_PROC, shared with userspace
+const
+  NOTE_EXIT*       = 0x80000000'u32 ## process exited
+  NOTE_FORK*       = 0x40000000'u32 ## process forked
+  NOTE_EXEC*       = 0x20000000'u32 ## process exec'd
+  NOTE_PCTRLMASK*  = 0xf0000000'u32 ## mask for hint bits
+  NOTE_PDATAMASK*  = 0x000fffff'u32 ## mask for pid
+
+# additional flags for EVFILT_PROC
+const
+  NOTE_TRACK*      = 0x00000001'u32 ## follow across forks
+  NOTE_TRACKERR*   = 0x00000002'u32 ## could not track child
+  NOTE_CHILD*      = 0x00000004'u32 ## am a child process
+
+when defined(macosx) or defined(freebsd):
+  # additional flags for EVFILE_TIMER
+  const
+    NOTE_SECONDS*    = 0x00000001'u32 ## data is seconds
+    NOTE_MSECONDS*   = 0x00000002'u32 ## data is milliseconds
+    NOTE_USECONDS*   = 0x00000004'u32 ## data is microseconds
+    NOTE_NSECONDS*   = 0x00000008'u32 ## data is nanoseconds
+else:
+  # NetBSD and OpenBSD doesnt support NOTE_{TIME} constants, but
+  # support EVFILT_TIMER with granularity of milliseconds.
+  const
+    NOTE_MSECONDS*   = 0x00000000'u32
+
 type
+  ## This define not fully satisfy NetBSD "struct kevent"
+  ## but it works and tested.
   KEvent* {.importc: "struct kevent",
-            header: "<sys/event.h>", pure, final.} = object
-    ident*: cuint    ## identifier for this event  (uintptr_t)
-    filter*: cshort  ## filter for event
-    flags*: cushort  ## general flags
-    fflags*: cuint   ## filter-specific flags
-    data*: cuint     ## filter-specific data  (intptr_t)
-    #udata*: ptr void ## opaque user data identifier
+            header: """#include <sys/types.h>
+                       #include <sys/event.h>
+                       #include <sys/time.h>""", pure, final.} = object
+    ident*  : uint     ## identifier for this event  (uintptr_t)
+    filter* : cshort   ## filter for event
+    flags*  : cushort  ## general flags
+    fflags* : cuint    ## filter-specific flags
+    data*   : int      ## filter-specific data  (intptr_t)
+    udata*  : pointer  ## opaque user data identifier
 
 proc kqueue*(): cint {.importc: "kqueue", header: "<sys/event.h>".}
   ## Creates new queue and returns its descriptor.
@@ -65,7 +151,7 @@ proc kevent*(kqFD: cint,
      {.importc: "kevent", header: "<sys/event.h>".}
   ## Manipulates queue for given ``kqFD`` descriptor.
 
-proc EV_SET*(event: ptr KEvent, ident: cuint, filter: cshort, flags: cushort,
-             fflags: cuint, data: cuint, udata: ptr void)
+proc EV_SET*(event: ptr KEvent, ident: uint, filter: cshort, flags: cushort,
+             fflags: cuint, data: int, udata: pointer)
      {.importc: "EV_SET", header: "<sys/event.h>".}
   ## Fills event with given data.
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 40b48f992..4c7b817cb 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -486,11 +486,11 @@ type
     l_onoff*: cint  ## Indicates whether linger option is enabled.
     l_linger*: cint ## Linger time, in seconds.
 
-  InPort* = int16 ## unsigned!
-  InAddrScalar* = int32 ## unsigned!
+  InPort* = uint16
+  InAddrScalar* = uint32
 
   InAddrT* {.importc: "in_addr_t", pure, final,
-             header: "<netinet/in.h>".} = int32 ## unsigned!
+             header: "<netinet/in.h>".} = uint32
 
   InAddr* {.importc: "struct in_addr", pure, final,
              header: "<netinet/in.h>".} = object ## struct in_addr
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index b72face91..0e3824a81 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -508,13 +508,39 @@ template foldl*(sequence, operation: expr): expr =
   ##   assert subtraction == -15, "Subtraction is (((5)-9)-11)"
   ##   assert multiplication == 495, "Multiplication is (((5)*9)*11)"
   ##   assert concatenation == "nimiscool"
-  assert sequence.len > 0, "Can't fold empty sequences"
-  var result {.gensym.}: type(sequence[0])
-  result = sequence[0]
-  for i in 1..<sequence.len:
+  let s = sequence
+  assert s.len > 0, "Can't fold empty sequences"
+  var result {.gensym.}: type(s[0])
+  result = s[0]
+  for i in 1..<s.len:
     let
       a {.inject.} = result
-      b {.inject.} = sequence[i]
+      b {.inject.} = s[i]
+    result = operation
+  result
+
+template foldl*(sequence, operation: expr, first): expr =
+  ## Template to fold a sequence from left to right, returning the accumulation.
+  ##
+  ## This version of ``foldl`` gets a starting parameter. This makes it possible
+  ## to accumulate the sequence into a different type than the sequence elements.
+  ##
+  ## The ``operation`` parameter should be an expression which uses the variables
+  ## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the
+  ## start value (the first ``a``) and therefor defines the type of the result.
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     numbers = @[0, 8, 1, 5]
+  ##     digits = foldl(numbers, a & (chr(b + ord('0'))), "")
+  ##   assert digits == "0815"
+  var result {.gensym.}: type(first)
+  result = first
+  for x in items(sequence):
+    let
+      a {.inject.} = result
+      b {.inject.} = x
     result = operation
   result
 
@@ -544,12 +570,13 @@ template foldr*(sequence, operation: expr): expr =
   ##   assert subtraction == 7, "Subtraction is (5-(9-(11)))"
   ##   assert multiplication == 495, "Multiplication is (5*(9*(11)))"
   ##   assert concatenation == "nimiscool"
-  assert sequence.len > 0, "Can't fold empty sequences"
-  var result {.gensym.}: type(sequence[0])
-  result = sequence[sequence.len - 1]
-  for i in countdown(sequence.len - 2, 0):
+  let s = sequence
+  assert s.len > 0, "Can't fold empty sequences"
+  var result {.gensym.}: type(s[0])
+  result = sequence[s.len - 1]
+  for i in countdown(s.len - 2, 0):
     let
-      a {.inject.} = sequence[i]
+      a {.inject.} = s[i]
       b {.inject.} = result
     result = operation
   result
diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim
new file mode 100644
index 000000000..e93ceb02f
--- /dev/null
+++ b/lib/pure/collections/sharedlist.nim
@@ -0,0 +1,95 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Shared list support.
+
+{.push stackTrace:off.}
+
+import
+  locks
+
+const
+  ElemsPerNode = 100
+
+type
+  SharedListNode[A] = ptr object
+    next: SharedListNode[A]
+    dataLen: int
+    d: array[ElemsPerNode, A]
+
+  SharedList*[A] = object ## generic shared list
+    head, tail: SharedListNode[A]
+    lock*: Lock
+
+template withLock(t, x: untyped) =
+  acquire(t.lock)
+  x
+  release(t.lock)
+
+proc iterAndMutate*[A](x: var SharedList[A]; action: proc(x: A): bool) =
+  ## iterates over the list. If 'action' returns true, the
+  ## current item is removed from the list.
+  withLock(x):
+    var n = x.head
+    while n != nil:
+      var i = 0
+      while i < n.dataLen:
+        # action can add new items at the end, so release the lock:
+        release(x.lock)
+        if action(n.d[i]):
+          acquire(x.lock)
+          let t = x.tail
+          n.d[i] = t.d[t.dataLen]
+          dec t.dataLen
+        else:
+          acquire(x.lock)
+          inc i
+      n = n.next
+
+iterator items*[A](x: var SharedList[A]): A =
+  withLock(x):
+    var it = x.head
+    while it != nil:
+      for i in 0..it.dataLen-1:
+        yield it.d[i]
+      it = it.next
+
+proc add*[A](x: var SharedList[A]; y: A) =
+  withLock(x):
+    var node: SharedListNode[A]
+    if x.tail == nil or x.tail.dataLen == ElemsPerNode:
+      node = cast[type node](allocShared0(sizeof(node[])))
+      node.next = x.tail
+      x.tail = node
+      if x.head == nil: x.head = node
+    else:
+      node = x.tail
+    node.d[node.dataLen] = y
+    inc(node.dataLen)
+
+proc initSharedList*[A](): SharedList[A] =
+  initLock result.lock
+  result.head = nil
+  result.tail = nil
+
+proc clear*[A](t: var SharedList[A]) =
+  withLock(t):
+    var it = t.head
+    while it != nil:
+      let nxt = it.next
+      deallocShared(it)
+      it = nxt
+    t.head = nil
+    t.tail = nil
+
+proc deinitSharedList*[A](t: var SharedList[A]) =
+  clear(t)
+  deinitLock t.lock
+
+{.pop.}
diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim
index beafe1109..e4ec05b1c 100644
--- a/lib/pure/collections/tableimpl.nim
+++ b/lib/pure/collections/tableimpl.nim
@@ -129,4 +129,7 @@ template delImpl() {.dirty, immediate.} =
           r = t.data[i].hcode and msk    # "home" location of key@i
           if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
             break
-        shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
+        when defined(js):
+          t.data[j] = t.data[i]
+        else:
+          shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index aa55b5ade..f602ce31d 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -92,6 +92,10 @@ type
 {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
     PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
 
+var
+  level {.threadvar.}: Level   ## global log filter
+  handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
+
 proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
   ## Format a log message using the ``frmt`` format string, ``level`` and varargs.
   ## See the module documentation for the format string syntax.
@@ -133,13 +137,13 @@ method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
 
 method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     writeLine(stdout, substituteLog(logger.fmtStr, level, args))
     if level in {lvlError, lvlFatal}: flushFile(stdout)
 
 method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to a file using ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
     if level in {lvlError, lvlFatal}: flushFile(logger.file)
 
@@ -224,7 +228,7 @@ proc rotate(logger: RollingFileLogger) =
 
 method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to a file using rolling ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     if logger.curLine >= logger.maxLines:
       logger.file.close()
       rotate(logger)
@@ -238,9 +242,6 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`])
 
 # --------
 
-var level {.threadvar.}: Level   ## global log filter
-var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
-
 proc logLoop(level: Level, args: varargs[string, `$`]) =
   for logger in items(handlers):
     if level >= logger.levelThreshold:
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index b0104336e..84c8d3b11 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -44,6 +44,7 @@ when not defined(js) and not defined(nimscript):
 
 const
   PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)
+  TAU* = 2.0 * PI ## the circle constant TAU (= 2 * PI)
   E* = 2.71828182845904523536028747 ## Euler's number
 
   MaxFloat64Precision* = 16 ## maximum number of meaningful digits
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 3951b46a3..043d6d80a 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -219,31 +219,67 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
 proc dealloc*(ai: ptr AddrInfo) =
   freeaddrinfo(ai)
 
-proc ntohl*(x: int32): int32 =
-  ## Converts 32-bit integers from network to host byte order.
+proc ntohl*(x: uint32): uint32 =
+  ## Converts 32-bit unsigned integers from network to host byte order.
   ## On machines where the host byte order is the same as network byte order,
   ## this is a no-op; otherwise, it performs a 4-byte swap operation.
   when cpuEndian == bigEndian: result = x
-  else: result = (x shr 24'i32) or
-                 (x shr 8'i32 and 0xff00'i32) or
-                 (x shl 8'i32 and 0xff0000'i32) or
-                 (x shl 24'i32)
+  else: result = (x shr 24'u32) or
+                 (x shr 8'u32 and 0xff00'u32) or
+                 (x shl 8'u32 and 0xff0000'u32) or
+                 (x shl 24'u32)
 
-proc ntohs*(x: int16): int16 =
-  ## Converts 16-bit integers from network to host byte order. On machines
-  ## where the host byte order is the same as network byte order, this is
-  ## a no-op; otherwise, it performs a 2-byte swap operation.
+template ntohl*(x: int32): expr {.deprecated.} =
+  ## Converts 32-bit integers from network to host byte order.
+  ## On machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+  ## **Warning**: This template is deprecated since 0.14.0, IPv4
+  ## addresses are now treated as unsigned integers. Please use the unsigned
+  ## version of this template.
+  cast[int32](ntohl(cast[uint32](x)))
+
+proc ntohs*(x: uint16): uint16 =
+  ## Converts 16-bit unsigned integers from network to host byte order. On
+  ## machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 2-byte swap operation.
   when cpuEndian == bigEndian: result = x
-  else: result = (x shr 8'i16) or (x shl 8'i16)
-
-template htonl*(x: int32): expr =
+  else: result = (x shr 8'u16) or (x shl 8'u16)
+
+template ntohs*(x: int16): expr {.deprecated.} =
+  ## Converts 16-bit integers from network to host byte order. On
+  ## machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 2-byte swap operation.
+  ## **Warning**: This template is deprecated since 0.14.0, where port
+  ## numbers became unsigned integers. Please use the unsigned version of
+  ## this template.
+  cast[int16](ntohs(cast[uint16](x)))
+
+template htonl*(x: int32): expr {.deprecated.} =
   ## Converts 32-bit integers from host to network byte order. On machines
   ## where the host byte order is the same as network byte order, this is
   ## a no-op; otherwise, it performs a 4-byte swap operation.
+  ## **Warning**: This template is deprecated since 0.14.0, IPv4
+  ## addresses are now treated as unsigned integers. Please use the unsigned
+  ## version of this template.
   nativesockets.ntohl(x)
 
-template htons*(x: int16): expr =
-  ## Converts 16-bit positive integers from host to network byte order.
+template htonl*(x: uint32): expr =
+  ## Converts 32-bit unsigned integers from host to network byte order. On
+  ## machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+  nativesockets.ntohl(x)
+
+template htons*(x: int16): expr {.deprecated.} =
+  ## Converts 16-bit integers from host to network byte order.
+  ## On machines where the host byte order is the same as network byte
+  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
+  ## **Warning**: This template is deprecated since 0.14.0, where port
+  ## numbers became unsigned integers. Please use the unsigned version of
+  ## this template.
+  nativesockets.ntohs(x)
+
+template htons*(x: uint16): expr =
+  ## Converts 16-bit unsigned integers from host to network byte order.
   ## On machines where the host byte order is the same as network byte
   ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
   nativesockets.ntohs(x)
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index b9764edd3..330682ca9 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -368,7 +368,7 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
       name.sin_family = toInt(AF_INET).int16
     else:
       name.sin_family = toInt(AF_INET)
-    name.sin_port = htons(int16(port))
+    name.sin_port = htons(port.uint16)
     name.sin_addr.s_addr = htonl(INADDR_ANY)
     if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)),
                   sizeof(name).SockLen) < 0'i32:
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 017385825..470559e17 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1350,15 +1350,12 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
   ## 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
   # Solaris:
   # /proc/<pid>/object/a.out (filename only)
   # /proc/<pid>/path/a.out (complete pathname)
-  # *BSD (and maybe Darwin too):
-  # /proc/<pid>/file
+  # FreeBSD: /proc/<pid>/file
   when defined(windows):
     when useWinUnicode:
       var buf = newWideCString("", 256)
@@ -1368,15 +1365,6 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
       result = newString(256)
       var len = getModuleFileNameA(0, result, 256)
       setlen(result, int(len))
-  elif defined(linux) or defined(aix):
-    result = getApplAux("/proc/self/exe")
-    if result.len == 0: result = getApplHeuristic()
-  elif defined(solaris):
-    result = getApplAux("/proc/" & $getpid() & "/path/a.out")
-    if result.len == 0: result = getApplHeuristic()
-  elif defined(freebsd):
-    result = getApplAux("/proc/" & $getpid() & "/file")
-    if result.len == 0: result = getApplHeuristic()
   elif defined(macosx):
     var size: cuint32
     getExecPath1(nil, size)
@@ -1386,9 +1374,15 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     if result.len > 0:
       result = result.expandFilename
   else:
+    when defined(linux) or defined(aix) or defined(netbsd):
+      result = getApplAux("/proc/self/exe")
+    elif defined(solaris):
+      result = getApplAux("/proc/" & $getpid() & "/path/a.out")
+    elif defined(freebsd):
+      result = getApplAux("/proc/" & $getpid() & "/file")
     # little heuristic that may work on other POSIX-like systems:
-    result = string(getEnv("_"))
-    if result.len == 0: result = getApplHeuristic()
+    if result.len == 0:
+      result = getApplHeuristic()
 
 proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} =
   ## Returns the filename of the application's executable.
@@ -1404,7 +1398,6 @@ proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} =
 
 proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
   ## Returns the directory of the application's executable.
-  ## **Note**: This does not work reliably on BSD.
   result = splitFile(getAppFilename()).dir
 
 proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 72c64befc..6fd05dc4b 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -164,7 +164,7 @@ proc `-` *[T](x: Rational[T], y: T): Rational[T] =
 
 proc `-` *[T](x: T, y: Rational[T]): Rational[T] =
   ## Subtract rational `y` from int `x`.
-  result.num = - x * y.den + y.num
+  result.num = x * y.den - y.num
   result.den = y.den
 
 proc `-=` *[T](x: var Rational[T], y: Rational[T]) =
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index df7071642..6e97237e0 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -134,11 +134,16 @@ proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
   ## Converts a string to a rope.
   if s.len == 0:
     result = nil
-  elif cacheEnabled:
-    result = insertInCache(s, cache)
-    cache = result
   else:
-    result = newRope(s)
+    when nimvm:
+      # No caching in VM context
+      result = newRope(s)
+    else:
+      if cacheEnabled:
+        result = insertInCache(s, cache)
+        cache = result
+      else:
+        result = newRope(s)
 
 proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
   ## Converts an int to a rope.
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index a446f85b4..f2c1e77e1 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -882,7 +882,7 @@ proc abbrev*(s: string, possibilities: openArray[string]): int =
 
 # ---------------------------------------------------------------------------
 
-proc join*(a: openArray[string], sep: string): string {.
+proc join*(a: openArray[string], sep: string = ""): string {.
   noSideEffect, rtl, extern: "nsuJoinSep".} =
   ## Concatenates all strings in `a` separating them with `sep`.
   if len(a) > 0:
@@ -896,16 +896,15 @@ proc join*(a: openArray[string], sep: string): string {.
   else:
     result = ""
 
-proc join*(a: openArray[string]): string {.
-  noSideEffect, rtl, extern: "nsuJoin".} =
-  ## Concatenates all strings in `a`.
-  if len(a) > 0:
-    var L = 0
-    for i in 0..high(a): inc(L, a[i].len)
-    result = newStringOfCap(L)
-    for i in 0..high(a): add(result, a[i])
-  else:
-    result = ""
+proc join*[T: not string](a: openArray[T], sep: string = ""): string {.
+  noSideEffect, rtl.} =
+  ## Converts all elements in `a` to strings using `$` and concatenates them
+  ## with `sep`.
+  result = ""
+  for i, x in a:
+    if i > 0:
+      add(result, sep)
+    add(result, $x)
 
 type
   SkipTable = array[char, int]
@@ -1721,3 +1720,8 @@ when isMainModule:
   doAssert(not isUpper("AAcc"))
   doAssert(not isUpper("A#$"))
   doAssert(unescape(r"\x013", "", "") == "\x013")
+
+  doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+  doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+  doAssert join([1, 2, 3]) == "123"
+  doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
diff --git a/lib/system.nim b/lib/system.nim
index 241f55224..fefabe53f 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1288,6 +1288,10 @@ const
   hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
   taintMode = compileOption("taintmode")
 
+when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
+  # tcc doesn't support TLS
+  {.error: "``--tlsEmulation:on`` must be used when using threads with tcc backend".}
+  
 when defined(boehmgc):
   when defined(windows):
     const boehmLib = "boehmgc.dll"
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
index 158fe91bc..a79dcb152 100644
--- a/lib/system/atomics.nim
+++ b/lib/system/atomics.nim
@@ -197,6 +197,51 @@ when defined(windows) and not someGcc:
   proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool =
     interlockedCompareExchange(p, cast[int](newValue), cast[int](oldValue)) != 0
   # XXX fix for 64 bit build
+elif defined(tcc) and not defined(windows):
+  when defined(amd64):
+    {.emit:"""
+static int __tcc_cas(int *ptr, int oldVal, int newVal)
+{
+    unsigned char ret;
+    __asm__ __volatile__ (
+            "  lock\n"
+            "  cmpxchgq %2,%1\n"
+            "  sete %0\n"
+            : "=q" (ret), "=m" (*ptr)
+            : "r" (newVal), "m" (*ptr), "a" (oldVal)
+            : "memory");
+
+    if (ret)
+      return 0;
+    else
+      return 1;
+}
+""".}
+  else:
+    assert sizeof(int) == 4
+    {.emit:"""
+static int __tcc_cas(int *ptr, int oldVal, int newVal)
+{
+    unsigned char ret;
+    __asm__ __volatile__ (
+            "  lock\n"
+            "  cmpxchgl %2,%1\n"
+            "  sete %0\n"
+            : "=q" (ret), "=m" (*ptr)
+            : "r" (newVal), "m" (*ptr), "a" (oldVal)
+            : "memory");
+
+    if (ret)
+      return 0;
+    else
+      return 1;
+}
+""".}
+    
+  proc tcc_cas(p: ptr int; oldValue, newValue: int): bool
+    {.importc: "__tcc_cas", nodecl.}
+  proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool =
+    tcc_cas(cast[ptr int](p), cast[int](oldValue), cast[int](newValue))
 else:
   # this is valid for GCC and Intel C++
   proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool
@@ -207,7 +252,7 @@ else:
 when (defined(x86) or defined(amd64)) and someGcc:
   proc cpuRelax* {.inline.} =
     {.emit: """asm volatile("pause" ::: "memory");""".}
-elif someGcc:
+elif someGcc or defined(tcc):
   proc cpuRelax* {.inline.} =
     {.emit: """asm volatile("" ::: "memory");""".}
 elif (defined(x86) or defined(amd64)) and defined(vcc):
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index 6dc8999d1..ba5e4bbeb 100644
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -23,16 +23,16 @@ proc rawWrite(f: File, s: string) =
 
 proc nimLoadLibraryError(path: string) =
   # carefully written to avoid memory allocation:
-  stdout.rawWrite("could not load: ")
-  stdout.rawWrite(path)
-  stdout.rawWrite("\n")
+  stderr.rawWrite("could not load: ")
+  stderr.rawWrite(path)
+  stderr.rawWrite("\n")
   quit(1)
 
 proc procAddrError(name: cstring) {.noinline.} =
   # carefully written to avoid memory allocation:
-  stdout.rawWrite("could not import: ")
-  stdout.write(name)
-  stdout.rawWrite("\n")
+  stderr.rawWrite("could not import: ")
+  stderr.write(name)
+  stderr.rawWrite("\n")
   quit(1)
 
 # this code was inspired from Lua's source code:
@@ -71,7 +71,7 @@ when defined(posix):
     when defined(nimDebugDlOpen):
       let error = dlerror()
       if error != nil:
-        c_fprintf(c_stdout, "%s\n", error)
+        c_fprintf(c_stderr, "%s\n", error)
 
   proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
     result = dlsym(lib, name)
diff --git a/lib/system/gc_stack.nim b/lib/system/gc_stack.nim
new file mode 100644
index 000000000..3a5c5594a
--- /dev/null
+++ b/lib/system/gc_stack.nim
@@ -0,0 +1,382 @@
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2016 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# "Stack GC" for embedded devices or ultra performance requirements.
+
+include osalloc
+
+# We manage memory as a thread local stack. Since the allocation pointer
+# is detached from the control flow pointer, this model is vastly more
+# useful than the traditional programming model while almost as safe.
+# Individual objects can also be deleted but no coalescing is performed.
+# Stacks can also be moved from one thread to another.
+
+# We also support 'finalizers'.
+
+type
+  Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
+    # A ref type can have a finalizer that is called before the object's
+    # storage is freed.
+
+  AlignType = BiggestFloat
+  ObjHeader = object
+    typ: PNimType
+    nextFinal: ptr ObjHeader # next object with finalizer
+
+  Hole = object # stacks can have holes. Otherwise 'growObj' would be insane.
+    zeroTyp: pointer # overlaid with 'typ' field. Always 'nil'.
+    size: int # size of the free slot
+
+  Chunk = ptr BaseChunk
+  BaseChunk = object
+    next: Chunk
+    size: int
+    head, last: ptr ObjHeader # first and last object in chunk that
+                              # has a finalizer attached to it
+
+type
+  StackPtr = object
+    chunk: pointer
+    remaining: int
+    current: Chunk
+
+  MemRegion* = object
+    remaining: int
+    chunk: pointer
+    head, last: Chunk
+    nextChunkSize, totalSize: int
+    hole: ptr Hole # we support individual freeing
+    lock: SysLock
+
+var
+  region {.threadVar.}: MemRegion
+
+template withRegion*(r: MemRegion; body: untyped) =
+  let oldRegion = region
+  region = r
+  try:
+    body
+  finally:
+    region = oldRegion
+
+template inc(p: pointer, s: int) =
+  p = cast[pointer](cast[int](p) +% s)
+
+template `+!`(p: pointer, s: int): pointer =
+  cast[pointer](cast[int](p) +% s)
+
+template `-!`(p: pointer, s: int): pointer =
+  cast[pointer](cast[int](p) +% s)
+
+proc allocSlowPath(r: var MemRegion; size: int) =
+  # we need to ensure that the underlying linked list
+  # stays small. Say we want to grab 16GB of RAM with some
+  # exponential growth function. So we allocate 16KB, then
+  # 32 KB, 64 KB, 128KB, 256KB, 512KB, 1MB, 2MB, 4MB,
+  # 8MB, 16MB, 32MB, 64MB, 128MB, 512MB, 1GB, 2GB, 4GB, 8GB,
+  # 16GB --> list contains only 20 elements! That's reasonable.
+  if (r.totalSize and 1) == 0:
+    r.nextChunkSize =
+      if r.totalSize < 64 * 1024: PageSize*4
+      else: r.nextChunkSize*2
+  var s = align(size+sizeof(BaseChunk), PageSize)
+  var fresh: Chunk
+  if s > r.nextChunkSize:
+    fresh = cast[Chunk](osAllocPages(s))
+  else:
+    fresh = cast[Chunk](osTryAllocPages(r.nextChunkSize))
+    if fresh == nil:
+      fresh = cast[Chunk](osAllocPages(s))
+      # lowest bit in totalSize is the "don't increase nextChunkSize"
+      inc r.totalSize
+    else:
+      s = r.nextChunkSize
+  fresh.size = s
+  fresh.final = nil
+  r.totalSize += s
+  let old = r.last
+  if old == nil:
+    r.head = fresh
+  else:
+    r.last.next = fresh
+  r.chunk = fresh +! sizeof(BaseChunk)
+  r.last = fresh
+  r.remaining = s - sizeof(BaseChunk)
+
+proc alloc(r: var MemRegion; size: int): pointer {.inline.} =
+  if unlikely(r.remaining < size): allocSlowPath(r, size)
+  dec(r.remaining, size)
+  result = r.chunk
+  inc r.chunk, size
+
+proc runFinalizers(c: Chunk) =
+  var it = c.head
+  while it != nil:
+    # indivually freed objects with finalizer stay in the list, but
+    # their typ is nil then:
+    if it.typ != nil and it.typ.finalizer != nil:
+      (cast[Finalizer](cell.typ.finalizer))(cell+!sizeof(ObjHeader))
+    it = it.next
+
+proc dealloc(r: var MemRegion; p: pointer) =
+  let it = p-!sizeof(ObjHeader)
+  if it.typ != nil and it.typ.finalizer != nil:
+    (cast[Finalizer](cell.typ.finalizer))(p)
+  it.typ = nil
+
+proc deallocAll(head: Chunk) =
+  var it = head
+  while it != nil:
+    runFinalizers(it)
+    osDeallocPages(it, it.size)
+    it = it.next
+
+proc deallocAll*(r: var MemRegion) =
+  deallocAll(r.head)
+  zeroMem(addr r, sizeof r)
+
+proc obstackPtr*(r: MemRegion): StackPtr =
+  result.chunk = r.chunk
+  result.remaining = r.remaining
+  result.current = r.last
+
+proc setObstackPtr*(r: MemRegion; sp: StackPtr) =
+  # free everything after 'sp':
+  if sp.current != nil:
+    deallocAll(sp.current.next)
+  r.chunk = sp.chunk
+  r.remaining = sp.remaining
+  r.last = sp.current
+
+proc joinRegion*(dest: var MemRegion; src: MemRegion) =
+  # merging is not hard.
+  if dest.head.isNil:
+    dest.head = src.head
+  else:
+    dest.last.next = src.head
+  dest.last = src.last
+  dest.chunk = src.chunk
+  dest.remaining = src.remaining
+  dest.nextChunkSize = max(dest.nextChunkSize, src.nextChunkSize)
+  dest.totalSize += src.totalSize
+  if dest.hole.size < src.hole.size:
+    dest.hole = src.hole
+
+proc isOnHeap*(r: MemRegion; p: pointer): bool =
+  # the last chunk is the largest, so check it first. It's also special
+  # in that contains the current bump pointer:
+  if r.last >= p and p < r.chunk:
+    return true
+  var it = r.head
+  while it != r.last:
+    if it >= p and p <= it+!it.size: return true
+    it = it.next
+
+proc isInteriorPointer(r: MemRegion; p: pointer): pointer =
+  discard " we cannot patch stack pointers anyway!"
+
+type
+  PointerStackChunk = object
+    next, prev: ptr PointerStackChunk
+    len: int
+    data: array[128, pointer]
+
+template head(s: PointerStackChunk): untyped = s.prev
+template tail(s: PointerStackChunk): untyped = s.next
+
+include chains
+
+proc push(r: var MemRegion; s: var PointerStackChunk; x: pointer) =
+  if s.len < high(s.data):
+    s.data[s.len] = x
+    inc s.len
+  else:
+    let fresh = cast[ptr PointerStackChunk](alloc(r, sizeof(PointerStackChunk)))
+    fresh.len = 1
+    fresh.data[0] = x
+    fresh.next = nil
+    fresh.prev = nil
+    append(s, fresh)
+
+
+proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
+                        dest, src: pointer, mt: PNimType) {.benign.}
+proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
+                        dest, src: pointer, n: ptr TNimNode) {.benign.} =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  case n.kind
+  of nkSlot:
+    genericDeepCopyAux(cast[pointer](d +% n.offset),
+                       cast[pointer](s +% n.offset), n.typ)
+  of nkList:
+    for i in 0..n.len-1:
+      genericDeepCopyAux(dest, src, n.sons[i])
+  of nkCase:
+    var dd = selectBranch(dest, n)
+    var m = selectBranch(src, n)
+    # reset if different branches are in use; note different branches also
+    # imply that's not self-assignment (``x = x``)!
+    if m != dd and dd != nil:
+      genericResetAux(dest, dd)
+    copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+            n.typ.size)
+    if m != nil:
+      genericDeepCopyAux(dest, src, m)
+  of nkNone: sysAssert(false, "genericDeepCopyAux")
+
+proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
+  result = rawNewStringNoInit(dr, src.len)
+  result.len = src.len
+  c_memcpy(result.data, src.data, src.len + 1)
+
+proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
+                        dest, src: pointer, mt: PNimType) =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  sysAssert(mt != nil, "genericDeepCopyAux 2")
+  case mt.kind
+  of tyString:
+    var x = cast[PPointer](dest)
+    var s2 = cast[PPointer](s)[]
+    if s2 == nil:
+      x[] = nil
+    else:
+      x[] = copyDeepString(cast[NimString](s2))
+  of tySequence:
+    var s2 = cast[PPointer](src)[]
+    var seq = cast[PGenericSeq](s2)
+    var x = cast[PPointer](dest)
+    if s2 == nil:
+      x[] = nil
+      return
+    sysAssert(dest != nil, "genericDeepCopyAux 3")
+    x[] = newSeq(mt, seq.len)
+    var dst = cast[ByteAddress](cast[PPointer](dest)[])
+    for i in 0..seq.len-1:
+      genericDeepCopyAux(dr, stack,
+        cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+        cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
+                     GenericSeqSize),
+        mt.base)
+  of tyObject:
+    # we need to copy m_type field for tyObject, as it could be empty for
+    # sequence reallocations:
+    var pint = cast[ptr PNimType](dest)
+    pint[] = cast[ptr PNimType](src)[]
+    if mt.base != nil:
+      genericDeepCopyAux(dr, stack, dest, src, mt.base)
+    genericDeepCopyAux(dr, stack, dest, src, mt.node)
+  of tyTuple:
+    genericDeepCopyAux(dr, stack, dest, src, mt.node)
+  of tyArray, tyArrayConstr:
+    for i in 0..(mt.size div mt.base.size)-1:
+      genericDeepCopyAux(dr, stack,
+                         cast[pointer](d +% i*% mt.base.size),
+                         cast[pointer](s +% i*% mt.base.size), mt.base)
+  of tyRef:
+    let s2 = cast[PPointer](src)[]
+    if s2 == nil:
+      cast[PPointer](dest)[] = nil
+    else:
+      # we modify the header of the cell temporarily; instead of the type
+      # field we store a forwarding pointer. XXX This is bad when the cloning
+      # fails due to OOM etc.
+      let x = usrToCell(s2)
+      let forw = cast[int](x.typ)
+      if (forw and 1) == 1:
+        # we stored a forwarding pointer, so let's use that:
+        let z = cast[pointer](forw and not 1)
+        unsureAsgnRef(cast[PPointer](dest), z)
+      else:
+        let realType = x.typ
+        let z = newObj(realType, realType.base.size)
+
+        unsureAsgnRef(cast[PPointer](dest), z)
+        x.typ = cast[PNimType](cast[int](z) or 1)
+        genericDeepCopyAux(dr, stack, z, s2, realType.base)
+        x.typ = realType
+  else:
+    copyMem(dest, src, mt.size)
+
+proc joinAliveDataFromRegion*(dest: var MemRegion; src: var MemRegion;
+                              root: pointer): pointer =
+  # we mark the alive data and copy only alive data over to 'dest'.
+  # This is O(liveset) but it nicely compacts memory, so it's fine.
+  # We use the 'typ' field as a forwarding pointer. The forwarding
+  # pointers have bit 0 set, so we can disambiguate them.
+  # We allocate a temporary stack in 'src' that we later free:
+  var s: PointerStackChunk
+  s.len = 1
+  s.data[0] = root
+  while s.len > 0:
+    var p: pointer
+    if s.tail == nil:
+      p = s.data[s.len-1]
+      dec s.len
+    else:
+      p = s.tail.data[s.tail.len-1]
+      dec s.tail.len
+      if s.tail.len == 0:
+        unlink(s, s.tail)
+
+proc rawNewObj(r: var MemRegion, typ: PNimType, size: int): pointer =
+  var res = cast[ptr ObjHeader](alloc(r, size + sizeof(ObjHeader)))
+  res.typ = typ
+  if typ.finalizer != nil:
+    res.nextFinal = r.chunk.head
+    r.chunk.head = res
+  result = res +! sizeof(ObjHeader)
+
+proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, region)
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, region)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+
+proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  zeroMem(result, size)
+
+proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+
+proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
+  collectCT(gch)
+  var ol = usrToCell(old)
+  sysAssert(ol.typ != nil, "growObj: 1")
+  gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
+
+  var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
+  var elemSize = 1
+  if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  copyMem(res, ol, oldsize + sizeof(Cell))
+  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
+          newsize-oldsize)
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+  result = cellToUsr(res)
+
+proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
+  result = growObj(old, newsize, region)
+
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index c96f2f958..1b98883b9 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -263,9 +263,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
 proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
   when defined(nimphp):
     asm """
-      $result = array();
-      for($i = 0; $i < `len`; $i++) $result[] = chr(0);
-      return $result;
+      return str_repeat(chr(0),`len`);
     """
   else:
     asm """
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index e0d14737e..5e576f0a3 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -427,7 +427,7 @@ elif defined(nogc) and defined(useMalloc):
   proc initGC() = discard
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
-    result = alloc(size)
+    result = alloc0(size)
   proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
     result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
     cast[PGenericSeq](result).len = len
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index cc1a28213..78410d716 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -94,7 +94,7 @@ elif defined(posix):
   proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
             off: int): pointer {.header: "<sys/mman.h>".}
 
-  proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
+  proc munmap(adr: pointer, len: int): cint {.header: "<sys/mman.h>".}
 
   proc osAllocPages(size: int): pointer {.inline.} =
     result = mmap(nil, size, PROT_READ or PROT_WRITE,
@@ -108,7 +108,7 @@ elif defined(posix):
     if result == cast[pointer](-1): result = nil
 
   proc osDeallocPages(p: pointer, size: int) {.inline} =
-    when reallyOsDealloc: munmap(p, size)
+    when reallyOsDealloc: discard munmap(p, size)
 
 elif defined(windows):
   const
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 7f18ed31c..4da4781ef 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -74,22 +74,22 @@ proc reprChar(x: char): string {.compilerRtl.} =
 
 proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
   # we read an 'int' but this may have been too large, so mask the other bits:
-  let e = if typ.size == 1: e and 0xff
-          elif typ.size == 2: e and 0xffff
-          elif typ.size == 4: e and 0xffffffff
-          else: e
+  let b = (sizeof(int)-typ.size)*8 # bits
+  let m = 1 shl (b-1) # mask
+  var o = e and ((1 shl b)-1) # clear upper bits
+  o = (o xor m) - m # sign extend
   # XXX we need a proper narrowing based on signedness here
   #e and ((1 shl (typ.size*8)) - 1)
   if ntfEnumHole notin typ.flags:
-    if e <% typ.node.len:
-      return $typ.node.sons[e].name
+    if o <% typ.node.len:
+      return $typ.node.sons[o].name
   else:
     # ugh we need a slow linear search:
     var n = typ.node
     var s = n.sons
     for i in 0 .. n.len-1:
-      if s[i].offset == e: return $s[i].name
-  result = $e & " (invalid data!)"
+      if s[i].offset == o: return $s[i].name
+  result = $o & " (invalid data!)"
 
 type
   PByteArray = ptr array[0.. 0xffff, int8]
@@ -260,6 +260,7 @@ when not defined(useNimRtl):
     of tyInt16: add result, $int(cast[ptr int16](p)[])
     of tyInt32: add result, $int(cast[ptr int32](p)[])
     of tyInt64: add result, $(cast[ptr int64](p)[])
+    of tyUInt: add result, $(cast[ptr uint](p)[])
     of tyUInt8: add result, $(cast[ptr uint8](p)[])
     of tyUInt16: add result, $(cast[ptr uint16](p)[])
     of tyUInt32: add result, $(cast[ptr uint32](p)[])
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index e81219a70..d0bba6775 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -82,12 +82,11 @@ when NoFakeVars:
     const
       IOFBF = cint(0)
       IONBF = cint(4)
-  elif defined(macosx) or defined(linux):
+  else:
+    # On all systems I could find, including Linux, Mac OS X, and the BSDs
     const
       IOFBF = cint(0)
       IONBF = cint(2)
-  else:
-    {.error: "IOFBF not ported to your platform".}
 else:
   var
     IOFBF {.importc: "_IOFBF", nodecl.}: cint
@@ -271,12 +270,33 @@ const
     # we always use binary here as for Nim the OS line ending
     # should not be translated.
 
+when defined(posix) and not defined(nimscript):
+  type
+    Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
+
+    Stat {.importc: "struct stat",
+             header: "<sys/stat.h>", final, pure.} = object ## struct stat
+      st_mode: Mode        ## Mode of file
+
+  proc S_ISDIR(m: Mode): bool {.importc, header: "<sys/stat.h>".}
+    ## Test for a directory.
+
+  proc fstat(a1: cint, a2: var Stat): cint {.importc, header: "<sys/stat.h>".}
 
 proc open(f: var File, filename: string,
           mode: FileMode = fmRead,
           bufSize: int = -1): bool =
   var p: pointer = fopen(filename, FormatOpen[mode])
   if p != nil:
+    when defined(posix) and not defined(nimscript):
+      # How `fopen` handles opening a directory is not specified in ISO C and
+      # POSIX. We do not want to handle directories as regular files that can
+      # be opened.
+      var f2 = cast[File](p)
+      var res: Stat
+      if fstat(getFileHandle(f2), res) >= 0'i32 and S_ISDIR(res.st_mode):
+        close(f2)
+        return false
     result = true
     f = cast[File](p)
     if bufSize > 0 and bufSize <= high(cint).int:
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index fbae46760..5e899dd1a 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -412,7 +412,7 @@ const
   FD_SETSIZE* = 64
   MSG_PEEK* = 2
 
-  INADDR_ANY* = 0
+  INADDR_ANY* = 0'u32
   INADDR_LOOPBACK* = 0x7F000001
   INADDR_BROADCAST* = -1
   INADDR_NONE* = -1
@@ -441,12 +441,12 @@ type
     sa_data: array[0..13, char]
 
   InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
-    s_addr*: int32  # IP address
+    s_addr*: uint32  # IP address
 
   Sockaddr_in* {.importc: "SOCKADDR_IN",
                   header: "winsock2.h".} = object
     sin_family*: int16
-    sin_port*: int16 # unsigned
+    sin_port*: uint16
     sin_addr*: InAddr
     sin_zero*: array[0..7, char]
 
@@ -456,7 +456,7 @@ type
   Sockaddr_in6* {.importc: "SOCKADDR_IN6",
                    header: "ws2tcpip.h".} = object
     sin6_family*: int16
-    sin6_port*: int16 # unsigned
+    sin6_port*: uint16
     sin6_flowinfo*: int32 # unsigned
     sin6_addr*: In6_addr
     sin6_scope_id*: int32 # unsigned
@@ -590,7 +590,7 @@ proc getnameinfo*(a1: ptr SockAddr, a2: SockLen,
                   a6: SockLen, a7: cint): cint {.
   stdcall, importc: "getnameinfo", dynlib: ws2dll.}
 
-proc inet_addr*(cp: cstring): int32 {.
+proc inet_addr*(cp: cstring): uint32 {.
   stdcall, importc: "inet_addr", dynlib: ws2dll.}
 
 proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {.
@@ -833,9 +833,9 @@ type inet_ntop_proc = proc(family: cint, paddr: pointer, pStringBuffer: cstring,
 
 var inet_ntop_real: inet_ntop_proc = nil
 
-let L = loadLib(ws2dll)
-if L != nil:
-  inet_ntop_real = cast[inet_ntop_proc](symAddr(L, "inet_ntop"))
+let ws2 = loadLib(ws2dll)
+if ws2 != nil:
+  inet_ntop_real = cast[inet_ntop_proc](symAddr(ws2, "inet_ntop"))
 
 proc WSAAddressToStringA(pAddr: ptr SockAddr, addrSize: DWORD, unused: pointer, pBuff: cstring, pBuffSize: ptr DWORD): cint {.stdcall, importc, dynlib: ws2dll.}
 proc inet_ntop_emulated(family: cint, paddr: pointer, pStringBuffer: cstring,