summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCharles Blake <cblake@csail.mit.edu>2015-07-24 14:38:20 -0400
committerCharles Blake <cblake@csail.mit.edu>2015-07-24 14:38:20 -0400
commita12c9cfb9d2e5df881ad90f0f4d7c211b8a14ce6 (patch)
tree12fd2554471d2d595d56024fc930a045d48f7e8f
parent49324157421d138c3cba39b629bdb88a5b88dc54 (diff)
downloadNim-a12c9cfb9d2e5df881ad90f0f4d7c211b8a14ce6.tar.gz
Add MemFile text interface factored so users can optionally skip Nim string
construction (e.g. to filter many lines out before building strings).  Only
Windows and/or Unix line endings are supported by default, though fiddling
with delim/eat arguments can probably support archaic MacOS9 files.
-rw-r--r--lib/pure/memfiles.nim32
1 files changed, 32 insertions, 0 deletions
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 76ff6a8e1..ab42e90c7 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -245,3 +245,35 @@ proc close*(f: var MemFile) =
   
   if error: raiseOSError(lastErr)
 
+type Record* {.unchecked.} = object
+  Beg*: cstring
+  Len*: int
+
+iterator records*(mfile: MemFile, delim='\l', eat='\r'): Record {.inline.} =
+  proc c_memchr(cstr: cstring, c: char, n: csize): cstring {.
+       importc: "memchr", header: "<string.h>" .}
+  proc `-!`(p, q: cstring): int {.inline.} = return cast[int](p) -% cast[int](q)
+  var rec: Record
+  var End: cstring
+  rec.Beg = cast[cstring](mfile.mem)
+  var remaining = mfile.size
+  while remaining > 0:
+    End = c_memchr(rec.Beg, delim, remaining)
+    if End == nil:                                  # unterminated final record
+      rec.Len = remaining
+      yield rec
+      break
+    rec.Len = End -! rec.Beg                        # delimiter is not included
+    if eat != '\0' and rec.Len > 0 and rec.Beg[rec.Len - 1] == eat:
+      dec(rec.Len)                                  # exclude extra pre-delim ch
+    yield rec
+    rec.Beg = cast[cstring](cast[int](End) +% 1)    # skip delimiter
+    remaining = mfile.size - (rec.Beg -! cast[cstring](mfile.mem))
+
+proc toString*(rec: Record): string {.inline.} =
+  proc toNimStr(str: cstring, len: int): string {. importc: "toNimStr" .}
+  result = toNimStr(cast[cstring](rec.Beg), rec.Len)
+  result[result.len] = '\0'
+
+iterator lines*(mfile: MemFile): string {.inline.} =
+  for rec in records(mfile): yield toString(rec)