summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure')
-rwxr-xr-xlib/pure/logging.nim146
-rwxr-xr-xlib/pure/os.nim21
-rwxr-xr-xlib/pure/ropes.nim375
-rw-r--r--lib/pure/sockets.nim206
-rwxr-xr-xlib/pure/strtabs.nim8
5 files changed, 742 insertions, 14 deletions
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
new file mode 100755
index 000000000..6df39f50b
--- /dev/null
+++ b/lib/pure/logging.nim
@@ -0,0 +1,146 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple logger. It is based on the following design:
+## * Runtime log formating is a bug: Sooner or later ever log file is parsed.
+## * Keep it simple: If this library does not fullfill your needs, write your 
+##   own. Trying to support every logging feature just leads to bloat.
+## 
+## Format is:: 
+##
+##   DEBUG|INFO|... (2009-11-02 00:00:00)? (Component: )? Message
+##
+## 
+
+type
+  TLevel* = enum  ## logging level
+    lvlAll,       ## all levels active
+    lvlDebug,     ## debug level (and any above) active
+    lvlInfo,      ## info level (and any above) active
+    lvlWarn,      ## warn level (and any above) active
+    lvlError,     ## error level (and any above) active
+    lvlFatal      ## fatal level (and any above) active
+
+const
+  LevelNames*: array [TLevel, string] = [
+    "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
+  ]
+
+type
+  TLogger* = object of TObject ## abstract logger; the base type of all loggers
+    levelThreshold*: TLevel    ## only messages of level >= levelThreshold 
+                               ## should be processed
+  TConsoleLogger* = object of TLogger ## logger that writes the messages to the
+                                      ## console
+  
+  TFileLogger* = object of TLogger ## logger that writes the messages to a file
+    f: TFile
+    
+  TRollingFileLogger* = object of 
+      TFileLogger ## logger that writes the message to a file
+    maxlines: int # maximum number of lines
+    lines: seq[string]
+
+method log*(L: ref TLogger, level: TLevel,
+            frmt: string, args: openArray[string]) =
+  ## override this method in custom loggers. Default implementation does
+  ## nothing.
+  nil
+  
+method log*(L: ref TConsoleLogger, level: TLevel,
+            frmt: string, args: openArray[string]) = 
+  Writeln(stdout, LevelNames[level], " ", frmt % args)
+
+method log*(L: ref TFileLogger, level: TLevel, 
+            frmt: string, args: openArray[string]) = 
+  Writeln(L.f, LevelNames[level], " ", frmt % args)
+
+proc defaultFilename*(): string = 
+  ## returns the default filename for a logger
+  var (path, name, ext) = splitFile(getApplicationFilename())
+  result = changeFileExt(path / name & "_" & getDateStr(), "log")
+
+proc substituteLog*(frmt: string): string = 
+  ## converts $date to the current date
+  ## converts $time to the current time
+  ## converts $app to getApplicationFilename()
+  ## converts 
+  result = ""
+  var i = 0
+  while i < frmt.len: 
+    if frmt[i] != '$': 
+      result.add(frmt[i])
+      inc(i)
+    else:
+      inc(i)
+      var v = ""
+      var app = getApplicationFilename()
+      while frmt[i] in IdentChars: 
+        v.add(toLower(frmt[i]))
+        inc(i)
+      case v
+      of "date": result.add(getDateStr())
+      of "time": result.add(getClockStr())
+      of "app":  result.add(app)
+      of "appdir": result.add(app.splitFile.dir)
+      of "appname": result.add(app.splitFile.name)
+      
+
+proc newFileLogger(filename = defaultFilename(), 
+                   mode: TFileMode = fmAppend,
+                   levelThreshold = lvlNone): ref TFileLogger = 
+  new(result)
+  result.levelThreshold = levelThreshold
+  if not open(result.f, filename, mode): 
+    raiseException(EIO, "cannot open for writing: " & filename)
+
+proc newRollingFileLogger(filename = defaultFilename(), 
+                          mode: TFileMode = fmAppend,
+                          levelThreshold = lvlNone,
+                          maxLines = 1000): ref TFileLogger = 
+  new(result)
+  result.levelThreshold = levelThreshold
+  result.maxLines = maxLines
+  if not open(result.f, filename, mode): 
+    raiseException(EIO, "cannot open for writing: " & filename)
+
+var
+  level* = lvlNone
+  handlers*: seq[ref TLogger] = @[]
+
+proc logLoop(level: TLevel, msg: string) =
+  for logger in items(handlers): 
+    if level >= logger.levelThreshold:
+      log(logger, level, msg)
+
+template log*(level: TLevel, msg: string) =
+  ## logs a message of the given level
+  if level >= logging.Level:
+    (bind logLoop)(level, frmt, args)
+
+template debug*(msg: string) =
+  ## logs a debug message
+  log(lvlDebug, msg)
+
+template info*(msg: string) = 
+  ## logs an info message
+  log(lvlInfo, msg)
+
+template warn*(msg: string) = 
+  ## logs a warning message
+  log(lvlWarn, msg)
+
+template error*(msg: string) = 
+  ## logs an error message
+  log(lvlError, msg)
+  
+template fatal*(msg: string) =  
+  ## logs a fatal error message and calls ``quit(msg)``
+  log(lvlFatal, msg)
+
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index afa145e9f..85ac9c83c 100755
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -635,22 +635,23 @@ proc copyFile*(dest, source: string) =
     if CopyFileA(source, dest, 0'i32) == 0'i32: OSError()
   else:
     # generic version of copyFile which works for any platform:
-    const
-      bufSize = 8192 # 8K buffer
-    var
-      d, s: TFile
+    const bufSize = 8000 # better for memory manager
+    var d, s: TFile
     if not open(s, source): OSError()
     if not open(d, dest, fmWrite):
       close(s)
       OSError()
-    var
-      buf: Pointer = alloc(bufsize)
-      bytesread, byteswritten: int
+    var buf = alloc(bufsize)
     while True:
-      bytesread = readBuffer(s, buf, bufsize)
-      byteswritten = writeBuffer(d, buf, bytesread)
+      var bytesread = readBuffer(s, buf, bufsize)
+      if bytesread > 0:
+        var byteswritten = writeBuffer(d, buf, bytesread)
+        if bytesread != bytesWritten:
+          dealloc(buf)
+          close(s)
+          close(d)
+          OSError()
       if bytesread != bufSize: break
-      if bytesread != bytesWritten: OSError()
     dealloc(buf)
     close(s)
     close(d)
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
new file mode 100755
index 000000000..6655a9fda
--- /dev/null
+++ b/lib/pure/ropes.nim
@@ -0,0 +1,375 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains support for a `rope`:idx: data type.
+## Ropes can represent very long strings efficiently; especially concatenation
+## is done in O(1) instead of O(n). They are essentially concatenation
+## trees that are only flattened when converting to a native Nimrod
+## string. The empty string is represented by ``nil``. Ropes are immutable and
+## subtrees can be shared without copying.
+## Leaves can be cached for better memory efficiency at the cost of a bit of
+## runtime efficiency.
+
+{.deadCodeElim: on.}
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+# copied from excpt.nim, because I don't want to make this template public
+template newException(exceptn, message: expr): expr =
+  block: # open a new scope
+    var
+      e: ref exceptn
+    new(e)
+    e.msg = message
+    e
+
+const
+  countCacheMisses = false
+
+var
+  cacheEnabled = false
+
+type 
+  PRope* = ref TRope ## empty rope is represented by nil
+  TRope {.acyclic, final, pure.} = object
+    left, right: PRope
+    length: int
+    data: string # != nil if a leaf
+
+proc isConc(r: PRope): bool {.inline.} = return isNil(r.data)
+
+# Note that the left and right pointers are not needed for leafs.
+# Leaves have relatively high memory overhead (~30 bytes on a 32
+# bit machine) and we produce many of them. This is why we cache and
+# share leafs accross different rope trees.
+# To cache them they are inserted in another tree, a splay tree for best
+# performance. But for the caching tree we use the leaf's left and right
+# pointers.
+
+proc len*(a: PRope): int =
+  ## the rope's length
+  if a == nil: result = 0
+  else: result = a.length
+  
+proc newRope(): PRope = new(result)
+proc newRope(data: string): PRope = 
+  new(result)
+  result.length = len(data)
+  result.data = data
+
+var 
+  cache: PRope                # the root of the cache tree
+  N: PRope                    # dummy rope needed for splay algorithm
+
+when countCacheMisses:
+  var misses, hits: int
+  
+proc splay(s: string, tree: PRope, cmpres: var int): PRope = 
+  var c: int
+  var t = tree
+  N.left = nil
+  N.right = nil               # reset to nil
+  var le = N
+  var r = N
+  while true: 
+    c = cmp(s, t.data)
+    if c < 0: 
+      if (t.left != nil) and (s < t.left.data): 
+        var y = t.left
+        t.left = y.right
+        y.right = t
+        t = y
+      if t.left == nil: break 
+      r.left = t
+      r = t
+      t = t.left
+    elif c > 0: 
+      if (t.right != nil) and (s > t.right.data): 
+        var y = t.right
+        t.right = y.left
+        y.left = t
+        t = y
+      if t.right == nil: break 
+      le.right = t
+      le = t
+      t = t.right
+    else: 
+      break 
+  cmpres = c
+  le.right = t.left
+  r.left = t.right
+  t.left = N.right
+  t.right = N.left
+  result = t
+
+proc insertInCache(s: string, tree: PRope): PRope = 
+  var t = tree
+  if t == nil: 
+    result = newRope(s)
+    when countCacheMisses: inc(misses)
+    return 
+  var cmp: int
+  t = splay(s, t, cmp)
+  if cmp == 0: 
+    # We get here if it's already in the Tree
+    # Don't add it again
+    result = t
+    when countCacheMisses: inc(hits)
+  else: 
+    when countCacheMisses: inc(misses)
+    result = newRope(s)
+    if cmp < 0: 
+      result.left = t.left
+      result.right = t
+      t.left = nil
+    else: 
+      # i > t.item:
+      result.right = t.right
+      result.left = t
+      t.right = nil
+
+proc rope*(s: string): PRope =
+  ## Converts a string to a rope. 
+  if s.len == 0: 
+    result = nil
+  elif cacheEnabled: 
+    result = insertInCache(s, cache)
+    cache = result
+  else: 
+    result = newRope(s)
+  
+proc rope*(i: BiggestInt): PRope = 
+  ## Converts an int to a rope. 
+  result = rope($i)
+
+proc rope*(f: BiggestFloat): PRope =
+  ## Converts a float to a rope. 
+  result = rope($f)
+
+proc disableCache*() =
+  ## the cache is discarded and disabled. The GC will reuse its used memory.
+  cache = nil
+  cacheEnabled = false
+  
+proc enableCache*() =
+  ## Enables the caching of leaves. This reduces the memory footprint at
+  ## the cost of runtime efficiency.
+  cacheEnabled = true
+
+proc `&`*(a, b: PRope): PRope =
+  ## the concatenation operator for ropes.
+  if a == nil: 
+    result = b
+  elif b == nil: 
+    result = a
+  else:
+    result = newRope()
+    result.length = a.length + b.length
+    when false:
+      # XXX rebalancing would be nice, but is too expensive.
+      result.left = a.left
+      var x = newRope()
+      x.left = a.right
+      x.right = b
+      result.right = x
+    else:
+      result.left = a
+      result.right = b
+  
+proc `&`*(a: PRope, b: string): PRope = 
+  ## the concatenation operator for ropes.
+  result = a & rope(b)
+  
+proc `&`*(a: string, b: PRope): PRope = 
+  ## the concatenation operator for ropes.
+  result = rope(a) & b
+  
+proc `&`*(a: openarray[PRope]): PRope = 
+  ## the concatenation operator for an openarray of ropes.
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc add*(a: var PRope, b: PRope) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+proc add*(a: var PRope, b: string) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+  
+proc `[]`*(r: PRope, i: int): char =
+  ## returns the character at position `i` in the rope `r`. This is quite
+  ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned.
+  var x = r
+  var j = i
+  if x == nil: return
+  while true:
+    if not isConc(x):
+      if x.data.len <% j: return x.data[j]
+      return '\0'
+    else:
+      if x.left.len >% j:
+        x = x.left
+      else:
+        x = x.right
+        dec(j, x.len)
+
+iterator leaves*(r: PRope): string =
+  ## iterates over any leaf string in the rope `r`.
+  if r != nil:
+    var stack = @[r]
+    while stack.len > 0: 
+      var it = stack.pop
+      while isConc(it):
+        stack.add(it.right)
+        it = it.left
+        assert(it != nil)
+      assert(it.data != nil)
+      yield it.data
+  
+iterator items*(r: PRope): char =
+  ## iterates over any character in the rope `r`.
+  for s in leaves(r):
+    for c in items(s): yield c
+
+proc write*(f: TFile, r: PRope) =
+  ## writes a rope to a file.
+  for s in leaves(r): write(f, s)
+
+proc `$`*(r: PRope): string = 
+  ## converts a rope back to a string.
+  result = newString(r.len)
+  setLen(result, 0)
+  for s in leaves(r): add(result, s)
+
+when false:
+  # Format string caching seems reasonable: All leaves can be shared and format
+  # string parsing has to be done only once. A compiled format string is stored
+  # as a rope. A negative length is used for the index into the args array.
+  proc compiledArg(idx: int): PRope =
+    new(result)
+    result.length = -idx
+  
+  proc compileFrmt(frmt: string): PRope = 
+    var i = 0
+    var length = len(frmt)
+    result = nil
+    var num = 0
+    while i < length: 
+      if frmt[i] == '$': 
+        inc(i)
+        case frmt[i]
+        of '$': 
+          add(result, "$")
+          inc(i)
+        of '#': 
+          inc(i)
+          add(result, compiledArg(num+1))
+          inc(num)
+        of '0'..'9': 
+          var j = 0
+          while true: 
+            j = j * 10 + ord(frmt[i]) - ord('0')
+            inc(i)
+            if frmt[i] notin {'0'..'9'}: break 
+          num = j
+          add(s, compiledArg(j))
+        of '{':
+          inc(i)
+          var j = 0
+          while frmt[i] in {'0'..'9'}:
+            j = j * 10 + ord(frmt[i]) - ord('0')
+            inc(i)
+          if frmt[i] == '}': inc(i)
+          else: raise newException(EInvalidValue, "invalid format string")
+          num = j
+          add(s, compiledArg(j))
+        else: raise newException(EInvalidValue, "invalid format string")
+      var start = i
+      while i < length: 
+        if frmt[i] != '$': inc(i)
+        else: break 
+      if i - 1 >= start: 
+        add(result, copy(frmt, start, i-1))
+  
+proc `%`*(frmt: string, args: openarray[PRope]): PRope =
+  ## `%` substitution operator for ropes. Does not support the ``$identifier``
+  ## nor ``${identifier}`` notations.
+  var i = 0
+  var length = len(frmt)
+  result = nil
+  var num = 0
+  while i < length: 
+    if frmt[i] == '$': 
+      inc(i)
+      case frmt[i]
+      of '$': 
+        add(result, "$")
+        inc(i)
+      of '#': 
+        inc(i)
+        add(result, args[num])
+        inc(num)
+      of '0'..'9': 
+        var j = 0
+        while true: 
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+          if frmt[i] notin {'0'..'9'}: break 
+        num = j
+        add(result, args[j-1])
+      of '{':
+        inc(i)
+        var j = 0
+        while frmt[i] in {'0'..'9'}:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+        if frmt[i] == '}': inc(i)
+        else: raise newException(EInvalidValue, "invalid format string")
+        num = j
+        add(result, args[j-1])
+      else: raise newException(EInvalidValue, "invalid format string")
+    var start = i
+    while i < length: 
+      if frmt[i] != '$': inc(i)
+      else: break 
+    if i - 1 >= start: 
+      add(result, copy(frmt, start, i - 1))
+
+proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) =
+  ## shortcut for ``add(c, frmt % args)``.
+  add(c, frmt % args)
+
+proc equalsFile*(r: PRope, f: TFile): bool =
+  ## returns true if the contents of the file `f` equal `r`.
+  var bufSize = 1024 # reasonable start value
+  var buf = alloc(BufSize)
+  for s in leaves(r):
+    if s.len > bufSize:
+      bufSize = max(bufSize * 2, s.len)
+      buf = realloc(buf, bufSize)
+    var readBytes = readBuffer(f, buf, s.len)
+    result = readBytes == s.len and equalMem(buf, cstring(s), s.len)
+    if not result: break
+  if result:
+    result = readBuffer(f, buf, 1) == 0 # really at the end of file?
+  dealloc(buf)
+
+proc equalsFile*(r: PRope, f: string): bool =
+  ## returns true if the contents of the file `f` equal `r`. If `f` does not
+  ## exist, false is returned.
+  var bin: TFile
+  result = open(bin, f)
+  if result:
+    result = equalsFile(r, bin)
+    close(bin)
+
+new(N) # init dummy node for splay algorithm
+
+{.pop.}
\ No newline at end of file
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
new file mode 100644
index 000000000..0f9221b37
--- /dev/null
+++ b/lib/pure/sockets.nim
@@ -0,0 +1,206 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple portable type-safe sockets layer. **Note**:
+## This module is incomplete and probably buggy. It does not work on Windows
+## yet. Help if you are interested.
+
+# TODO:
+# getservbyname(name, proto)
+# getservbyport(port, proto)
+# gethostbyname(name)
+# gethostbyaddr(addr)
+# shutdown(sock, how)
+# connect(sock, address, port)
+# select({ socket, ... }, timeout)
+
+# sendto
+# recvfrom
+
+# bind(socket, address, port)
+
+# getsockopt(socket, level, optname)
+# setsockopt(socket, level, optname, value)
+
+import os
+
+when defined(Windows):
+  import winlean
+else:
+  import posix
+
+type
+  TSocket* = distinct cint ## socket type
+  TPort* = distinct int16  ## port type
+  
+  TDomain* = enum   ## domain, which specifies the protocol family of the
+                    ## created socket. Other domains than those that are listed
+                    ## here are unsupported.
+    AF_UNIX,        ## for local socket (using a file).
+    AF_INET,        ## for network protocol IPv4 or
+    AF_INET6        ## for network protocol IPv6.
+
+  TType* = enum     ## second argument to `socket` proc
+    SOCK_STREAM,    ## reliable stream-oriented service or Stream Sockets
+    SOCK_DGRAM,     ## datagram service or Datagram Sockets
+    SOCK_SEQPACKET, ## reliable sequenced packet service, or
+    SOCK_RAW        ## raw protocols atop the network layer.
+
+  TProtocol* = enum ## third argument to `socket` proc
+    IPPROTO_TCP,    ## Transmission control protocol. 
+    IPPROTO_UDP,    ## User datagram protocol.
+    IPPROTO_IP,     ## Internet protocol. 
+    IPPROTO_IPV6,   ## Internet Protocol Version 6. 
+    IPPROTO_RAW,    ## Raw IP Packets Protocol. 
+    IPPROTO_ICMP    ## Control message protocol. 
+
+const
+  InvalidSocket* = TSocket(-1'i32) ## invalid socket number
+
+proc `==`*(a, b: TSocket): bool {.borrow.}
+proc `==`*(a, b: TPort): bool {.borrow.}
+
+proc ToInt(domain: TDomain): cint =
+  case domain
+  of AF_UNIX:        result = posix.AF_UNIX
+  of AF_INET:        result = posix.AF_INET
+  of AF_INET6:       result = posix.AF_INET6
+
+proc ToInt(typ: TType): cint =
+  case typ
+  of SOCK_STREAM:    result = posix.SOCK_STREAM
+  of SOCK_DGRAM:     result = posix.SOCK_DGRAM
+  of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
+  of SOCK_RAW:       result = posix.SOCK_RAW
+
+proc ToInt(p: TProtocol): cint =
+  case p
+  of IPPROTO_TCP:    result = posix.IPPROTO_TCP
+  of IPPROTO_UDP:    result = posix.IPPROTO_UDP
+  of IPPROTO_IP:     result = posix.IPPROTO_IP
+  of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
+  of IPPROTO_RAW:    result = posix.IPPROTO_RAW
+  of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
+
+proc socket*(domain: TDomain = AF_INET6, typ: TType = SOCK_STREAM,
+             protocol: TProtocol = IPPROTO_TCP): TSocket =
+  ## creates a new socket; returns `InvalidSocket` if an error occurs.  
+  result = TSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol)))
+
+proc listen*(socket: TSocket, attempts = 5) =
+  ## listens to socket.
+  if posix.listen(cint(socket), cint(attempts)) < 0'i32: OSError()
+
+proc bindAddr*(socket: TSocket, port = TPort(0)) =
+  var name: Tsockaddr_in
+  name.sin_family = posix.AF_INET
+  name.sin_port = htons(int16(port))
+  name.sin_addr.s_addr = htonl(INADDR_ANY)
+  if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)),
+                sizeof(name)) < 0'i32:
+    OSError()
+  
+proc getSockName*(socket: TSocket): TPort = 
+  var name: Tsockaddr_in
+  name.sin_family = posix.AF_INET
+  #name.sin_port = htons(cint16(port))
+  #name.sin_addr.s_addr = htonl(INADDR_ANY)
+  var namelen: cint = sizeof(name)
+  if getsockname(cint(socket), cast[ptr TSockAddr](addr(name)),
+                 addr(namelen)) == -1'i32:
+    OSError()
+  result = TPort(ntohs(name.sin_port))
+
+proc accept*(server: TSocket): TSocket =
+  ## waits for a client and returns its socket
+  var client: Tsockaddr_in
+  var clientLen: TsockLen = sizeof(client)
+  result = TSocket(accept(cint(server), cast[ptr TSockAddr](addr(client)),
+                          addr(clientLen)))
+
+proc close*(socket: TSocket) =
+  ## closes a socket.
+  when defined(windows):
+    discard winlean.closeSocket(cint(socket))
+  else:
+    discard posix.close(cint(socket))
+
+proc recvLine*(socket: TSocket, line: var string): bool =
+  ## returns false if no further data is available.
+  setLen(line, 0)
+  while true:
+    var c: char
+    var n = recv(cint(socket), addr(c), 1, 0'i32)
+    if n <= 0: return
+    if c == '\r':
+      n = recv(cint(socket), addr(c), 1, MSG_PEEK)
+      if n > 0 and c == '\L':
+        discard recv(cint(socket), addr(c), 1, 0'i32)
+      elif n <= 0: return false
+      return true
+    elif c == '\L': return true
+    add(line, c)
+
+proc recv*(socket: TSocket, data: pointer, size: int): int =
+  ## receive data from a socket
+  result = posix.recv(cint(socket), data, size, 0'i32)
+
+proc recv*(socket: TSocket): string =
+  ## receive all the data from the socket
+  const bufSize = 200
+  var buf = newString(bufSize)
+  result = ""
+  while true:
+    var bytesRead = recv(socket, cstring(buf), bufSize-1)
+    buf[bytesRead] = '\0' # might not be necessary
+    setLen(buf, bytesRead)
+    add(result, buf)
+    if bytesRead != bufSize-1: break
+  
+proc skip*(socket: TSocket) =
+  ## skips all the data that is pending for the socket
+  const bufSize = 200
+  var buf = alloc(bufSize)
+  while recv(socket, buf, bufSize) == bufSize: nil
+  dealloc(buf)
+
+proc send*(socket: TSocket, data: pointer, size: int): int =
+  result = posix.send(cint(socket), data, size, 0'i32)
+
+proc send*(socket: TSocket, data: string) =
+  if send(socket, cstring(data), data.len) != data.len: OSError()
+
+proc ntohl*(x: int32): int32 = 
+  ## Convert 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.
+  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)
+
+proc ntohs*(x: int16): int16 =
+  ## Convert 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.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 8'i16) or (x shl 8'i16)
+
+proc htonl*(x: int32): int32 =
+  ## Convert 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.
+  result = sockets.ntohl(x)
+
+proc htons*(x: int16): int16 =
+  ## Convert 16-bit positive 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.
+  result = sockets.ntohs(x)
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 10cd0b933..8ea59637a 100755
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -7,10 +7,10 @@
 #    distribution, for details about the copyright.
 #
 
-##  The ``strtabs`` module implements an efficient hash table that is a mapping
-##  from strings to strings. Supports a case-sensitive, case-insensitive and
-##  style-insensitive mode. An efficient string substitution operator  ``%``
-##  for the string table is also provided.
+## The ``strtabs`` module implements an efficient hash table that is a mapping
+## from strings to strings. Supports a case-sensitive, case-insensitive and
+## style-insensitive mode. An efficient string substitution operator  ``%``
+## for the string table is also provided.
 
 import
   os, hashes, strutils