mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-28 19:36:34 +00:00
Merge branch 'master' of github.com:Araq/Nimrod into upstream
This commit is contained in:
@@ -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``.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -103,4 +103,3 @@ proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.}
|
||||
proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
|
||||
|
||||
{.pop}
|
||||
|
||||
|
||||
106
lib/system/embedded.nim
Normal file
106
lib/system/embedded.nim
Normal file
@@ -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
|
||||
@@ -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.}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user