summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-03-31 18:51:11 +0300
committerZahary Karadjov <zahary@gmail.com>2012-03-31 18:51:11 +0300
commit8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5 (patch)
tree3fb011eb742df74754abc2479d211bbdbef16b02 /lib
parent22dc76a361c70af93403dfbf2610c8d49111637c (diff)
parentc7fc519fa39ded59744bc677261faa04b6947cee (diff)
downloadNim-8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod into upstream
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/irc.nim6
-rwxr-xr-xlib/pure/sockets.nim87
-rwxr-xr-xlib/system.nim54
-rwxr-xr-xlib/system/ansi_c.nim1
-rw-r--r--lib/system/embedded.nim106
-rwxr-xr-xlib/system/excpt.nim2
-rwxr-xr-xlib/system/mmdisp.nim72
-rwxr-xr-xlib/system/repr.nim3
8 files changed, 298 insertions, 33 deletions
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 8946a9d8f..81dff024e 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent =
     inc(i) # Skip `:`
     var nick = ""
     i.inc msg.parseUntil(nick, {'!', ' '}, i)
+    result.nick = ""
+    result.serverName = ""
     if msg[i] == '!':
       result.nick = nick
       inc(i) # Skip `!`
@@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent =
     result = parseMessage(line)
     # Get the origin
     result.origin = result.params[0]
-    if result.origin == irc.nick: result.origin = result.nick
+    if result.origin == irc.nick and
+       result.nick != "": result.origin = result.nick
 
     if result.cmd == MError:
       irc.close()
@@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
   result.messageBuffer = @[]
   result.handleEvent = ircEvent
   result.userArg = userArg
+  result.lineBuffer = ""
 
 proc register*(d: PDispatcher, irc: PAsyncIRC) =
   ## Registers ``irc`` with dispatcher ``d``.
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 5721d79fe..31973c6ce 100755
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -8,8 +8,12 @@
 #
 
 ## This module implements a simple portable type-safe sockets layer.
+##
+## Most procedures raise EOS on error.
+
 
 import os, parseutils
+from times import epochTime
 
 when defined(Windows):
   import winlean
@@ -59,6 +63,8 @@ type
   TRecvLineResult* = enum ## result for recvLineAsync
     RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
 
+  ETimeout* = object of ESynch
+
 const
   InvalidSocket* = TSocket(-1'i32) ## invalid socket number
 
@@ -377,12 +383,14 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
   ## host name. If ``name`` is a host name, this function will try each IP
   ## of that host name. ``htons`` is already performed on ``port`` so you must
   ## not do it.
+  
   var hints: TAddrInfo
   var aiList: ptr TAddrInfo = nil
   hints.ai_family = toInt(af)
   hints.ai_socktype = toInt(SOCK_STREAM)
   hints.ai_protocol = toInt(IPPROTO_TCP)
   gaiNim(name, port, hints, aiList)
+  
   # try all possibilities:
   var success = false
   var it = aiList
@@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
   freeaddrinfo(aiList)
   if not success: OSError()
 
-
 proc timeValFromMilliseconds(timeout = 500): TTimeVal =
   if timeout != -1:
     var seconds = timeout div 1000
@@ -545,7 +552,33 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
     result = int(select(cint(m+1), addr(rd), nil, nil, nil))
   
   pruneSocketSet(readfds, (rd))
+  
+proc recv*(socket: TSocket, data: pointer, size: int): int =
+  ## receives data from a socket
+  result = recv(cint(socket), data, size, 0'i32)
 
+template waitFor(): stmt =
+  if timeout - int(waited * 1000.0) < 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  var s = @[socket]
+  var startTime = epochTime()
+  if select(s, timeout - int(waited * 1000.0)) != 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  waited += (epochTime() - startTime)
+
+proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int =
+  ## overload with a ``timeout`` parameter in miliseconds.
+  var waited = 0.0 # number of seconds already waited  
+  
+  var read = 0
+  while read < size:
+    waitFor()
+    result = recv(cint(socket), addr(data[read]), 1, 0'i32)
+    if result < 0:
+      return
+    inc(read)
+  
+  result = read
 
 proc recvLine*(socket: TSocket, line: var TaintedString): bool =
   ## returns false if no further data is available. `Line` must be initialized
@@ -567,6 +600,29 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
     elif c == '\L': return true
     add(line.string, c)
 
+proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
+  ## variant with a ``timeout`` parameter, the timeout parameter specifies
+  ## how many miliseconds to wait for data.
+  
+  var waited = 0.0 # number of seconds already waited
+  
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    waitFor()
+    var n = recv(cint(socket), addr(c), 1, 0'i32)
+    if n < 0: return
+    elif n == 0: return true
+    if c == '\r':
+      waitFor()
+      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.string, c)
+
 proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
   ## similar to ``recvLine`` but for non-blocking sockets.
   ## The values of the returned enum should be pretty self explanatory:
@@ -592,10 +648,6 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
     elif c == '\L': return RecvFullLine
     add(line.string, c)
 
-proc recv*(socket: TSocket, data: pointer, size: int): int =
-  ## receives data from a socket
-  result = recv(cint(socket), data, size, 0'i32)
-
 proc recv*(socket: TSocket): TaintedString =
   ## receives all the data from the socket.
   ## Socket errors will result in an ``EOS`` error.
@@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString =
       add(result.string, buf)
       if bytesRead != bufSize-1: break
 
+proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
+  ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
+  ## parameter specifies the amount of miliseconds to wait for data on the
+  ## socket.
+  var s = @[socket]
+  if s.select(timeout) != 1:
+    raise newException(ETimeout, "Call to recv() timed out.")
+  
+  return socket.recv
+
 proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
   ## receives all the data from a non-blocking socket. If socket is non-blocking 
   ## and there are no messages available, `False` will be returned.
@@ -723,6 +785,21 @@ proc setBlocking*(s: TSocket, blocking: bool) =
       if fcntl(cint(s), F_SETFL, mode) == -1:
         OSError()
 
+proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
+             af: TDomain = AF_INET) =
+  ## Overload for ``connect`` to support timeouts. The ``timeout`` parameter 
+  ## specifies the time in miliseconds of how long to wait for a connection
+  ## to be made.
+  ##
+  ## **Warning:** If ``socket`` is non-blocking and timeout is not ``-1`` then
+  ## this function may set blocking mode on ``socket`` to true.
+  socket.setBlocking(true)
+  
+  socket.connectAsync(name, port, af)
+  var s: seq[TSocket] = @[socket]
+  if selectWrite(s, timeout) != 1:
+    raise newException(ETimeout, "Call to connect() timed out.")
+
 when defined(Windows):
   var wsa: TWSADATA
   if WSAStartup(0x0101'i16, wsa) != 0: OSError()
diff --git a/lib/system.nim b/lib/system.nim
index e1b82b6bb..78912be7e 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -851,7 +851,7 @@ template sysAssert(cond: bool, msg: string) =
 
 include "system/inclrtl"
 
-when not defined(ecmascript) and not defined(nimrodVm):
+when not defined(ecmascript) and not defined(nimrodVm) and not defined(avr):
   include "system/cgprocs"
 
 proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
@@ -1604,16 +1604,17 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   {.push stack_trace: off.}
 
   proc initGC()
-  when not defined(boehmgc):
+  when not defined(boehmgc) and not defined(useMalloc):
     proc initAllocator() {.inline.}
 
-  proc initStackBottom() {.inline.} = 
-    # WARNING: This is very fragile! An array size of 8 does not work on my
-    # Linux 64bit system. Very strange, but we are at the will of GCC's 
-    # optimizer...
-    var locals {.volatile.}: pointer
-    locals = addr(locals)
-    setStackBottom(locals)
+  when not defined(nogc):
+    proc initStackBottom() {.inline.} = 
+      # WARNING: This is very fragile! An array size of 8 does not work on my
+      # Linux 64bit system. Very strange, but we are at the will of GCC's 
+      # optimizer...
+      var locals {.volatile.}: pointer
+      locals = addr(locals)
+      setStackBottom(locals)
 
   var
     strDesc: TNimType
@@ -1868,7 +1869,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   when hasThreadSupport:
     include "system/syslocks"
     include "system/threads"
-  else:
+  elif not defined(nogc):
     initStackBottom()
     initGC()
 
@@ -1881,21 +1882,23 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     ## for debug builds.
     
   {.push stack_trace: off.}
-  include "system/excpt"
+  when hostCPU == "avr":
+    include "system/embedded"
+  else:
+    include "system/excpt"
+    
   # we cannot compile this with stack tracing on
   # as it would recurse endlessly!
   include "system/arithm"
   {.pop.} # stack trace
   {.pop.} # stack trace
       
-  include "system/dyncalls"
+  when hostOS != "standalone": include "system/dyncalls"
   include "system/sets"
 
   const
     GenericSeqSize = (2 * sizeof(int))
     
-  proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
-
   proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
     sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
     var d: int
@@ -1918,7 +1921,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
 
   include "system/mmdisp"
   {.push stack_trace: off.}
-  include "system/sysstr"
+  when hostCPU != "avr": include "system/sysstr"
   {.pop.}
 
   include "system/sysio"
@@ -1938,18 +1941,19 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     var res = TaintedString(newStringOfCap(80))
     while f.readLine(res): yield TaintedString(res)
 
-  include "system/assign"
-  include "system/repr"
+  when hostCPU != "avr":
+    include "system/assign"
+    include "system/repr"
 
-  proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
-    ## retrieves the current exception; if there is none, nil is returned.
-    result = currException
+    proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} =
+      ## retrieves the current exception; if there is none, nil is returned.
+      result = currException
 
-  proc getCurrentExceptionMsg*(): string {.inline.} =
-    ## retrieves the error message that was attached to the current
-    ## exception; if there is none, "" is returned.
-    var e = getCurrentException()
-    return if e == nil: "" else: e.msg
+    proc getCurrentExceptionMsg*(): string {.inline.} =
+      ## retrieves the error message that was attached to the current
+      ## exception; if there is none, "" is returned.
+      var e = getCurrentException()
+      return if e == nil: "" else: e.msg
 
   {.push stack_trace: off.}
   when defined(endb):
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 9722e1396..e328f7099 100755
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -103,4 +103,3 @@ proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.}
 proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
 
 {.pop}
-
diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim
new file mode 100644
index 000000000..f17432561
--- /dev/null
+++ b/lib/system/embedded.nim
@@ -0,0 +1,106 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Bare-bones implementation of some things for embedded targets.
+
+proc writeToStdErr(msg: CString) = write(stdout, msg)
+
+proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
+proc chckRange(i, a, b: int): int {.inline, compilerproc.}
+proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
+proc chckNil(p: pointer) {.inline, compilerproc.}
+
+proc pushFrame(s: PFrame) {.compilerRtl, inl.} = nil
+proc popFrame {.compilerRtl, inl.} = nil
+
+proc setFrame(s: PFrame) {.compilerRtl, inl.} = nil
+proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = nil
+proc popSafePoint {.compilerRtl, inl.} = nil
+proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = nil
+proc popCurrentException {.compilerRtl, inl.} = nil
+
+# some platforms have native support for stack traces:
+const
+  nativeStackTraceSupported = false
+  hasSomeStackTrace = false
+
+proc quitOrDebug() {.inline.} =
+  quit(1)
+
+proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
+  writeToStdErr(ename)
+ 
+proc reraiseException() {.compilerRtl.} =
+  writeToStdErr("reraise not supported")
+
+proc WriteStackTrace() = nil
+
+proc setControlCHook(hook: proc () {.noconv.}) =
+  # ugly cast, but should work on all architectures:
+  type TSignalHandler = proc (sig: cint) {.noconv.}
+  c_signal(SIGINT, cast[TSignalHandler](hook))
+
+proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("value out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+  writeToStdErr("field is not accessible")
+
+proc chckIndx(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseIndexError()
+
+proc chckRange(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRangeF(x, a, b: float): float =
+  if x >= a and x <= b:
+    return x
+  else:
+    raise newException(EOutOfRange, "value " & $x & " out of range")
+
+proc chckNil(p: pointer) =
+  if p == nil: c_raise(SIGSEGV)
+
+proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return # optimized fast path
+  while x != subclass:
+    if x == nil:
+      raise newException(EInvalidObjectConversion, "invalid object conversion")
+    x = x.base
+
+proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
+  if a != b:
+    raise newException(EInvalidObjectAssignment, "invalid object assignment")
+
+proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return true # optimized fast path
+  while x != subclass:
+    if x == nil: return false
+    x = x.base
+  return true
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 8ffca90fb..2df7fe4ad 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -27,7 +27,7 @@ else:
   proc writeToStdErr(msg: CString) =
     discard MessageBoxA(0, msg, nil, 0)
 
-proc registerSignalHandler() {.compilerproc.}
+proc registerSignalHandler()
 
 proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
 proc chckRange(i, a, b: int): int {.inline, compilerproc.}
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index e8ad23970..1abf3fbbf 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -181,6 +181,78 @@ when defined(boehmgc):
   proc deallocOsPages() {.inline.} = nil
 
   include "system/cellsets"
+elif defined(nogc) and defined(useMalloc):
+  
+  when not defined(useNimRtl):
+    proc alloc(size: int): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc alloc0(size: int): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc realloc(p: Pointer, newsize: int): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc dealloc(p: Pointer) = cfree(p)
+    
+    proc allocShared(size: int): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc allocShared0(size: int): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc reallocShared(p: Pointer, newsize: int): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc deallocShared(p: Pointer) = cfree(p)
+
+    proc GC_disable() = nil
+    proc GC_enable() = nil
+    proc GC_fullCollect() = nil
+    proc GC_setStrategy(strategy: TGC_Strategy) = nil
+    proc GC_enableMarkAndSweep() = nil
+    proc GC_disableMarkAndSweep() = nil
+    proc GC_getStatistics(): string = return ""
+    
+    proc getOccupiedMem(): int = nil
+    proc getFreeMem(): int = nil
+    proc getTotalMem(): int = nil
+    
+    proc setStackBottom(theStackBottom: pointer) = nil
+
+  proc initGC() = nil
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  type
+    TMemRegion = object {.final, pure.}
+  
+  proc Alloc(r: var TMemRegion, size: int): pointer =
+    result = alloc(size)
+  proc Alloc0(r: var TMemRegion, size: int): pointer =
+    result = alloc0(size)
+  proc Dealloc(r: var TMemRegion, p: Pointer) = Dealloc(p)
+  proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
+  proc deallocOsPages() {.inline.} = nil
+
 elif defined(nogc):
   # Even though we don't want the GC, we cannot simply use C's memory manager
   # because Nimrod's runtime wants ``realloc`` to zero out the additional
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 2dec8136c..ec02f5e08 100755
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -9,6 +9,9 @@
 
 # The generic ``repr`` procedure. It is an invaluable debugging tool.
 
+when not defined(useNimRtl):
+  proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
+
 proc reprInt(x: int64): string {.compilerproc.} = return $x
 proc reprFloat(x: float): string {.compilerproc.} = return $x