summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-12-31 02:21:01 -0800
committerAraq <rumpf_a@web.de>2011-12-31 02:21:01 -0800
commit61ff32933789ea5d0c327d7a5c5d7b1f4dfc8499 (patch)
tree28ff00cbc675e9e1113637bf2d952d2ace616d00 /lib
parent9fdfda136c4d3ec0d8e72867345b427b30e88ef4 (diff)
parentcf2078aed8c0b706f2e3576914558c9530fcb832 (diff)
downloadNim-61ff32933789ea5d0c327d7a5c5d7b1f4dfc8499.tar.gz
Merge pull request #79 from Tass/master
readAll
Diffstat (limited to 'lib')
-rwxr-xr-xlib/system.nim9
-rwxr-xr-xlib/system/sysio.nim69
2 files changed, 56 insertions, 22 deletions
diff --git a/lib/system.nim b/lib/system.nim
index f8bfe3e77..ab38fbb21 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1677,10 +1677,13 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
     ## Flushes `f`'s buffer.
 
+  proc readAll*(file: TFile): TaintedString
+    ## Reads all data from the stream `file`. Raises an IO exception
+    ## in case of an error
+  
   proc readFile*(filename: string): TaintedString
-    ## Opens a file named `filename` for reading. Then reads the
-    ## file's content completely into a string and
-    ## closes the file afterwards. Returns the string. 
+    ## Opens a file named `filename` for reading. Then calls `readAll`
+    ## and closes the file afterwards. Returns the string. 
     ## Raises an IO exception in case of an error.
 
   proc writeFile*(filename, content: string)
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 890f526ea..d012110f1 100755
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -24,6 +24,13 @@ proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl.}
 proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs.}
 proc strlen(c: cstring): int {.importc: "strlen", nodecl.}
 
+
+# C routine that is used here:
+proc fread(buf: Pointer, size, n: int, f: TFile): int {.
+  importc: "fread", noDecl.}
+proc fseek(f: TFile, offset: clong, whence: int): int {.
+  importc: "fseek", noDecl.}
+proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
 proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
   importc, nodecl.}
 
@@ -36,6 +43,9 @@ var
   IOFBF {.importc: "_IOFBF", nodecl.}: cint
   IONBF {.importc: "_IONBF", nodecl.}: cint
 
+const
+  buf_size = 4000
+
 proc raiseEIO(msg: string) {.noinline, noreturn.} =
   raise newException(EIO, msg)
 
@@ -82,21 +92,49 @@ proc write(f: TFile, c: Char) = putc(c, f)
 proc write(f: TFile, a: openArray[string]) =
   for x in items(a): write(f, x)
 
+proc readAllBuffer(file: TFile): string = 
+  # This proc is for TFile we want to read but don't know how many
+  # bytes we need to read before the buffer is empty.
+  result = ""
+  var buffer = newString(buf_size)
+  var bytesRead = buf_size
+  while bytesRead == buf_size:
+    bytesRead = readBuffer(file, addr(buffer[0]), buf_size)
+    result.add(buffer)
+  
+proc rawFileSize(file: TFile): int = 
+  # this does not raise an error opposed to `getFileSize`
+  var oldPos = ftell(file)
+  discard fseek(file, 0, 2) # seek the end of the file
+  result = ftell(file)
+  discard fseek(file, clong(oldPos), 0)
+
+proc readAllFile(file: TFile, len: int): string =
+  # We aquire the filesize beforehand and hope it doesn't change.
+  # Speeds things up.
+  if len >= high(int):
+    raiseEIO("file too big to fit in memory")
+  result = newString(int(len))
+  if readBuffer(file, addr(result[0]), int(len)) != len:
+    raiseEIO("error while reading from file")
+
+proc readAllFile(file: TFile): string =
+  var len = rawFileSize(file)
+  result = readAllFile(file, len)
+  
+proc readAll(file: TFile): TaintedString = 
+  # Separate handling needed because we need to buffer when we
+  # don't know the overall length of the TFile.
+  var len = rawFileSize(file)
+  if len >= 0:
+    result = readAllFile(file, len).TaintedSTring
+  else:
+    result = readAllBuffer(file).TaintedString
+  
 proc readFile(filename: string): TaintedString =
   var f = open(filename)
   try:
-    var len = getFileSize(f)
-    if len < high(int):
-      when taintMode:
-        result = newString(int(len)).TaintedString
-        if readBuffer(f, addr(string(result)[0]), int(len)) != len:
-          raiseEIO("error while reading from file")
-      else:
-        result = newString(int(len))
-        if readBuffer(f, addr(result[0]), int(len)) != len:
-          raiseEIO("error while reading from file")
-    else:
-      raiseEIO("file too big to fit in memory")
+    result = readAllFile(f).TaintedString
   finally:
     close(f)
 
@@ -157,13 +195,6 @@ proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
   f = fdopen(filehandle, FormatOpen[mode])
   result = f != nil
 
-# C routine that is used here:
-proc fread(buf: Pointer, size, n: int, f: TFile): int {.
-  importc: "fread", noDecl.}
-proc fseek(f: TFile, offset: clong, whence: int): int {.
-  importc: "fseek", noDecl.}
-proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
-
 proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
   importc: "fwrite", noDecl.}