summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/system.nim328
-rw-r--r--lib/system/ansi_c.nim21
-rw-r--r--lib/system/dyncalls.nim32
-rw-r--r--lib/system/endb.nim153
-rw-r--r--lib/system/excpt.nim6
-rw-r--r--lib/system/gc.nim6
-rw-r--r--lib/system/gc_common.nim4
-rw-r--r--lib/system/gc_ms.nim3
-rw-r--r--lib/system/io.nim640
-rw-r--r--lib/system/mmdisp.nim2
-rw-r--r--lib/system/sysio.nim434
-rw-r--r--lib/system/threads.nim7
-rw-r--r--lib/system/widestrs.nim4
13 files changed, 816 insertions, 824 deletions
diff --git a/lib/system.nim b/lib/system.nim
index b9be52308..7febde127 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1630,7 +1630,9 @@ else:
 template sysAssert(cond: bool, msg: string) =
   when defined(useSysAssert):
     if not cond:
-      echo "[SYSASSERT] ", msg
+      cstderr.rawWrite "[SYSASSERT] "
+      cstderr.rawWrite msg
+      cstderr.rawWrite "\n"
       quit 1
 
 const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript)
@@ -3153,257 +3155,45 @@ when not defined(JS): #and not defined(nimscript):
         strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic})
       {.pop.}
 
-
-  # ----------------- IO Part ------------------------------------------------
-  type
-    CFile {.importc: "FILE", header: "<stdio.h>",
-            incompletestruct.} = object
-    File* = ptr CFile ## The type representing a file handle.
-
-    FileMode* = enum           ## The file mode when opening a file.
-      fmRead,                   ## Open the file for read access only.
-      fmWrite,                  ## Open the file for write access only.
-                                ## If the file does not exist, it will be
-                                ## created. Existing files will be cleared!
-      fmReadWrite,              ## Open the file for read and write access.
-                                ## If the file does not exist, it will be
-                                ## created. Existing files will be cleared!
-      fmReadWriteExisting,      ## Open the file for read and write access.
-                                ## If the file does not exist, it will not be
-                                ## created. The existing file will not be cleared.
-      fmAppend                  ## Open the file for writing only; append data
-                                ## at the end.
-
-    FileHandle* = cint ## type that represents an OS file handle; this is
-                       ## useful for low-level file access
-
-  include "system/ansi_c"
-  include "system/memory"
-
-  proc zeroMem(p: pointer, size: Natural) =
-    nimZeroMem(p, size)
-    when declared(memTrackerOp):
-      memTrackerOp("zeroMem", p, size)
-  proc copyMem(dest, source: pointer, size: Natural) =
-    nimCopyMem(dest, source, size)
-    when declared(memTrackerOp):
-      memTrackerOp("copyMem", dest, size)
-  proc moveMem(dest, source: pointer, size: Natural) =
-    c_memmove(dest, source, size)
-    when declared(memTrackerOp):
-      memTrackerOp("moveMem", dest, size)
-  proc equalMem(a, b: pointer, size: Natural): bool =
-    nimCmpMem(a, b, size) == 0
+  when not defined(nimscript):
+    include "system/ansi_c"
+    include "system/memory"
+
+    proc zeroMem(p: pointer, size: Natural) =
+      nimZeroMem(p, size)
+      when declared(memTrackerOp):
+        memTrackerOp("zeroMem", p, size)
+    proc copyMem(dest, source: pointer, size: Natural) =
+      nimCopyMem(dest, source, size)
+      when declared(memTrackerOp):
+        memTrackerOp("copyMem", dest, size)
+    proc moveMem(dest, source: pointer, size: Natural) =
+      c_memmove(dest, source, size)
+      when declared(memTrackerOp):
+        memTrackerOp("moveMem", dest, size)
+    proc equalMem(a, b: pointer, size: Natural): bool =
+      nimCmpMem(a, b, size) == 0
 
   proc cmp(x, y: string): int =
-    when nimvm:
+    when defined(nimscript):
       if x < y: result = -1
       elif x > y: result = 1
       else: result = 0
     else:
-      let minlen = min(x.len, y.len)
-      result = int(nimCmpMem(x.cstring, y.cstring, minlen.csize))
-      if result == 0:
-        result = x.len - y.len
-
-  when defined(nimscript):
-    proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
-      ## Opens a file named `filename` for reading, calls `readAll
-      ## <#readAll>`_ and closes the file afterwards. Returns the string.
-      ## Raises an IO exception in case of an error. If # you need to call
-      ## this inside a compile time macro you can use `staticRead
-      ## <#staticRead>`_.
-
-    proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
-      ## Opens a file named `filename` for writing. Then writes the
-      ## `content` completely to the file and closes the file afterwards.
-      ## Raises an IO exception in case of an error.
+      when nimvm:
+        if x < y: result = -1
+        elif x > y: result = 1
+        else: result = 0
+      else:
+        let minlen = min(x.len, y.len)
+        result = int(nimCmpMem(x.cstring, y.cstring, minlen.csize))
+        if result == 0:
+          result = x.len - y.len
 
   when not defined(nimscript) and hostOS != "standalone":
-
-    # text file handling:
-    var
-      stdin* {.importc: "stdin", header: "<stdio.h>".}: File
-        ## The standard input stream.
-      stdout* {.importc: "stdout", header: "<stdio.h>".}: File
-        ## The standard output stream.
-      stderr* {.importc: "stderr", header: "<stdio.h>".}: File
-        ## The standard error stream.
-
-    when defined(windows):
-      # work-around C's sucking abstraction:
-      # BUGFIX: stdin and stdout should be binary files!
-      proc c_setmode(handle, mode: cint) {.
-        importc: when defined(bcc): "setmode" else: "_setmode",
-        header: "<io.h>".}
-      var
-        O_BINARY {.importc: "_O_BINARY", header:"<fcntl.h>".}: cint
-
-      # we use binary mode on Windows:
-      c_setmode(c_fileno(stdin), O_BINARY)
-      c_setmode(c_fileno(stdout), O_BINARY)
-      c_setmode(c_fileno(stderr), O_BINARY)
-
     when defined(endb):
       proc endbStep()
 
-    when defined(useStdoutAsStdmsg):
-      template stdmsg*: File = stdout
-    else:
-      template stdmsg*: File = stderr
-        ## Template which expands to either stdout or stderr depending on
-        ## `useStdoutAsStdmsg` compile-time switch.
-
-    proc open*(f: var File, filename: string,
-               mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [],
-               raises: [], benign.}
-      ## Opens a file named `filename` with given `mode`.
-      ##
-      ## Default mode is readonly. Returns true iff the file could be opened.
-      ## This throws no exception if the file could not be opened.
-
-    proc open*(f: var File, filehandle: FileHandle,
-               mode: FileMode = fmRead): bool {.tags: [], raises: [],
-               benign.}
-      ## Creates a ``File`` from a `filehandle` with given `mode`.
-      ##
-      ## Default mode is readonly. Returns true iff the file could be opened.
-
-    proc open*(filename: string,
-               mode: FileMode = fmRead, bufSize: int = -1): File =
-      ## Opens a file named `filename` with given `mode`.
-      ##
-      ## Default mode is readonly. Raises an ``IOError`` if the file
-      ## could not be opened.
-      if not open(result, filename, mode, bufSize):
-        sysFatal(IOError, "cannot open: ", filename)
-
-    proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
-      tags: [], benign.}
-      ## reopens the file `f` with given `filename` and `mode`. This
-      ## is often used to redirect the `stdin`, `stdout` or `stderr`
-      ## file variables.
-      ##
-      ## Default mode is readonly. Returns true iff the file could be reopened.
-
-    proc setStdIoUnbuffered*() {.tags: [], benign.}
-      ## Configures `stdin`, `stdout` and `stderr` to be unbuffered.
-
-    proc close*(f: File) {.tags: [], gcsafe.}
-      ## Closes the file.
-
-    proc endOfFile*(f: File): bool {.tags: [], benign.}
-      ## Returns true iff `f` is at the end.
-
-    proc readChar*(f: File): char {.tags: [ReadIOEffect].}
-      ## Reads a single character from the stream `f`. Should not be used in
-      ## performance sensitive code.
-
-    proc flushFile*(f: File) {.tags: [WriteIOEffect].}
-      ## Flushes `f`'s buffer.
-
-    proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.}
-      ## Reads all data from the stream `file`.
-      ##
-      ## Raises an IO exception in case of an error. It is an error if the
-      ## current file position is not at the beginning of the file.
-
-    proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
-      ## Opens a file named `filename` for reading.
-      ##
-      ## Then calls `readAll <#readAll>`_ and closes the file afterwards.
-      ## Returns the string.  Raises an IO exception in case of an error. If
-      ## you need to call this inside a compile time macro you can use
-      ## `staticRead <#staticRead>`_.
-
-    proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
-      ## Opens a file named `filename` for writing. Then writes the
-      ## `content` completely to the file and closes the file afterwards.
-      ## Raises an IO exception in case of an error.
-
-    proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, c: char) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.}
-    proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], benign.}
-      ## Writes a value to the file `f`. May throw an IO exception.
-
-    proc readLine*(f: File): TaintedString  {.tags: [ReadIOEffect], benign.}
-      ## reads a line of text from the file `f`. May throw an IO exception.
-      ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
-      ## character(s) are not part of the returned string.
-
-    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
-                  benign.}
-      ## reads a line of text from the file `f` into `line`. May throw an IO
-      ## exception.
-      ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
-      ## character(s) are not part of the returned string. Returns ``false``
-      ## if the end of the file has been reached, ``true`` otherwise. If
-      ## ``false`` is returned `line` contains no new data.
-
-    proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
-                             tags: [WriteIOEffect], benign.}
-      ## writes the values `x` to `f` and then writes "\\n".
-      ## May throw an IO exception.
-
-    proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
-      ## retrieves the file size (in bytes) of `f`.
-
-    proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
-      tags: [ReadIOEffect], benign.}
-      ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-      ## the actual number of bytes that have been read which may be less than
-      ## `len` (if not as many bytes are remaining), but not greater.
-
-    proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
-      tags: [ReadIOEffect], benign.}
-      ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-      ## the actual number of bytes that have been read which may be less than
-      ## `len` (if not as many bytes are remaining), but not greater.
-      ##
-      ## **Warning:** The buffer `a` must be pre-allocated. This can be done
-      ## using, for example, ``newString``.
-
-    proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
-      tags: [ReadIOEffect], benign.}
-      ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
-      ## the actual number of bytes that have been read which may be less than
-      ## `len` (if not as many bytes are remaining), but not greater.
-
-    proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
-      tags: [WriteIOEffect], benign.}
-      ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-      ## the number of actual written bytes, which may be less than `len` in case
-      ## of an error.
-
-    proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
-      tags: [WriteIOEffect], benign.}
-      ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-      ## the number of actual written bytes, which may be less than `len` in case
-      ## of an error.
-
-    proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
-      tags: [WriteIOEffect], benign.}
-      ## writes the bytes of buffer pointed to by the parameter `buffer` to the
-      ## file `f`. Returns the number of actual written bytes, which may be less
-      ## than `len` in case of an error.
-
-    proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.}
-      ## sets the position of the file pointer that is used for read/write
-      ## operations. The file's first byte has the index zero.
-
-    proc getFilePos*(f: File): int64 {.benign.}
-      ## retrieves the current position of the file pointer that is used to
-      ## read from the file `f`. The file's first byte has the index zero.
-
-    proc getFileHandle*(f: File): FileHandle
-      ## returns the OS file handle of the file ``f``. This is only useful for
-      ## platform specific programming.
 
   when defined(gcDestructors) and not defined(nimscript):
     include "core/strs"
@@ -3553,47 +3343,8 @@ when not defined(JS): #and not defined(nimscript):
     {.pop.}
     when hasAlloc: include "system/strmantle"
 
-    when hostOS != "standalone": include "system/sysio"
     when hasThreadSupport:
       when hostOS != "standalone": include "system/channels"
-  else:
-    include "system/sysio"
-
-  when not defined(nimscript) and hostOS != "standalone":
-    iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
-      ## Iterates over any line in the file named `filename`.
-      ##
-      ## If the file does not exist `IOError` is raised. The trailing newline
-      ## character(s) are removed from the iterated lines. Example:
-      ##
-      ## .. code-block:: nim
-      ##   import strutils
-      ##
-      ##   proc transformLetters(filename: string) =
-      ##     var buffer = ""
-      ##     for line in filename.lines:
-      ##       buffer.add(line.replace("a", "0") & '\x0A')
-      ##     writeFile(filename, buffer)
-      var f = open(filename, bufSize=8000)
-      defer: close(f)
-      var res = TaintedString(newStringOfCap(80))
-      while f.readLine(res): yield res
-
-    iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
-      ## Iterate over any line in the file `f`.
-      ##
-      ## The trailing newline character(s) are removed from the iterated lines.
-      ## Example:
-      ##
-      ## .. code-block:: nim
-      ##   proc countZeros(filename: File): tuple[lines, zeros: int] =
-      ##     for line in filename.lines:
-      ##       for letter in line:
-      ##         if letter == '0':
-      ##           result.zeros += 1
-      ##       result.lines += 1
-      var res = TaintedString(newStringOfCap(80))
-      while f.readLine(res): yield res
 
   when not defined(nimscript) and hasAlloc:
     when not defined(gcDestructors):
@@ -3684,9 +3435,6 @@ elif defined(JS):
       if x < y: return -1
       return 1
 
-  when defined(nimffi):
-    include "system/sysio"
-
 when not defined(nimNoArrayToString):
   proc `$`*[T, IDX](x: array[IDX, T]): string =
     ## generic ``$`` operator for arrays that is lifted from the components
@@ -3702,7 +3450,11 @@ proc `$`*[T](x: openarray[T]): string =
 
 proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
   ## a shorthand for ``echo(errormsg); quit(errorcode)``.
-  echo(errormsg)
+  when defined(nimscript) or defined(js) or (hostOS == "standalone"):
+    echo errormsg
+  else:
+    cstderr.rawWrite(errormsg)
+    cstderr.rawWrite("\n")
   quit(errorcode)
 
 {.pop.} # checks
@@ -4430,7 +4182,7 @@ when defined(cpp) and appType != "lib" and
       echo trace & "Error: unhandled exception: " & ex.msg &
                    " [" & $ex.name & "]\n"
     else:
-      stderr.write trace & "Error: unhandled exception: " & ex.msg &
+      cstderr.rawWrite trace & "Error: unhandled exception: " & ex.msg &
                    " [" & $ex.name & "]\n"
     quit 1
 
@@ -4479,3 +4231,9 @@ proc `$`*(t: typedesc): string {.magic: "TypeTrait".} =
     doAssert $(type(42)) == "int"
     doAssert $(type("Foo")) == "string"
     static: doAssert $(type(@['A', 'B'])) == "seq[char]"
+
+import system/widestrs
+export widestrs
+
+import system/io
+export io
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index af34060d8..3afef0bfb 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -111,22 +111,27 @@ type c_sighandler_t = proc (a: cint) {.noconv.}
 proc c_signal(sign: cint, handler: proc (a: cint) {.noconv.}): c_sighandler_t {.
   importc: "signal", header: "<signal.h>", discardable.}
 
-proc c_fprintf(f: File, frmt: cstring): cint {.
+type
+  CFile {.importc: "FILE", header: "<stdio.h>",
+          incompletestruct.} = object
+  CFileStar* = ptr CFile ## The type representing a file handle.
+
+var
+  cstderr* {.importc: "stderr", header: "<stdio.h>".}: CFileStar
+  cstdout* {.importc: "stdout", header: "<stdio.h>".}: CFileStar
+
+proc c_fprintf(f: CFileStar, frmt: cstring): cint {.
   importc: "fprintf", header: "<stdio.h>", varargs, discardable.}
 proc c_printf(frmt: cstring): cint {.
   importc: "printf", header: "<stdio.h>", varargs, discardable.}
 
+proc c_fputs(c: cstring, f: CFileStar): cint {.
+  importc: "fputs", header: "<stdio.h>", discardable.}
+
 proc c_sprintf(buf, frmt: cstring): cint {.
   importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
   # we use it only in a way that cannot lead to security issues
 
-when defined(windows):
-  proc c_fileno(f: File): cint {.
-      importc: "_fileno", header: "<stdio.h>".}
-else:
-  proc c_fileno(f: File): cint {.
-      importc: "fileno", header: "<fcntl.h>".}
-
 proc c_malloc(size: csize): pointer {.
   importc: "malloc", header: "<stdlib.h>".}
 proc c_free(p: pointer) {.
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index 70bdc429b..528587d05 100644
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -19,11 +19,11 @@ const
 
 proc nimLoadLibraryError(path: string) =
   # carefully written to avoid memory allocation:
-  stderr.rawWrite("could not load: ")
-  stderr.rawWrite(path)
-  stderr.rawWrite("\n")
+  cstderr.rawWrite("could not load: ")
+  cstderr.rawWrite(path)
+  cstderr.rawWrite("\n")
   when not defined(nimDebugDlOpen) and not defined(windows):
-    stderr.rawWrite("compile with -d:nimDebugDlOpen for more information\n")
+    cstderr.rawWrite("compile with -d:nimDebugDlOpen for more information\n")
   when defined(windows) and defined(guiapp):
     # Because console output is not shown in GUI apps, display error as message box:
     const prefix = "could not load: "
@@ -35,9 +35,9 @@ proc nimLoadLibraryError(path: string) =
 
 proc procAddrError(name: cstring) {.noinline.} =
   # carefully written to avoid memory allocation:
-  stderr.rawWrite("could not import: ")
-  stderr.rawWrite(name)
-  stderr.rawWrite("\n")
+  cstderr.rawWrite("could not import: ")
+  cstderr.rawWrite(name)
+  cstderr.rawWrite("\n")
   quit(1)
 
 # this code was inspired from Lua's source code:
@@ -79,8 +79,8 @@ when defined(posix):
     when defined(nimDebugDlOpen):
       let error = dlerror()
       if error != nil:
-        stderr.rawWrite(error)
-        stderr.rawWrite("\n")
+        cstderr.rawWrite(error)
+        cstderr.rawWrite("\n")
 
   proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
     result = dlsym(lib, name)
@@ -162,20 +162,20 @@ elif defined(genode):
 
 elif defined(nintendoswitch):
   proc nimUnloadLibrary(lib: LibHandle) =
-    stderr.rawWrite("nimUnLoadLibrary not implemented")
-    stderr.rawWrite("\n")
+    cstderr.rawWrite("nimUnLoadLibrary not implemented")
+    cstderr.rawWrite("\n")
     quit(1)
 
   proc nimLoadLibrary(path: string): LibHandle =
-    stderr.rawWrite("nimLoadLibrary not implemented")
-    stderr.rawWrite("\n")
+    cstderr.rawWrite("nimLoadLibrary not implemented")
+    cstderr.rawWrite("\n")
     quit(1)
 
 
   proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
-    stderr.rawWrite("nimGetProAddr not implemented")
-    stderr.rawWrite(name)
-    stderr.rawWrite("\n")
+    cstderr.rawWrite("nimGetProAddr not implemented")
+    cstderr.rawWrite(name)
+    cstderr.rawWrite("\n")
     quit(1)
 
 else:
diff --git a/lib/system/endb.nim b/lib/system/endb.nim
index 257ee3fea..b1f91295c 100644
--- a/lib/system/endb.nim
+++ b/lib/system/endb.nim
@@ -76,29 +76,52 @@ proc `==`(a, b: StaticStr): bool =
 proc `==`(a: StaticStr, b: cstring): bool =
   result = c_strcmp(unsafeAddr a.data, b) == 0
 
-proc write(f: File, s: StaticStr) =
+proc write(f: CFileStar, s: cstring) = c_fputs(s, f)
+proc writeLine(f: CFileStar, s: cstring) =
+  c_fputs(s, f)
+  c_fputs("\n", f)
+
+proc write(f: CFileStar, s: StaticStr) =
   write(f, cstring(unsafeAddr s.data))
 
+proc write(f: CFileStar, i: int) =
+  when sizeof(int) == 8:
+    discard c_fprintf(f, "%lld", i)
+  else:
+    discard c_fprintf(f, "%ld", i)
+
+proc close(f: CFileStar): cint {.
+  importc: "fclose", header: "<stdio.h>", discardable.}
+
+proc c_fgetc(stream: CFileStar): cint {.
+  importc: "fgetc", header: "<stdio.h>".}
+proc c_ungetc(c: cint, f: CFileStar): cint {.
+  importc: "ungetc", header: "<stdio.h>", discardable.}
+
+var
+  cstdin* {.importc: "stdin", header: "<stdio.h>".}: CFileStar
+
 proc listBreakPoints() =
-  write(stdout, EndbBeg)
-  write(stdout, "| Breakpoints:\n")
+  write(cstdout, EndbBeg)
+  write(cstdout, "| Breakpoints:\n")
   for b in listBreakpoints():
-    write(stdout, abs(b.low))
+    write(cstdout, abs(b.low))
     if b.high != b.low:
-      write(stdout, "..")
-      write(stdout, abs(b.high))
-    write(stdout, " ")
-    write(stdout, b.filename)
+      write(cstdout, "..")
+      write(cstdout, abs(b.high))
+    write(cstdout, " ")
+    write(cstdout, b.filename)
     if b.isActive:
-      write(stdout, " [disabled]\n")
+      write(cstdout, " [disabled]\n")
     else:
-      write(stdout, "\n")
-  write(stdout, EndbEnd)
+      write(cstdout, "\n")
+  write(cstdout, EndbEnd)
+
+proc openAppend(filename: cstring): CFileStar =
+  proc fopen(filename, mode: cstring): CFileStar {.importc: "fopen", header: "<stdio.h>".}
 
-proc openAppend(filename: cstring): File =
-  var p: pointer = fopen(filename, "ab")
-  if p != nil:
-    result = cast[File](p)
+  result = fopen(filename, "ab")
+  if result != nil:
     write(result, "----------------------------------------\n")
 
 proc dbgRepr(p: pointer, typ: PNimType): string =
@@ -112,12 +135,12 @@ proc dbgRepr(p: pointer, typ: PNimType): string =
   # dec(recGcLock)
   deinitReprClosure(cl)
 
-proc writeVariable(stream: File, slot: VarSlot) =
+proc writeVariable(stream: CFileStar, slot: VarSlot) =
   write(stream, slot.name)
   write(stream, " = ")
   writeLine(stream, dbgRepr(slot.address, slot.typ))
 
-proc listFrame(stream: File, f: PFrame) =
+proc listFrame(stream: CFileStar, f: PFrame) =
   write(stream, EndbBeg)
   write(stream, "| Frame (")
   write(stream, f.len)
@@ -126,7 +149,7 @@ proc listFrame(stream: File, f: PFrame) =
     writeLine(stream, getLocal(f, i).name)
   write(stream, EndbEnd)
 
-proc listLocals(stream: File, f: PFrame) =
+proc listLocals(stream: CFileStar, f: PFrame) =
   write(stream, EndbBeg)
   write(stream, "| Frame (")
   write(stream, f.len)
@@ -135,7 +158,7 @@ proc listLocals(stream: File, f: PFrame) =
     writeVariable(stream, getLocal(f, i))
   write(stream, EndbEnd)
 
-proc listGlobals(stream: File) =
+proc listGlobals(stream: CFileStar) =
   write(stream, EndbBeg)
   write(stream, "| Globals:\n")
   for i in 0 .. getGlobalLen()-1:
@@ -145,10 +168,10 @@ proc listGlobals(stream: File) =
 proc debugOut(msg: cstring) =
   # the *** *** markers are for easy recognition of debugger
   # output for external frontends.
-  write(stdout, EndbBeg)
-  write(stdout, "| ")
-  write(stdout, msg)
-  write(stdout, EndbEnd)
+  write(cstdout, EndbBeg)
+  write(cstdout, "| ")
+  write(cstdout, msg)
+  write(cstdout, EndbEnd)
 
 proc dbgFatal(msg: cstring) =
   debugOut(msg)
@@ -157,20 +180,20 @@ proc dbgFatal(msg: cstring) =
 
 proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
   if dbgFramePointer != nil:
-    write(stdout, "*** endb| now in proc: ")
-    write(stdout, dbgFramePointer.procname)
-    write(stdout, " ***\n")
+    write(cstdout, "*** endb| now in proc: ")
+    write(cstdout, dbgFramePointer.procname)
+    write(cstdout, " ***\n")
   else:
-    write(stdout, "*** endb| (proc name not available) ***\n")
+    write(cstdout, "*** endb| (proc name not available) ***\n")
 
 proc dbgShowExecutionPoint() =
-  write(stdout, "*** endb| ")
-  write(stdout, framePtr.filename)
-  write(stdout, "(")
-  write(stdout, framePtr.line)
-  write(stdout, ") ")
-  write(stdout, framePtr.procname)
-  write(stdout, " ***\n")
+  write(cstdout, "*** endb| ")
+  write(cstdout, framePtr.filename)
+  write(cstdout, "(")
+  write(cstdout, framePtr.line)
+  write(cstdout, ") ")
+  write(cstdout, framePtr.procname)
+  write(cstdout, " ***\n")
 
 proc scanAndAppendWord(src: cstring, a: var StaticStr, start: int): int =
   result = start
@@ -279,7 +302,7 @@ proc breakpointToggle(s: cstring, start: int) =
     if not b.isNil: b.flip
     else: debugOut("[Warning] unknown breakpoint ")
 
-proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
+proc dbgEvaluate(stream: CFileStar, s: cstring, start: int, f: PFrame) =
   var dbgTemp: StaticStr
   var i = scanWord(s, dbgTemp, start)
   while s[i] in {' ', '\t'}: inc(i)
@@ -315,8 +338,8 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
   var dbgTemp: StaticStr
   var i = scanFilename(s, dbgTemp, start)
   if dbgTemp.len == 0:
-    # just write it to stdout:
-    listFrame(stdout, currFrame)
+    # just write it to cstdout:
+    listFrame(cstdout, currFrame)
   else:
     var stream = openAppend(addr dbgTemp.data)
     if stream == nil:
@@ -325,7 +348,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
     listFrame(stream, currFrame)
     close(stream)
 
-proc readLine(f: File, line: var StaticStr): bool =
+proc readLine(f: CFileStar, line: var StaticStr): bool =
   while true:
     var c = c_fgetc(f)
     if c < 0'i32:
@@ -340,16 +363,16 @@ proc readLine(f: File, line: var StaticStr): bool =
   result = true
 
 proc listFilenames() =
-  write(stdout, EndbBeg)
-  write(stdout, "| Files:\n")
+  write(cstdout, EndbBeg)
+  write(cstdout, "| Files:\n")
   var i = 0
   while true:
     let x = dbgFilenames[i]
     if x.isNil: break
-    write(stdout, x)
-    write(stdout, "\n")
+    write(cstdout, x)
+    write(cstdout, "\n")
     inc i
-  write(stdout, EndbEnd)
+  write(cstdout, EndbEnd)
 
 proc dbgWriteStackTrace(f: PFrame)
 proc commandPrompt() =
@@ -361,10 +384,10 @@ proc commandPrompt() =
     dbgTemp: StaticStr
 
   while again:
-    write(stdout, "*** endb| >>")
+    write(cstdout, "*** endb| >>")
     let oldLen = dbgUser.len
     dbgUser.len = 0
-    if not readLine(stdin, dbgUser): break
+    if not readLine(cstdin, dbgUser): break
     if dbgUser.len == 0: dbgUser.len = oldLen
     # now look what we have to do:
     var i = scanWord(addr dbgUser.data, dbgTemp, 0)
@@ -398,7 +421,7 @@ proc commandPrompt() =
         prevState = dbgState
         prevSkipFrame = dbgSkipToFrame
       dbgState = dbSkipCurrent
-      dbgEvaluate(stdout, addr dbgUser.data, i, dbgFramePtr)
+      dbgEvaluate(cstdout, addr dbgUser.data, i, dbgFramePtr)
       dbgState = prevState
       dbgSkipToFrame = prevSkipFrame
     elif ?"o" or ?"out":
@@ -412,7 +435,7 @@ proc commandPrompt() =
         prevState = dbgState
         prevSkipFrame = dbgSkipToFrame
       dbgState = dbSkipCurrent
-      listLocals(stdout, dbgFramePtr)
+      listLocals(cstdout, dbgFramePtr)
       dbgState = prevState
       dbgSkipToFrame = prevSkipFrame
     elif ?"g" or ?"globals":
@@ -420,7 +443,7 @@ proc commandPrompt() =
         prevState = dbgState
         prevSkipFrame = dbgSkipToFrame
       dbgState = dbSkipCurrent
-      listGlobals(stdout)
+      listGlobals(cstdout)
       dbgState = prevState
       dbgSkipToFrame = prevSkipFrame
     elif ?"u" or ?"up":
@@ -501,29 +524,29 @@ proc dbgWriteStackTrace(f: PFrame) =
     b = b.prev
   for j in countdown(i-1, 0):
     if tempFrames[j] == nil:
-      write(stdout, "(")
-      write(stdout, skipped)
-      write(stdout, " calls omitted) ...")
+      write(cstdout, "(")
+      write(cstdout, skipped)
+      write(cstdout, " calls omitted) ...")
     else:
-      write(stdout, tempFrames[j].filename)
+      write(cstdout, tempFrames[j].filename)
       if tempFrames[j].line > 0:
-        write(stdout, '(')
-        write(stdout, tempFrames[j].line)
-        write(stdout, ')')
-      write(stdout, ' ')
-      write(stdout, tempFrames[j].procname)
-    write(stdout, "\n")
+        write(cstdout, "(")
+        write(cstdout, tempFrames[j].line)
+        write(cstdout, ")")
+      write(cstdout, " ")
+      write(cstdout, tempFrames[j].procname)
+    write(cstdout, "\n")
 
 proc checkForBreakpoint =
   let b = checkBreakpoints(framePtr.filename, framePtr.line)
   if b != nil:
-    write(stdout, "*** endb| reached ")
-    write(stdout, framePtr.filename)
-    write(stdout, "(")
-    write(stdout, framePtr.line)
-    write(stdout, ") ")
-    write(stdout, framePtr.procname)
-    write(stdout, " ***\n")
+    write(cstdout, "*** endb| reached ")
+    write(cstdout, framePtr.filename)
+    write(cstdout, "(")
+    write(cstdout, framePtr.line)
+    write(cstdout, ") ")
+    write(cstdout, framePtr.procname)
+    write(cstdout, " ***\n")
     commandPrompt()
 
 proc lineHookImpl() {.nimcall.} =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index f2f82c3b8..0025d9088 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -17,15 +17,15 @@ var
     ## instead of stdmsg.write when printing stacktrace.
     ## Unstable API.
 
-proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
+proc c_fwrite(buf: pointer, size, n: csize, f: CFileStar): cint {.
   importc: "fwrite", header: "<stdio.h>".}
 
-proc rawWrite(f: File, s: string|cstring) =
+proc rawWrite(f: CFileStar, s: string|cstring) =
   # we cannot throw an exception here!
   discard c_fwrite(cstring(s), 1, s.len, f)
 
 when not defined(windows) or not defined(guiapp):
-  proc writeToStdErr(msg: cstring) = rawWrite(stdmsg, msg)
+  proc writeToStdErr(msg: cstring) = rawWrite(cstderr, msg)
 
 else:
   proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 018197c1e..d6d7da66e 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -104,9 +104,11 @@ when not defined(useNimRtl):
 template gcAssert(cond: bool, msg: string) =
   when defined(useGcAssert):
     if not cond:
-      echo "[GCASSERT] ", msg
+      cstderr.rawWrite "[GCASSERT] "
+      cstderr.rawWrite msg
       when defined(logGC):
-        echo "[GCASSERT] statistics:\L", GC_getStatistics()
+        cstderr.rawWrite "[GCASSERT] statistics:\L"
+        cstderr.rawWrite GC_getStatistics()
       GC_disable()
       writeStackTrace()
       #var x: ptr int
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index ebd3dada2..5af64ae20 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -457,7 +457,7 @@ proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
     globalMarkers[globalMarkersLen] = markerProc
     inc globalMarkersLen
   else:
-    echo "[GC] cannot register global variable; too many global variables"
+    cstderr.rawWrite("[GC] cannot register global variable; too many global variables")
     quit 1
 
 proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
@@ -465,5 +465,5 @@ proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerProc.}
     threadLocalMarkers[threadLocalMarkersLen] = markerProc
     inc threadLocalMarkersLen
   else:
-    echo "[GC] cannot register thread local variable; too many thread local variables"
+    cstderr.rawWrite("[GC] cannot register thread local variable; too many thread local variables")
     quit 1
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index aa5fb6aea..bd08eedf0 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -88,7 +88,8 @@ when not defined(useNimRtl):
 template gcAssert(cond: bool, msg: string) =
   when defined(useGcAssert):
     if not cond:
-      echo "[GCASSERT] ", msg
+      cstderr.rawWrite "[GCASSERT] "
+      cstderr.rawWrite msg
       quit 1
 
 proc cellToUsr(cell: PCell): pointer {.inline.} =
diff --git a/lib/system/io.nim b/lib/system/io.nim
new file mode 100644
index 000000000..408631db5
--- /dev/null
+++ b/lib/system/io.nim
@@ -0,0 +1,640 @@
+
+include inclrtl
+
+# ----------------- IO Part ------------------------------------------------
+type
+  CFile {.importc: "FILE", header: "<stdio.h>",
+          incompletestruct.} = object
+  File* = ptr CFile ## The type representing a file handle.
+
+  FileMode* = enum           ## The file mode when opening a file.
+    fmRead,                   ## Open the file for read access only.
+    fmWrite,                  ## Open the file for write access only.
+                              ## If the file does not exist, it will be
+                              ## created. Existing files will be cleared!
+    fmReadWrite,              ## Open the file for read and write access.
+                              ## If the file does not exist, it will be
+                              ## created. Existing files will be cleared!
+    fmReadWriteExisting,      ## Open the file for read and write access.
+                              ## If the file does not exist, it will not be
+                              ## created. The existing file will not be cleared.
+    fmAppend                  ## Open the file for writing only; append data
+                              ## at the end.
+
+  FileHandle* = cint ## type that represents an OS file handle; this is
+                      ## useful for low-level file access
+
+# text file handling:
+when not defined(nimscript) and not defined(js):
+  var
+    stdin* {.importc: "stdin", header: "<stdio.h>".}: File
+      ## The standard input stream.
+    stdout* {.importc: "stdout", header: "<stdio.h>".}: File
+      ## The standard output stream.
+    stderr* {.importc: "stderr", header: "<stdio.h>".}: File
+      ## The standard error stream.
+
+when defined(useStdoutAsStdmsg):
+  template stdmsg*: File = stdout
+else:
+  template stdmsg*: File = stderr
+    ## Template which expands to either stdout or stderr depending on
+    ## `useStdoutAsStdmsg` compile-time switch.
+
+when defined(windows):
+  proc c_fileno(f: File): cint {.
+    importc: "_fileno", header: "<stdio.h>".}
+else:
+  proc c_fileno(f: File): cint {.
+    importc: "fileno", header: "<fcntl.h>".}
+
+when defined(windows):
+  proc c_fdopen(filehandle: cint, mode: cstring): File {.
+    importc: "_fdopen", header: "<stdio.h>".}
+else:
+  proc c_fdopen(filehandle: cint, mode: cstring): File {.
+    importc: "fdopen", header: "<stdio.h>".}
+proc c_fputs(c: cstring, f: File): cint {.
+  importc: "fputs", header: "<stdio.h>", tags: [WriteIOEffect].}
+proc c_fgets(c: cstring, n: cint, f: File): cstring {.
+  importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
+proc c_fgetc(stream: File): cint {.
+  importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
+proc c_ungetc(c: cint, f: File): cint {.
+  importc: "ungetc", header: "<stdio.h>", tags: [].}
+proc c_putc(c: cint, stream: File): cint {.
+  importc: "putc", header: "<stdio.h>", tags: [WriteIOEffect].}
+proc c_fflush(f: File): cint {.
+  importc: "fflush", header: "<stdio.h>".}
+proc c_fclose(f: File): cint {.
+  importc: "fclose", header: "<stdio.h>".}
+proc c_clearerr(f: File) {.
+  importc: "clearerr", header: "<stdio.h>".}
+proc c_feof(f: File): cint {.
+  importc: "feof", header: "<stdio.h>".}
+
+when not declared(c_fwrite):
+  proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
+    importc: "fwrite", header: "<stdio.h>".}
+
+# C routine that is used here:
+proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
+  importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
+when defined(windows):
+  when not defined(amd64):
+    proc c_fseek(f: File, offset: int64, whence: cint): cint {.
+      importc: "fseek", header: "<stdio.h>", tags: [].}
+    proc c_ftell(f: File): int64 {.
+      importc: "ftell", header: "<stdio.h>", tags: [].}
+  else:
+    proc c_fseek(f: File, offset: int64, whence: cint): cint {.
+      importc: "_fseeki64", header: "<stdio.h>", tags: [].}
+    proc c_ftell(f: File): int64 {.
+      importc: "_ftelli64", header: "<stdio.h>", tags: [].}
+else:
+  proc c_fseek(f: File, offset: int64, whence: cint): cint {.
+    importc: "fseeko", header: "<stdio.h>", tags: [].}
+  proc c_ftell(f: File): int64 {.
+    importc: "ftello", header: "<stdio.h>", tags: [].}
+proc c_ferror(f: File): cint {.
+  importc: "ferror", header: "<stdio.h>", tags: [].}
+proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
+  importc: "setvbuf", header: "<stdio.h>", tags: [].}
+
+proc c_fprintf(f: File, frmt: cstring): cint {.
+  importc: "fprintf", header: "<stdio.h>", varargs, discardable.}
+
+template sysFatal(exc, msg) =
+  raise newException(exc, msg)
+
+proc raiseEIO(msg: string) {.noinline, noreturn.} =
+  sysFatal(IOError, msg)
+
+proc raiseEOF() {.noinline, noreturn.} =
+  sysFatal(EOFError, "EOF reached")
+
+proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
+
+when not defined(NimScript):
+  var
+    errno {.importc, header: "<errno.h>".}: cint ## error variable
+
+proc checkErr(f: File) =
+  when not defined(NimScript):
+    if c_ferror(f) != 0:
+      let msg = "errno: " & $errno & " `" & $strerror(errno) & "`"
+      c_clearerr(f)
+      raiseEIO(msg)
+  else:
+    # shouldn't happen
+    quit(1)
+
+{.push stackTrace:off, profiler:off.}
+proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
+  tags: [ReadIOEffect], benign.} =
+  ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
+  ## the actual number of bytes that have been read which may be less than
+  ## `len` (if not as many bytes are remaining), but not greater.
+  result = c_fread(buffer, 1, len, f)
+  if result != len: checkErr(f)
+
+proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
+  tags: [ReadIOEffect], benign.} =
+  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+  ## the actual number of bytes that have been read which may be less than
+  ## `len` (if not as many bytes are remaining), but not greater.
+  result = readBuffer(f, addr(a[start]), len)
+
+proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
+  tags: [ReadIOEffect], benign.} =
+  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+  ## the actual number of bytes that have been read which may be less than
+  ## `len` (if not as many bytes are remaining), but not greater.
+  ##
+  ## **Warning:** The buffer `a` must be pre-allocated. This can be done
+  ## using, for example, ``newString``.
+  if (start + len) > len(a):
+    raiseEIO("buffer overflow: (start+len) > length of openarray buffer")
+  result = readBuffer(f, addr(a[start]), len)
+
+proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.} =
+  ## Writes a value to the file `f`. May throw an IO exception.
+  discard c_fputs(c, f)
+  checkErr(f)
+
+proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
+  tags: [WriteIOEffect], benign.} =
+  ## writes the bytes of buffer pointed to by the parameter `buffer` to the
+  ## file `f`. Returns the number of actual written bytes, which may be less
+  ## than `len` in case of an error.
+  result = c_fwrite(buffer, 1, len, f)
+  checkErr(f)
+
+proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
+  tags: [WriteIOEffect], benign.} =
+  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+  ## the number of actual written bytes, which may be less than `len` in case
+  ## of an error.
+  var x = cast[ptr UncheckedArray[int8]](a)
+  result = writeBuffer(f, addr(x[int(start)]), len)
+
+proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
+  tags: [WriteIOEffect], benign.} =
+  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+  ## the number of actual written bytes, which may be less than `len` in case
+  ## of an error.
+  var x = cast[ptr UncheckedArray[int8]](a)
+  result = writeBuffer(f, addr(x[int(start)]), len)
+
+proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.} =
+  if writeBuffer(f, cstring(s), s.len) != s.len:
+    raiseEIO("cannot write string to file")
+{.pop.}
+
+when NoFakeVars:
+  when defined(windows):
+    const
+      IOFBF = cint(0)
+      IONBF = cint(4)
+  else:
+    # On all systems I could find, including Linux, Mac OS X, and the BSDs
+    const
+      IOFBF = cint(0)
+      IONBF = cint(2)
+else:
+  var
+    IOFBF {.importc: "_IOFBF", nodecl.}: cint
+    IONBF {.importc: "_IONBF", nodecl.}: cint
+
+const
+  BufSize = 4000
+
+proc close*(f: File) {.tags: [], gcsafe.} =
+  ## Closes the file.
+  if not f.isNil:
+    discard c_fclose(f)
+
+proc readChar*(f: File): char {.tags: [ReadIOEffect].} =
+  ## Reads a single character from the stream `f`. Should not be used in
+  ## performance sensitive code.
+  let x = c_fgetc(f)
+  if x < 0:
+    checkErr(f)
+    raiseEOF()
+  result = char(x)
+
+proc flushFile*(f: File) {.tags: [WriteIOEffect].} =
+  ## Flushes `f`'s buffer.
+  discard c_fflush(f)
+
+proc getFileHandle*(f: File): FileHandle =
+  ## returns the OS file handle of the file ``f``. This is only useful for
+  ## platform specific programming.
+  c_fileno(f)
+
+proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
+              benign.} =
+  ## reads a line of text from the file `f` into `line`. May throw an IO
+  ## exception.
+  ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
+  ## character(s) are not part of the returned string. Returns ``false``
+  ## if the end of the file has been reached, ``true`` otherwise. If
+  ## ``false`` is returned `line` contains no new data.
+  proc c_memchr(s: pointer, c: cint, n: csize): pointer {.
+    importc: "memchr", header: "<string.h>".}
+
+  var pos = 0
+
+  # Use the currently reserved space for a first try
+  var sp = max(line.string.len, 80)
+  line.string.setLen(sp)
+
+  while true:
+    # memset to \L so that we can tell how far fgets wrote, even on EOF, where
+    # fgets doesn't append an \L
+    for i in 0..<sp: line.string[pos+i] = '\L'
+
+    var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil
+    if not fgetsSuccess: checkErr(f)
+    let m = c_memchr(addr line.string[pos], '\L'.ord, sp)
+    if m != nil:
+      # \l found: Could be our own or the one by fgets, in any case, we're done
+      var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0])
+      if last > 0 and line.string[last-1] == '\c':
+        line.string.setLen(last-1)
+        return last > 1 or fgetsSuccess
+        # We have to distinguish between two possible cases:
+        # \0\l\0 => line ending in a null character.
+        # \0\l\l => last line without newline, null was put there by fgets.
+      elif last > 0 and line.string[last-1] == '\0':
+        if last < pos + sp - 1 and line.string[last+1] != '\0':
+          dec last
+      line.string.setLen(last)
+      return last > 0 or fgetsSuccess
+    else:
+      # fgets will have inserted a null byte at the end of the string.
+      dec sp
+    # No \l found: Increase buffer and read more
+    inc pos, sp
+    sp = 128 # read in 128 bytes at a time
+    line.string.setLen(pos+sp)
+
+proc readLine*(f: File): TaintedString  {.tags: [ReadIOEffect], benign.} =
+  ## reads a line of text from the file `f`. May throw an IO exception.
+  ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
+  ## character(s) are not part of the returned string.
+  result = TaintedString(newStringOfCap(80))
+  if not readLine(f, result): raiseEOF()
+
+proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} =
+  when sizeof(int) == 8:
+    if c_fprintf(f, "%lld", i) < 0: checkErr(f)
+  else:
+    if c_fprintf(f, "%ld", i) < 0: checkErr(f)
+
+proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], benign.} =
+  when sizeof(BiggestInt) == 8:
+    if c_fprintf(f, "%lld", i) < 0: checkErr(f)
+  else:
+    if c_fprintf(f, "%ld", i) < 0: checkErr(f)
+
+proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} =
+  if b: write(f, "true")
+  else: write(f, "false")
+proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} =
+  if c_fprintf(f, "%.16g", r) < 0: checkErr(f)
+proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} =
+  if c_fprintf(f, "%.16g", r) < 0: checkErr(f)
+
+proc write*(f: File, c: char) {.tags: [WriteIOEffect], benign.} =
+  discard c_putc(cint(c), f)
+
+proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], benign.} =
+  for x in items(a): write(f, x)
+
+proc readAllBuffer(file: File): string =
+  # This proc is for File we want to read but don't know how many
+  # bytes we need to read before the buffer is empty.
+  result = ""
+  var buffer = newString(BufSize)
+  while true:
+    var bytesRead = readBuffer(file, addr(buffer[0]), BufSize)
+    if bytesRead == BufSize:
+      result.add(buffer)
+    else:
+      buffer.setLen(bytesRead)
+      result.add(buffer)
+      break
+
+proc rawFileSize(file: File): int64 =
+  # this does not raise an error opposed to `getFileSize`
+  var oldPos = c_ftell(file)
+  discard c_fseek(file, 0, 2) # seek the end of the file
+  result = c_ftell(file)
+  discard c_fseek(file, oldPos, 0)
+
+proc endOfFile*(f: File): bool {.tags: [], benign.} =
+  ## Returns true iff `f` is at the end.
+  var c = c_fgetc(f)
+  discard c_ungetc(c, f)
+  return c < 0'i32
+  #result = c_feof(f) != 0
+
+proc readAllFile(file: File, len: int64): string =
+  # We acquire the filesize beforehand and hope it doesn't change.
+  # Speeds things up.
+  result = newString(len)
+  let bytes = readBuffer(file, addr(result[0]), len)
+  if endOfFile(file):
+    if bytes < len:
+      result.setLen(bytes)
+  else:
+    # We read all the bytes but did not reach the EOF
+    # Try to read it as a buffer
+    result.add(readAllBuffer(file))
+
+proc readAllFile(file: File): string =
+  var len = rawFileSize(file)
+  result = readAllFile(file, len)
+
+proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} =
+  ## Reads all data from the stream `file`.
+  ##
+  ## Raises an IO exception in case of an error. It is an error if the
+  ## current file position is not at the beginning of the file.
+
+  # Separate handling needed because we need to buffer when we
+  # don't know the overall length of the File.
+  when declared(stdin):
+    let len = if file != stdin: rawFileSize(file) else: -1
+  else:
+    let len = rawFileSize(file)
+  if len > 0:
+    result = readAllFile(file, len).TaintedString
+  else:
+    result = readAllBuffer(file).TaintedString
+
+proc writeLn[Ty](f: File, x: varargs[Ty, `$`]) =
+  for i in items(x):
+    write(f, i)
+  write(f, "\n")
+
+proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
+                          tags: [WriteIOEffect], benign.} =
+  ## writes the values `x` to `f` and then writes "\\n".
+  ## May throw an IO exception.
+  for i in items(x):
+    write(f, i)
+  write(f, "\n")
+
+# interface to the C procs:
+
+when defined(windows) and not defined(useWinAnsi):
+  when defined(cpp):
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.}
+  else:
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importc: "_wfopen", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importc: "_wfreopen", nodecl.}
+
+  proc fopen(filename, mode: cstring): pointer =
+    var f = newWideCString(filename)
+    var m = newWideCString(mode)
+    result = wfopen(f, m)
+
+  proc freopen(filename, mode: cstring, stream: File): File =
+    var f = newWideCString(filename)
+    var m = newWideCString(mode)
+    result = wfreopen(f, m, stream)
+
+else:
+  proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.}
+  proc freopen(filename, mode: cstring, stream: File): File {.
+    importc: "freopen", nodecl.}
+
+const
+  FormatOpen: array[FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"]
+    #"rt", "wt", "w+t", "r+t", "at"
+    # we always use binary here as for Nim the OS line ending
+    # should not be translated.
+
+when defined(posix) and not defined(nimscript):
+  when defined(linux) and defined(amd64):
+    type
+      Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
+
+      # fillers ensure correct size & offsets
+      Stat {.importc: "struct stat",
+              header: "<sys/stat.h>", final, pure.} = object ## struct stat
+        filler_1: array[24, char]
+        st_mode: Mode        ## Mode of file
+        filler_2: array[144 - 24 - 4, char]
+
+    proc S_ISDIR(m: Mode): bool =
+      ## Test for a directory.
+      (m and 0o170000) == 0o40000
+
+  else:
+    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 c_fstat(a1: cint, a2: var Stat): cint {.
+    importc: "fstat", header: "<sys/stat.h>".}
+
+
+proc open*(f: var File, filename: string,
+          mode: FileMode = fmRead,
+          bufSize: int = -1): bool  {.tags: [], raises: [], benign.} =
+  ## Opens a file named `filename` with given `mode`.
+  ##
+  ## Default mode is readonly. Returns true iff the file could be opened.
+  ## This throws no exception if the file could not be opened.
+  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 c_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:
+      discard c_setvbuf(f, nil, IOFBF, bufSize.cint)
+    elif bufSize == 0:
+      discard c_setvbuf(f, nil, IONBF, 0)
+
+proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
+  tags: [], benign.} =
+  ## reopens the file `f` with given `filename` and `mode`. This
+  ## is often used to redirect the `stdin`, `stdout` or `stderr`
+  ## file variables.
+  ##
+  ## Default mode is readonly. Returns true iff the file could be reopened.
+  var p: pointer = freopen(filename, FormatOpen[mode], f)
+  result = p != nil
+
+proc open*(f: var File, filehandle: FileHandle,
+           mode: FileMode = fmRead): bool {.tags: [], raises: [], benign.} =
+  ## Creates a ``File`` from a `filehandle` with given `mode`.
+  ##
+  ## Default mode is readonly. Returns true iff the file could be opened.
+
+  f = c_fdopen(filehandle, FormatOpen[mode])
+  result = f != nil
+
+proc open*(filename: string,
+            mode: FileMode = fmRead, bufSize: int = -1): File =
+  ## Opens a file named `filename` with given `mode`.
+  ##
+  ## Default mode is readonly. Raises an ``IOError`` if the file
+  ## could not be opened.
+  if not open(result, filename, mode, bufSize):
+    sysFatal(IOError, "cannot open: " & filename)
+
+proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} =
+  ## sets the position of the file pointer that is used for read/write
+  ## operations. The file's first byte has the index zero.
+  if c_fseek(f, pos, cint(relativeTo)) != 0:
+    raiseEIO("cannot set file position")
+
+proc getFilePos*(f: File): int64 {.benign.} =
+  ## retrieves the current position of the file pointer that is used to
+  ## read from the file `f`. The file's first byte has the index zero.
+  result = c_ftell(f)
+  if result < 0: raiseEIO("cannot retrieve file position")
+
+proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} =
+  ## retrieves the file size (in bytes) of `f`.
+  var oldPos = getFilePos(f)
+  discard c_fseek(f, 0, 2) # seek the end of the file
+  result = getFilePos(f)
+  setFilePos(f, oldPos)
+
+proc setStdIoUnbuffered*() {.tags: [], benign.} =
+  ## Configures `stdin`, `stdout` and `stderr` to be unbuffered.
+  when declared(stdout):
+    discard c_setvbuf(stdout, nil, IONBF, 0)
+  when declared(stderr):
+    discard c_setvbuf(stderr, nil, IONBF, 0)
+  when declared(stdin):
+    discard c_setvbuf(stdin, nil, IONBF, 0)
+
+when declared(stdout):
+  when defined(windows) and compileOption("threads"):
+    const insideRLocksModule = false
+    include "system/syslocks"
+
+    var echoLock: SysLock
+    initSysLock echoLock
+
+  proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
+    # flockfile deadlocks some versions of Android 5.x.x
+    when not defined(windows) and not defined(android) and not defined(nintendoswitch):
+      proc flockfile(f: File) {.importc, noDecl.}
+      proc funlockfile(f: File) {.importc, noDecl.}
+      flockfile(stdout)
+    when defined(windows) and compileOption("threads"):
+      acquireSys echoLock
+    for s in args:
+      discard c_fwrite(s.cstring, s.len, 1, stdout)
+    const linefeed = "\n" # can be 1 or more chars
+    discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
+    discard c_fflush(stdout)
+    when not defined(windows) and not defined(android) and not defined(nintendoswitch):
+      funlockfile(stdout)
+    when defined(windows) and compileOption("threads"):
+      releaseSys echoLock
+
+
+when defined(windows) and not defined(nimscript):
+  # work-around C's sucking abstraction:
+  # BUGFIX: stdin and stdout should be binary files!
+  proc c_setmode(handle, mode: cint) {.
+    importc: when defined(bcc): "setmode" else: "_setmode",
+    header: "<io.h>".}
+  var
+    O_BINARY {.importc: "_O_BINARY", header:"<fcntl.h>".}: cint
+
+  # we use binary mode on Windows:
+  c_setmode(c_fileno(stdin), O_BINARY)
+  c_setmode(c_fileno(stdout), O_BINARY)
+  c_setmode(c_fileno(stderr), O_BINARY)
+
+
+proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} =
+  ## Opens a file named `filename` for reading, calls `readAll
+  ## <#readAll>`_ and closes the file afterwards. Returns the string.
+  ## Raises an IO exception in case of an error. If # you need to call
+  ## this inside a compile time macro you can use `staticRead
+  ## <#staticRead>`_.
+  var f: File
+  if open(f, filename):
+    try:
+      result = readAll(f).TaintedString
+    finally:
+      close(f)
+  else:
+    sysFatal(IOError, "cannot open: " & filename)
+
+proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
+  ## Opens a file named `filename` for writing. Then writes the
+  ## `content` completely to the file and closes the file afterwards.
+  ## Raises an IO exception in case of an error.
+  var f: File
+  if open(f, filename, fmWrite):
+    try:
+      f.write(content)
+    finally:
+      close(f)
+  else:
+    sysFatal(IOError, "cannot open: " & filename)
+
+iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
+  ## Iterates over any line in the file named `filename`.
+  ##
+  ## If the file does not exist `IOError` is raised. The trailing newline
+  ## character(s) are removed from the iterated lines. Example:
+  ##
+  ## .. code-block:: nim
+  ##   import strutils
+  ##
+  ##   proc transformLetters(filename: string) =
+  ##     var buffer = ""
+  ##     for line in filename.lines:
+  ##       buffer.add(line.replace("a", "0") & '\x0A')
+  ##     writeFile(filename, buffer)
+  var f = open(filename, bufSize=8000)
+  defer: close(f)
+  var res = TaintedString(newStringOfCap(80))
+  while f.readLine(res): yield res
+
+iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
+  ## Iterate over any line in the file `f`.
+  ##
+  ## The trailing newline character(s) are removed from the iterated lines.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   proc countZeros(filename: File): tuple[lines, zeros: int] =
+  ##     for line in filename.lines:
+  ##       for letter in line:
+  ##         if letter == '0':
+  ##           result.zeros += 1
+  ##       result.lines += 1
+  var res = TaintedString(newStringOfCap(80))
+  while f.readLine(res): yield res
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 9cc7ab323..9284f07d2 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -62,7 +62,7 @@ const
 
 proc raiseOutOfMem() {.noinline.} =
   if outOfMemHook != nil: outOfMemHook()
-  echo("out of memory")
+  cstderr.rawWrite("out of memory")
   quit(1)
 
 when defined(boehmgc):
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 5b0278d74..f49d681bf 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -15,439 +15,5 @@
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
-when defined(windows):
-  proc c_fdopen(filehandle: cint, mode: cstring): File {.
-    importc: "_fdopen", header: "<stdio.h>".}
-else:
-  proc c_fdopen(filehandle: cint, mode: cstring): File {.
-    importc: "fdopen", header: "<stdio.h>".}
-proc c_fputs(c: cstring, f: File): cint {.
-  importc: "fputs", header: "<stdio.h>", tags: [WriteIOEffect].}
-proc c_fgets(c: cstring, n: cint, f: File): cstring {.
-  importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
-proc c_fgetc(stream: File): cint {.
-  importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
-proc c_ungetc(c: cint, f: File): cint {.
-  importc: "ungetc", header: "<stdio.h>", tags: [].}
-proc c_putc(c: cint, stream: File): cint {.
-  importc: "putc", header: "<stdio.h>", tags: [WriteIOEffect].}
-proc c_fflush(f: File): cint {.
-  importc: "fflush", header: "<stdio.h>".}
-proc c_fclose(f: File): cint {.
-  importc: "fclose", header: "<stdio.h>".}
-proc c_clearerr(f: File) {.
-  importc: "clearerr", header: "<stdio.h>".}
-proc c_feof(f: File): cint {.
-  importc: "feof", header: "<stdio.h>".}
-
-when not declared(c_fwrite):
-  proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
-    importc: "fwrite", header: "<stdio.h>".}
-
-# C routine that is used here:
-proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
-  importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
-when defined(windows):
-  when not defined(amd64):
-    proc c_fseek(f: File, offset: int64, whence: cint): cint {.
-      importc: "fseek", header: "<stdio.h>", tags: [].}
-    proc c_ftell(f: File): int64 {.
-      importc: "ftell", header: "<stdio.h>", tags: [].}
-  else:
-    proc c_fseek(f: File, offset: int64, whence: cint): cint {.
-      importc: "_fseeki64", header: "<stdio.h>", tags: [].}
-    proc c_ftell(f: File): int64 {.
-      importc: "_ftelli64", header: "<stdio.h>", tags: [].}
-else:
-  proc c_fseek(f: File, offset: int64, whence: cint): cint {.
-    importc: "fseeko", header: "<stdio.h>", tags: [].}
-  proc c_ftell(f: File): int64 {.
-    importc: "ftello", header: "<stdio.h>", tags: [].}
-proc c_ferror(f: File): cint {.
-  importc: "ferror", header: "<stdio.h>", tags: [].}
-proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
-  importc: "setvbuf", header: "<stdio.h>", tags: [].}
-
-proc raiseEIO(msg: string) {.noinline, noreturn.} =
-  sysFatal(IOError, msg)
-
-proc raiseEOF() {.noinline, noreturn.} =
-  sysFatal(EOFError, "EOF reached")
-
-proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
-
-when not defined(NimScript):
-  var
-    errno {.importc, header: "<errno.h>".}: cint ## error variable
-
-proc checkErr(f: File) =
-  when not defined(NimScript):
-    if c_ferror(f) != 0:
-      let msg = "errno: " & $errno & " `" & $strerror(errno) & "`"
-      c_clearerr(f)
-      raiseEIO(msg)
-  else:
-    # shouldn't happen
-    quit(1)
-
-{.push stackTrace:off, profiler:off.}
-proc readBuffer(f: File, buffer: pointer, len: Natural): int =
-  result = c_fread(buffer, 1, len, f)
-  if result != len: checkErr(f)
-
-proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
-  result = readBuffer(f, addr(a[start]), len)
-
-proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
-  if (start + len) > len(a):
-    raiseEIO("buffer overflow: (start+len) > length of openarray buffer")
-  result = readBuffer(f, addr(a[start]), len)
-
-proc write(f: File, c: cstring) =
-  discard c_fputs(c, f)
-  checkErr(f)
-
-proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
-  result = c_fwrite(buffer, 1, len, f)
-  checkErr(f)
-
-proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
-  var x = cast[ptr UncheckedArray[int8]](a)
-  result = writeBuffer(f, addr(x[int(start)]), len)
-proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
-  var x = cast[ptr UncheckedArray[int8]](a)
-  result = writeBuffer(f, addr(x[int(start)]), len)
-
-proc write(f: File, s: string) =
-  if writeBuffer(f, cstring(s), s.len) != s.len:
-    raiseEIO("cannot write string to file")
-{.pop.}
-
-when NoFakeVars:
-  when defined(windows):
-    const
-      IOFBF = cint(0)
-      IONBF = cint(4)
-  else:
-    # On all systems I could find, including Linux, Mac OS X, and the BSDs
-    const
-      IOFBF = cint(0)
-      IONBF = cint(2)
-else:
-  var
-    IOFBF {.importc: "_IOFBF", nodecl.}: cint
-    IONBF {.importc: "_IONBF", nodecl.}: cint
-
-const
-  BufSize = 4000
-
-proc close*(f: File) =
-  if not f.isNil:
-    discard c_fclose(f)
-
-proc readChar(f: File): char =
-  let x = c_fgetc(f)
-  if x < 0:
-    checkErr(f)
-    raiseEOF()
-  result = char(x)
-
-proc flushFile*(f: File) = discard c_fflush(f)
-proc getFileHandle*(f: File): FileHandle = c_fileno(f)
-
-proc readLine(f: File, line: var TaintedString): bool =
-  var pos = 0
-
-  # Use the currently reserved space for a first try
-  var sp = max(line.string.len, 80)
-  line.string.setLen(sp)
-
-  while true:
-    # memset to \L so that we can tell how far fgets wrote, even on EOF, where
-    # fgets doesn't append an \L
-    nimSetMem(addr line.string[pos], '\L'.ord, sp)
-    var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil
-    if not fgetsSuccess: checkErr(f)
-    let m = c_memchr(addr line.string[pos], '\L'.ord, sp)
-    if m != nil:
-      # \l found: Could be our own or the one by fgets, in any case, we're done
-      var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0])
-      if last > 0 and line.string[last-1] == '\c':
-        line.string.setLen(last-1)
-        return last > 1 or fgetsSuccess
-        # We have to distinguish between two possible cases:
-        # \0\l\0 => line ending in a null character.
-        # \0\l\l => last line without newline, null was put there by fgets.
-      elif last > 0 and line.string[last-1] == '\0':
-        if last < pos + sp - 1 and line.string[last+1] != '\0':
-          dec last
-      line.string.setLen(last)
-      return last > 0 or fgetsSuccess
-    else:
-      # fgets will have inserted a null byte at the end of the string.
-      dec sp
-    # No \l found: Increase buffer and read more
-    inc pos, sp
-    sp = 128 # read in 128 bytes at a time
-    line.string.setLen(pos+sp)
-
-proc readLine(f: File): TaintedString =
-  result = TaintedString(newStringOfCap(80))
-  if not readLine(f, result): raiseEOF()
-
-proc write(f: File, i: int) =
-  when sizeof(int) == 8:
-    if c_fprintf(f, "%lld", i) < 0: checkErr(f)
-  else:
-    if c_fprintf(f, "%ld", i) < 0: checkErr(f)
-
-proc write(f: File, i: BiggestInt) =
-  when sizeof(BiggestInt) == 8:
-    if c_fprintf(f, "%lld", i) < 0: checkErr(f)
-  else:
-    if c_fprintf(f, "%ld", i) < 0: checkErr(f)
-
-proc write(f: File, b: bool) =
-  if b: write(f, "true")
-  else: write(f, "false")
-proc write(f: File, r: float32) =
-  if c_fprintf(f, "%.16g", r) < 0: checkErr(f)
-proc write(f: File, r: BiggestFloat) =
-  if c_fprintf(f, "%.16g", r) < 0: checkErr(f)
-
-proc write(f: File, c: char) = discard c_putc(cint(c), f)
-proc write(f: File, a: varargs[string, `$`]) =
-  for x in items(a): write(f, x)
-
-proc readAllBuffer(file: File): string =
-  # This proc is for File we want to read but don't know how many
-  # bytes we need to read before the buffer is empty.
-  result = ""
-  var buffer = newString(BufSize)
-  while true:
-    var bytesRead = readBuffer(file, addr(buffer[0]), BufSize)
-    if bytesRead == BufSize:
-      result.add(buffer)
-    else:
-      buffer.setLen(bytesRead)
-      result.add(buffer)
-      break
-
-proc rawFileSize(file: File): int64 =
-  # this does not raise an error opposed to `getFileSize`
-  var oldPos = c_ftell(file)
-  discard c_fseek(file, 0, 2) # seek the end of the file
-  result = c_ftell(file)
-  discard c_fseek(file, oldPos, 0)
-
-proc endOfFile(f: File): bool =
-  var c = c_fgetc(f)
-  discard c_ungetc(c, f)
-  return c < 0'i32
-  #result = c_feof(f) != 0
-
-proc readAllFile(file: File, len: int64): string =
-  # We acquire the filesize beforehand and hope it doesn't change.
-  # Speeds things up.
-  result = newString(len)
-  let bytes = readBuffer(file, addr(result[0]), len)
-  if endOfFile(file):
-    if bytes < len:
-      result.setLen(bytes)
-  else:
-    # We read all the bytes but did not reach the EOF
-    # Try to read it as a buffer
-    result.add(readAllBuffer(file))
-
-proc readAllFile(file: File): string =
-  var len = rawFileSize(file)
-  result = readAllFile(file, len)
-
-proc readAll(file: File): TaintedString =
-  # Separate handling needed because we need to buffer when we
-  # don't know the overall length of the File.
-  when declared(stdin):
-    let len = if file != stdin: rawFileSize(file) else: -1
-  else:
-    let len = rawFileSize(file)
-  if len > 0:
-    result = readAllFile(file, len).TaintedString
-  else:
-    result = readAllBuffer(file).TaintedString
-
-proc writeLn[Ty](f: File, x: varargs[Ty, `$`]) =
-  for i in items(x):
-    write(f, i)
-  write(f, "\n")
-
-proc writeLine[Ty](f: File, x: varargs[Ty, `$`]) =
-  for i in items(x):
-    write(f, i)
-  write(f, "\n")
-
-when declared(stdout):
-  proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x)
-  proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
-
-# interface to the C procs:
-
-include "system/widestrs"
-
-when defined(windows) and not defined(useWinAnsi):
-  when defined(cpp):
-    proc wfopen(filename, mode: WideCString): pointer {.
-      importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
-    proc wfreopen(filename, mode: WideCString, stream: File): File {.
-      importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.}
-  else:
-    proc wfopen(filename, mode: WideCString): pointer {.
-      importc: "_wfopen", nodecl.}
-    proc wfreopen(filename, mode: WideCString, stream: File): File {.
-      importc: "_wfreopen", nodecl.}
-
-  proc fopen(filename, mode: cstring): pointer =
-    var f = newWideCString(filename)
-    var m = newWideCString(mode)
-    result = wfopen(f, m)
-
-  proc freopen(filename, mode: cstring, stream: File): File =
-    var f = newWideCString(filename)
-    var m = newWideCString(mode)
-    result = wfreopen(f, m, stream)
-
-else:
-  proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.}
-  proc freopen(filename, mode: cstring, stream: File): File {.
-    importc: "freopen", nodecl.}
-
-const
-  FormatOpen: array[FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"]
-    #"rt", "wt", "w+t", "r+t", "at"
-    # we always use binary here as for Nim the OS line ending
-    # should not be translated.
-
-when defined(posix) and not defined(nimscript):
-  when defined(linux) and defined(amd64):
-    type
-      Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
-
-      # fillers ensure correct size & offsets
-      Stat {.importc: "struct stat",
-              header: "<sys/stat.h>", final, pure.} = object ## struct stat
-        filler_1: array[24, char]
-        st_mode: Mode        ## Mode of file
-        filler_2: array[144 - 24 - 4, char]
-
-    proc S_ISDIR(m: Mode): bool =
-      ## Test for a directory.
-      (m and 0o170000) == 0o40000
-
-  else:
-    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 c_fstat(a1: cint, a2: var Stat): cint {.
-    importc: "fstat", 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 c_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:
-      discard c_setvbuf(f, nil, IOFBF, bufSize.cint)
-    elif bufSize == 0:
-      discard c_setvbuf(f, nil, IONBF, 0)
-
-proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
-  var p: pointer = freopen(filename, FormatOpen[mode], f)
-  result = p != nil
-
-proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
-  f = c_fdopen(filehandle, FormatOpen[mode])
-  result = f != nil
-
-proc setFilePos(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) =
-  if c_fseek(f, pos, cint(relativeTo)) != 0:
-    raiseEIO("cannot set file position")
-
-proc getFilePos(f: File): int64 =
-  result = c_ftell(f)
-  if result < 0: raiseEIO("cannot retrieve file position")
-
-proc getFileSize(f: File): int64 =
-  var oldPos = getFilePos(f)
-  discard c_fseek(f, 0, 2) # seek the end of the file
-  result = getFilePos(f)
-  setFilePos(f, oldPos)
-
-proc readFile(filename: string): TaintedString =
-  var f: File
-  if open(f, filename):
-    try:
-      result = readAll(f).TaintedString
-    finally:
-      close(f)
-  else:
-    sysFatal(IOError, "cannot open: ", filename)
-
-proc writeFile(filename, content: string) =
-  var f: File
-  if open(f, filename, fmWrite):
-    try:
-      f.write(content)
-    finally:
-      close(f)
-  else:
-    sysFatal(IOError, "cannot open: ", filename)
-
-proc setStdIoUnbuffered() =
-  when declared(stdout):
-    discard c_setvbuf(stdout, nil, IONBF, 0)
-  when declared(stderr):
-    discard c_setvbuf(stderr, nil, IONBF, 0)
-  when declared(stdin):
-    discard c_setvbuf(stdin, nil, IONBF, 0)
-
-when declared(stdout):
-  when defined(windows) and compileOption("threads"):
-    var echoLock: SysLock
-    initSysLock echoLock
-
-  proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
-    # flockfile deadlocks some versions of Android 5.x.x
-    when not defined(windows) and not defined(android) and not defined(nintendoswitch):
-      proc flockfile(f: File) {.importc, noDecl.}
-      proc funlockfile(f: File) {.importc, noDecl.}
-      flockfile(stdout)
-    when defined(windows) and compileOption("threads"):
-      acquireSys echoLock
-    for s in args:
-      discard c_fwrite(s.cstring, s.len, 1, stdout)
-    const linefeed = "\n" # can be 1 or more chars
-    discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
-    discard c_fflush(stdout)
-    when not defined(windows) and not defined(android) and not defined(nintendoswitch):
-      funlockfile(stdout)
-    when defined(windows) and compileOption("threads"):
-      releaseSys echoLock
 
 {.pop.}
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index f89de4376..bbe170376 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -325,11 +325,8 @@ when not defined(useNimRtl):
 
   when emulatedThreadVars:
     if nimThreadVarsSize() > sizeof(ThreadLocalStorage):
-      echo "too large thread local storage size requested ",
-           "(", nimThreadVarsSize(), "/", sizeof(ThreadLocalStorage), "). ",
-           "Use -d:\"nimTlsSize=", nimThreadVarsSize(),
-           "\" to preallocate sufficient storage."
-
+      c_fprintf(cstderr, """too large thread local storage size requested,
+use -d:\"nimTlsSize=X\" to setup even more or stop using unittest.nim""")
       quit 1
 
   when hasSharedHeap and not defined(boehmgc) and not defined(gogc) and not defined(nogc):
diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim
index 85e5e1462..a52e58ac3 100644
--- a/lib/system/widestrs.nim
+++ b/lib/system/widestrs.nim
@@ -10,8 +10,8 @@
 # Nim support for C/C++'s `wide strings`:idx:. This is part of the system
 # module! Do not import it directly!
 
-when not declared(ThisIsSystem):
-  {.error: "You must not import this module explicitly".}
+#when not declared(ThisIsSystem):
+#  {.error: "You must not import this module explicitly".}
 
 type
   Utf16Char* = distinct int16