Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Andreas Rumpf 2016-04-19 12:11:18 +02:00
commit ef9a9b119d
35 changed files with 590 additions and 176 deletions

View file

@ -796,17 +796,17 @@ proc infix*(a: NimNode; op: string;
proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} =
node.expectKind nnkPostfix
result = (node[0], $node[1])
result = (node[1], $node[0])
proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} =
node.expectKind nnkPrefix
result = (node[0], $node[1])
result = (node[1], $node[0])
proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
right: NimNode] {.compileTime.} =
assert node.kind == nnkInfix
result = (node[0], $node[1], node[2])
result = (node[1], $node[0], node[2])
proc copy*(node: NimNode): NimNode {.compileTime.} =
## An alias for copyNimTree().

View file

@ -105,7 +105,8 @@ else:
proc readLineFromStdin*(prompt: string): TaintedString {.
tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt)
if isNil(buffer): quit(0)
if isNil(buffer):
raise newException(IOError, "Linenoise returned nil")
result = TaintedString($buffer)
if result.string.len > 0:
historyAdd(buffer)
@ -114,12 +115,12 @@ else:
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt)
if isNil(buffer): quit(0)
if isNil(buffer):
raise newException(IOError, "Linenoise returned nil")
line = TaintedString($buffer)
if line.string.len > 0:
historyAdd(buffer)
linenoise.free(buffer)
# XXX how to determine CTRL+D?
result = true
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):

View file

@ -9,6 +9,9 @@
## This module provides an easy to use sockets-style
## nim interface to the OpenSSL library.
##
## **Warning:** This module is deprecated, use the SSL procedures defined in
## the ``net`` module instead.
{.deprecated.}

View file

@ -222,6 +222,8 @@ __clang__
/* ----------------------------------------------------------------------- */
#define COMMA ,
#include <limits.h>
#include <stddef.h>

View file

@ -2627,3 +2627,17 @@ proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {.
## Returns zero on success.
##
## For more information read http://www.unix.com/man-page/posix/3/utimes/.
proc handle_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.importc: "signal", header: "<signal.h>".}
template onSignal*(signals: varargs[cint], body: untyped): stmt =
## Setup code to be executed when Unix signals are received. Example:
## from posix import SIGINT, SIGTERM
## onSignal(SIGINT, SIGTERM):
## echo "bye"
for s in signals:
handle_signal(s,
proc (sig: cint) {.noconv.} =
body
)

View file

@ -1316,6 +1316,23 @@ proc generateExceptionCheck(futSym,
)
result.add elseNode
template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver,
rootReceiver: expr, fromNode: NimNode) =
## Params:
## futureVarNode: The NimNode which is a symbol identifying the Future[T]
## variable to yield.
## fromNode: Used for better debug information (to give context).
## valueReceiver: The node which defines an expression that retrieves the
## future's value.
##
## rootReceiver: ??? TODO
# -> yield future<x>
result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode)
# -> future<x>.read
valueReceiver = newDotExpr(futureVarNode, newIdentNode("read"))
result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver,
fromNode)
template createVar(result: var NimNode, futSymName: string,
asyncProc: NimNode,
valueReceiver, rootReceiver: expr,
@ -1323,9 +1340,7 @@ template createVar(result: var NimNode, futSymName: string,
result = newNimNode(nnkStmtList, fromNode)
var futSym = genSym(nskVar, "future")
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
useVar(result, futSym, valueReceiver, rootReceiver, fromNode)
proc processBody(node, retFutureSym: NimNode,
subTypeIsVoid: bool,
@ -1352,7 +1367,11 @@ proc processBody(node, retFutureSym: NimNode,
case node[1].kind
of nnkIdent, nnkInfix:
# await x
result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
result = newNimNode(nnkStmtList, node)
var futureValue: NimNode
result.useVar(node[1], futureValue, futureValue, node)
# -> yield x
# -> x.read()
of nnkCall, nnkCommand:
# await foo(p, x)
var futureValue: NimNode
@ -1550,6 +1569,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
for i in 0 .. <result[4].len:
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
result[4].del(i)
result[4] = newEmptyNode()
if subtypeIsVoid:
# Add discardable pragma.
if returnType.kind == nnkEmpty:
@ -1559,7 +1579,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
result[6] = outerProcBody
#echo(treeRepr(result))
#if prc[0].getName == "hubConnectionLoop":
#if prc[0].getName == "g":
# echo(toStrLit(result))
macro async*(prc: stmt): stmt {.immediate.} =

View file

@ -162,7 +162,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
# Request completed immediately.
var bytesRead: DWord
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesRead, false.WinBool)
cast[POverlapped](ol), bytesRead, false.WinBool)
if not overlappedRes.bool:
let err = osLastError()
if err.int32 == ERROR_HANDLE_EOF:
@ -282,7 +282,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
# Request completed immediately.
var bytesWritten: DWord
let overlappedRes = getOverlappedResult(f.fd.Handle,
cast[POverlapped](ol)[], bytesWritten, false.WinBool)
cast[POverlapped](ol), bytesWritten, false.WinBool)
if not overlappedRes.bool:
retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
else:

View file

@ -11,7 +11,7 @@
## asynchronous dispatcher defined in the ``asyncdispatch`` module.
##
## SSL
## ---
## ----
##
## SSL can be enabled by compiling with the ``-d:ssl`` flag.
##
@ -62,7 +62,9 @@ import os
export SOBool
when defined(ssl):
const defineSsl = defined(ssl) or defined(nimdoc)
when defineSsl:
import openssl
type
@ -79,7 +81,7 @@ type
of false: nil
case isSsl: bool
of true:
when defined(ssl):
when defineSsl:
sslHandle: SslPtr
sslContext: SslContext
bioIn: BIO
@ -125,7 +127,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint,
Domain(domain), SockType(sockType),
Protocol(protocol), buffered)
when defined(ssl):
when defineSsl:
proc getSslError(handle: SslPtr, err: cint): cint =
assert err < 0
var ret = SSLGetError(handle, err.cint)
@ -186,7 +188,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} =
## or an error occurs.
await connect(socket.fd.AsyncFD, address, port, socket.domain)
if socket.isSsl:
when defined(ssl):
when defineSsl:
let flags = {SocketFlag.SafeDisconn}
sslSetConnectState(socket.sslHandle)
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
@ -197,7 +199,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket,
## this is a template and not a proc.
var res = 0
if socket.isSsl:
when defined(ssl):
when defineSsl:
# SSL mode.
sslLoop(socket, flags,
sslRead(socket.sslHandle, buf, size.cint))
@ -274,7 +276,7 @@ proc send*(socket: AsyncSocket, data: string,
## data has been sent.
assert socket != nil
if socket.isSsl:
when defined(ssl):
when defineSsl:
var copy = data
sslLoop(socket, flags,
sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
@ -426,9 +428,6 @@ proc recvLine*(socket: AsyncSocket,
##
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
## uses ``\r\L`` to delimit a new line.
template addNLIfEmpty(): stmt =
if result.len == 0:
result.add("\c\L")
assert SocketFlag.Peek notin flags ## TODO:
# TODO: Optimise this
@ -456,7 +455,8 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
of AF_INET6: realaddr = "::"
of AF_INET: realaddr = "0.0.0.0"
else:
raiseOSError("Unknown socket address family and no address specified to bindAddr")
raise newException(ValueError,
"Unknown socket address family and no address specified to bindAddr")
var aiList = getAddrInfo(realaddr, port, socket.domain)
if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
@ -468,7 +468,7 @@ proc close*(socket: AsyncSocket) =
## Closes the socket.
defer:
socket.fd.AsyncFD.closeSocket()
when defined(ssl):
when defineSsl:
if socket.isSSL:
let res = SslShutdown(socket.sslHandle)
SSLFree(socket.sslHandle)
@ -478,7 +478,7 @@ proc close*(socket: AsyncSocket) =
raiseSslError()
socket.closed = true # TODO: Add extra debugging checks for this.
when defined(ssl):
when defineSsl:
proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
## Wraps a socket in an SSL context. This function effectively turns
## ``socket`` into an SSL socket.

View file

@ -90,6 +90,8 @@ template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediat
if r+4 != result.len:
setLen(result, r+4)
else:
if r != result.len:
setLen(result, r)
#assert(r == result.len)
discard
@ -162,4 +164,3 @@ when isMainModule:
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t

View file

@ -663,6 +663,27 @@ proc sort*[A, B](t: OrderedTableRef[A, B],
## contrast to the `sort` for count tables).
t[].sort(cmp)
proc del*[A, B](t: var OrderedTable[A, B], key: A) =
## deletes `key` from ordered hash table `t`. O(n) comlexity.
var prev = -1
let hc = hash(key)
forAllOrderedPairs:
if t.data[h].hcode == hc:
if t.first == h:
t.first = t.data[h].next
else:
t.data[prev].next = t.data[h].next
var zeroValue : type(t.data[h])
t.data[h] = zeroValue
dec t.counter
break
else:
prev = h
proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
## deletes `key` from ordered hash table `t`. O(n) comlexity.
t[].del(key)
# ------------------------------ count tables -------------------------------
type
@ -984,6 +1005,26 @@ when isMainModule:
s3[p1] = 30_000
s3[p2] = 45_000
block: # Ordered table should preserve order after deletion
var
s4 = initOrderedTable[int, int]()
s4[1] = 1
s4[2] = 2
s4[3] = 3
var prev = 0
for i in s4.values:
doAssert(prev < i)
prev = i
s4.del(2)
doAssert(2 notin s4)
doAssert(s4.len == 2)
prev = 0
for i in s4.values:
doAssert(prev < i)
prev = i
var
t1 = initCountTable[string]()
t2 = initCountTable[string]()

View file

@ -335,7 +335,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
var m = newMimetypes()
for name, file in xs.items:
var contentType: string
let (dir, fName, ext) = splitFile(file)
let (_, fName, ext) = splitFile(file)
if ext.len > 0:
contentType = m.getMimetype(ext[1..ext.high], nil)
p.add(name, readFile(file), fName & ext, contentType)
@ -627,7 +627,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent,
result.userAgent = defUserAgent
result.maxRedirects = maxRedirects
when defined(ssl):
result.sslContext = net.SslContext(sslContext)
result.sslContext = sslContext
proc close*(client: AsyncHttpClient) =
## Closes any connections held by the HTTP client.

View file

@ -56,6 +56,11 @@ import
export
tables.`$`
when defined(nimJsonGet):
{.pragma: deprecatedGet, deprecated.}
else:
{.pragma: deprecatedGet.}
type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
jsonError, ## an error occurred during parsing
@ -799,16 +804,23 @@ proc len*(n: JsonNode): int =
of JObject: result = n.fields.len
else: discard
proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
proc `[]`*(node: JsonNode, name: string): JsonNode {.inline, deprecatedGet.} =
## Gets a field from a `JObject`, which must not be nil.
## If the value at `name` does not exist, returns nil
## If the value at `name` does not exist, raises KeyError.
##
## **Note:** The behaviour of this procedure changed in version 0.14.0. To
## get a list of usages and to restore the old behaviour of this procedure,
## compile with the ``-d:nimJsonGet`` flag.
assert(not isNil(node))
assert(node.kind == JObject)
result = node.fields.getOrDefault(name)
when defined(nimJsonGet):
if not node.fields.hasKey(name): return nil
result = node.fields[name]
proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
## Gets the node at `index` in an Array. Result is undefined if `index`
## is out of bounds
## is out of bounds, but as long as array bound checks are enabled it will
## result in an exception.
assert(not isNil(node))
assert(node.kind == JArray)
return node.elems[index]
@ -838,20 +850,28 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
## Traverses the node and gets the given value. If any of the
## keys do not exist, returns nil. Also returns nil if one of the
## intermediate data structures is not an object
## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the
## intermediate data structures is not an object.
result = node
for key in keys:
if isNil(result) or result.kind!=JObject:
if isNil(result) or result.kind != JObject:
return nil
result=result[key]
result = result.fields.getOrDefault(key)
proc getOrDefault*(node: JsonNode, key: string): JsonNode =
## Gets a field from a `node`. If `node` is nil or not an object or
## value at `key` does not exist, returns nil
if not isNil(node) and node.kind == JObject:
result = node.fields.getOrDefault(key)
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key)
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
## Traverses the node and tries to set the value at the given location
## to `value` If any of the keys are missing, they are added
## to ``value``. If any of the keys are missing, they are added.
var node = node
for i in 0..(keys.len-2):
if isNil(node[keys[i]]):
if not node.hasKey(keys[i]):
node[keys[i]] = newJObject()
node = node[keys[i]]
node[keys[keys.len-1]] = value
@ -1217,16 +1237,6 @@ when false:
# To get that we shall use, obj["json"]
when isMainModule:
when not defined(js):
var parsed = parseFile("tests/testdata/jsontest.json")
try:
discard parsed["key2"][12123]
doAssert(false)
except IndexError: doAssert(true)
var parsed2 = parseFile("tests/testdata/jsontest2.json")
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
# nil passthrough
@ -1314,3 +1324,19 @@ when isMainModule:
var j4 = %*{"test": nil}
doAssert j4 == %{"test": newJNull()}
echo("99% of tests finished. Going to try loading file.")
# Test loading of file.
when not defined(js):
var parsed = parseFile("tests/testdata/jsontest.json")
try:
discard parsed["key2"][12123]
doAssert(false)
except IndexError: doAssert(true)
var parsed2 = parseFile("tests/testdata/jsontest2.json")
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
echo("Tests succeeded!")

View file

@ -8,6 +8,10 @@
#
## This module contains various string matchers for email addresses, etc.
##
## **Warning:** This module is deprecated since version 0.14.0.
{.deprecated.}
{.deadCodeElim: on.}
{.push debugger:off .} # the user does not want to trace a part

View file

@ -8,19 +8,76 @@
#
## This module implements a high-level cross-platform sockets interface.
## The procedures implemented in this module are primarily for blocking sockets.
## For asynchronous non-blocking sockets use the ``asyncnet`` module together
## with the ``asyncdispatch`` module.
##
## The first thing you will always need to do in order to start using sockets,
## is to create a new instance of the ``Socket`` type using the ``newSocket``
## procedure.
##
## SSL
## ====
##
## In order to use the SSL procedures defined in this module, you will need to
## compile your application with the ``-d:ssl`` flag.
##
## Examples
## ========
##
## Connecting to a server
## ----------------------
##
## After you create a socket with the ``newSocket`` procedure, you can easily
## connect it to a server running at a known hostname (or IP address) and port.
## To do so over TCP, use the example below.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.connect("google.com", Port(80))
##
## UDP is a connectionless protocol, so UDP sockets don't have to explicitly
## call the ``connect`` procedure. They can simply start sending data
## immediately.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.sendTo("192.168.0.1", Port(27960), "status\n")
##
## Creating a server
## -----------------
##
## After you create a socket with the ``newSocket`` procedure, you can create a
## TCP server by calling the ``bindAddr`` and ``listen`` procedures.
##
## .. code-block:: Nim
## var socket = newSocket()
## socket.bindAddr(Port(1234))
## socket.listen()
##
## You can then begin accepting connections using the ``accept`` procedure.
##
## .. code-block:: Nim
## var client = newSocket()
## var address = ""
## while true:
## socket.acceptAddr(client, address)
## echo("Client connected from: ", address)
##
{.deadCodeElim: on.}
import nativesockets, os, strutils, parseutils, times
export Port, `$`, `==`
const useWinVersion = defined(Windows) or defined(nimdoc)
const defineSsl = defined(ssl) or defined(nimdoc)
when defined(ssl):
when defineSsl:
import openssl
# Note: The enumerations are mapped to Window's constants.
when defined(ssl):
when defineSsl:
type
SslError* = object of Exception
@ -54,7 +111,7 @@ type
currPos: int # current index in buffer
bufLen: int # current length of buffer
of false: nil
when defined(ssl):
when defineSsl:
case isSsl: bool
of true:
sslHandle: SSLPtr
@ -160,7 +217,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
raiseOSError(osLastError())
result = newSocket(fd, domain, sockType, protocol, buffered)
when defined(ssl):
when defineSsl:
CRYPTO_malloc_init()
SslLibraryInit()
SslLoadErrorStrings()
@ -301,7 +358,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
## error was caused by no data being available to be read.
##
## If ``err`` is not lower than 0 no exception will be raised.
when defined(ssl):
when defineSsl:
if socket.isSSL:
if err <= 0:
var ret = SSLGetError(socket.sslHandle, err.cint)
@ -334,7 +391,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
raiseSSLError()
else: raiseSSLError("Unknown Error")
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
if err == -1 and not (when defineSsl: socket.isSSL else: false):
var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
if async:
when useWinVersion:
@ -414,7 +471,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
client.isBuffered = server.isBuffered
# Handle SSL.
when defined(ssl):
when defineSsl:
if server.isSSL:
# We must wrap the client sock in a ssl context.
@ -425,7 +482,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
# Client socket is set above.
address = $inet_ntoa(sockAddress.sin_addr)
when false: #defined(ssl):
when false: #defineSsl:
proc acceptAddrSSL*(server: Socket, client: var Socket,
address: var string): SSLAcceptResult {.
tags: [ReadIOEffect].} =
@ -444,7 +501,7 @@ when false: #defined(ssl):
## ``AcceptNoClient`` will be returned when no client is currently attempting
## to connect.
template doHandshake(): stmt =
when defined(ssl):
when defineSsl:
if server.isSSL:
client.setBlocking(false)
# We must wrap the client sock in a ssl context.
@ -495,7 +552,7 @@ proc accept*(server: Socket, client: var Socket,
proc close*(socket: Socket) =
## Closes a socket.
try:
when defined(ssl):
when defineSsl:
if socket.isSSL:
ErrClearError()
# As we are closing the underlying socket immediately afterwards,
@ -547,8 +604,9 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {
var valuei = cint(if value: 1 else: 0)
setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
when defined(ssl):
proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
when defineSsl:
proc handshake*(socket: Socket): bool
{.tags: [ReadIOEffect, WriteIOEffect], deprecated.} =
## This proc needs to be called on a socket after it connects. This is
## only applicable when using ``connectAsync``.
## This proc performs the SSL handshake.
@ -557,6 +615,8 @@ when defined(ssl):
## ``True`` whenever handshake completed successfully.
##
## A ESSL error is raised on any other errors.
##
## **Note:** This procedure is deprecated since version 0.14.0.
result = true
if socket.isSSL:
var ret = SSLConnect(socket.sslHandle)
@ -594,7 +654,7 @@ proc hasDataBuffered*(s: Socket): bool =
if s.isBuffered:
result = s.bufLen > 0 and s.currPos != s.bufLen
when defined(ssl):
when defineSsl:
if s.isSSL and not result:
result = s.sslHasPeekChar
@ -608,7 +668,7 @@ proc select(readfd: Socket, timeout = 500): int =
proc readIntoBuf(socket: Socket, flags: int32): int =
result = 0
when defined(ssl):
when defineSsl:
if socket.isSSL:
result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
else:
@ -658,7 +718,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
result = read
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
if socket.sslHasPeekChar:
copyMem(data, addr(socket.sslPeekChar), 1)
@ -696,7 +756,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
if timeout - int(waited * 1000.0) < 1:
raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
when defined(ssl):
when defineSsl:
if socket.isSSL:
if socket.hasDataBuffered:
# sslPeekChar is present.
@ -764,7 +824,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
c = socket.buffer[socket.currPos]
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
if not socket.sslHasPeekChar:
result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
@ -872,7 +932,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {.
##
## **Note**: This is a low-level version of ``send``. You likely should use
## the version below.
when defined(ssl):
when defineSsl:
if socket.isSSL:
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
@ -943,7 +1003,7 @@ proc sendTo*(socket: Socket, address: string, port: Port,
proc isSsl*(socket: Socket): bool =
## Determines whether ``socket`` is a SSL socket.
when defined(ssl):
when defineSsl:
result = socket.isSSL
else:
result = false
@ -1253,7 +1313,7 @@ proc connect*(socket: Socket, address: string,
dealloc(aiList)
if not success: raiseOSError(lastError)
when defined(ssl):
when defineSsl:
if socket.isSSL:
# RFC3546 for SNI specifies that IP addresses are not allowed.
if not isIpAddress(address):
@ -1314,8 +1374,10 @@ proc connect*(socket: Socket, address: string, port = Port(0),
if selectWrite(s, timeout) != 1:
raise newException(TimeoutError, "Call to 'connect' timed out.")
else:
when defined(ssl):
when defineSsl:
if socket.isSSL:
socket.fd.setBlocking(true)
{.warning[Deprecated]: off.}
doAssert socket.handshake()
{.warning[Deprecated]: on.}
socket.fd.setBlocking(true)

View file

@ -129,7 +129,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
if additionalInfo.len == 0:
e.msg = osErrorMsg(errorCode)
else:
e.msg = additionalInfo & " " & osErrorMsg(errorCode)
e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo
if e.msg == "":
e.msg = "unknown OS error"
raise e
@ -1452,7 +1452,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr =
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'Stat' structure on posix
when defined(Windows):
template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
template toTime(e: FILETIME): expr {.gensym.} = winTimeToUnixTime(rdFileTime(e)) # local templates default to bind semantics
template merge(a, b): expr = a or (b shl 32)
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)

View file

@ -784,8 +784,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
{.noSideEffect, rtl, extern: "nsuIndent".} =
## Indents each line in ``s`` by ``count`` amount of ``padding``.
##
## **Note:** This currently does not preserve the specific new line characters
## used.
## **Note:** This does not preserve the new line characters used in ``s``.
result = ""
var i = 0
for line in s.splitLines():
@ -796,32 +795,39 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
result.add(line)
i.inc
proc unindent*(s: string, eatAllIndent = false): string {.
noSideEffect, rtl, extern: "nsuUnindent".} =
## Unindents `s`.
result = newStringOfCap(s.len)
proc unindent*(s: string, count: Natural, padding: string = " "): string
{.noSideEffect, rtl, extern: "nsuUnindent".} =
## Unindents each line in ``s`` by ``count`` amount of ``padding``.
##
## **Note:** This does not preserve the new line characters used in ``s``.
result = ""
var i = 0
var pattern = true
var indent = 0
while s[i] == ' ': inc i
var level = if i == 0: -1 else: i
while i < s.len:
if s[i] == ' ':
if i > 0 and s[i-1] in {'\l', '\c'}:
pattern = true
indent = 0
if pattern:
inc(indent)
if indent > level and not eatAllIndent:
result.add(s[i])
if level < 0: level = indent
else:
# a space somewhere: do not delete
result.add(s[i])
else:
pattern = false
result.add(s[i])
inc i
for line in s.splitLines():
if i != 0:
result.add("\n")
var indentCount = 0
for j in 0..<count.int:
indentCount.inc
if line[j .. j + <padding.len] != padding:
indentCount = j
break
result.add(line[indentCount*padding.len .. ^1])
i.inc
proc unindent*(s: string): string
{.noSideEffect, rtl, extern: "nsuUnindentAll".} =
## Removes all indentation composed of whitespace from each line in ``s``.
##
## For example:
##
## .. code-block:: nim
## const x = """
## Hello
## There
## """.unindent()
##
## doAssert x == "Hello\nThere\n"
unindent(s, 1000) # TODO: Passing a 1000 is a bit hackish.
proc startsWith*(s, prefix: string): bool {.noSideEffect,
rtl, extern: "nsuStartsWith".} =
@ -1743,3 +1749,33 @@ when isMainModule:
doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
doAssert join([1, 2, 3]) == "123"
doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
doAssert """~~!!foo
~~!!bar
~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
doAssert """~~!!foo
~~!!bar
~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
doAssert """~~foo
~~ bar
~~ baz""".unindent(4, "~") == "foo\n bar\n baz"
doAssert """foo
bar
baz
""".unindent(4) == "foo\nbar\nbaz\n"
doAssert """foo
bar
baz
""".unindent(2) == "foo\n bar\n baz\n"
doAssert """foo
bar
baz
""".unindent(100) == "foo\nbar\nbaz\n"
doAssert """foo
foo
bar
""".unindent() == "foo\nfoo\nbar\n"
echo("strutils tests passed")

View file

@ -390,11 +390,11 @@ when isMainModule:
doAssert(("type MyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") ==
strutils.unindent """
strutils.unindent("""
type MyEnum* = enum
fieldA, fieldB,
FiledClkad, fieldD,
fieldE, longishFieldName""")
fieldE, longishFieldName""", 6))
doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
@ -404,8 +404,8 @@ when isMainModule:
doAssert((subex("type\n Enum = enum\n $', '40c'\n '{..}") % [
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") ==
strutils.unindent """
strutils.unindent("""
type
Enum = enum
fieldNameA, fieldNameB, fieldNameC,
fieldNameD""")
fieldNameD""", 6))

View file

@ -182,7 +182,16 @@ proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign, deprecated.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
## them from the other information in the broken-down time structure.
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``toTime`` instead.
proc toTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
@ -356,7 +365,7 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
##
## **Note:** This has been only briefly tested and it may not be
## very accurate.
let t = toSeconds(timeInfoToTime(a))
let t = toSeconds(toTime(a))
let secs = toSeconds(a, interval)
result = getLocalTime(fromSeconds(t + secs))
@ -365,7 +374,7 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
##
## **Note:** This has been only briefly tested, it is inaccurate especially
## when you subtract so much that you reach the Julian calendar.
let t = toSeconds(timeInfoToTime(a))
let t = toSeconds(toTime(a))
var intval: TimeInterval
intval.milliseconds = - interval.milliseconds
intval.seconds = - interval.seconds
@ -517,6 +526,11 @@ when not defined(JS):
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc toTime(timeInfo: TimeInfo): Time =
var cTimeInfo = timeInfo # for C++ we have to make a copy,
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
proc toStringTillNL(p: cstring): string =
result = ""
var i = 0
@ -618,7 +632,16 @@ elif defined(JS):
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
proc toTime*(timeInfo: TimeInfo): Time =
result = internGetTime()
result.setSeconds(timeInfo.second)
result.setMinutes(timeInfo.minute)
result.setHours(timeInfo.hour)
result.setMonth(ord(timeInfo.month))
result.setFullYear(timeInfo.year)
result.setDate(timeInfo.monthday)
proc `$`(timeInfo: TimeInfo): string = return $(toTime(timeInfo))
proc `$`(time: Time): string = return $time.toLocaleString()
proc `-` (a, b: Time): int64 =
@ -708,24 +731,24 @@ proc years*(y: int): TimeInterval {.inline.} =
proc `+=`*(t: var Time, ti: TimeInterval) =
## modifies `t` by adding the interval `ti`
t = timeInfoToTime(getLocalTime(t) + ti)
t = toTime(getLocalTime(t) + ti)
proc `+`*(t: Time, ti: TimeInterval): Time =
## adds the interval `ti` to Time `t`
## by converting to localTime, adding the interval, and converting back
##
## ``echo getTime() + 1.day``
result = timeInfoToTime(getLocalTime(t) + ti)
result = toTime(getLocalTime(t) + ti)
proc `-=`*(t: var Time, ti: TimeInterval) =
## modifies `t` by subtracting the interval `ti`
t = timeInfoToTime(getLocalTime(t) - ti)
t = toTime(getLocalTime(t) - ti)
proc `-`*(t: Time, ti: TimeInterval): Time =
## adds the interval `ti` to Time `t`
##
## ``echo getTime() - 1.day``
result = timeInfoToTime(getLocalTime(t) - ti)
result = toTime(getLocalTime(t) - ti)
proc formatToken(info: TimeInfo, token: string, buf: var string) =
## Helper of the format proc to parse individual tokens.
@ -1193,7 +1216,7 @@ proc parse*(value, layout: string): TimeInfo =
parseToken(info, token, value, j)
token = ""
# Reset weekday as it might not have been provided and the default may be wrong
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
info.weekday = getLocalTime(toTime(info)).weekday
return info
# Leap year calculations are adapted from:
@ -1204,7 +1227,7 @@ proc parse*(value, layout: string): TimeInfo =
proc countLeapYears*(yearSpan: int): int =
## Returns the number of leap years spanned by a given number of years.
##
## Note: for leap years, start date is assumed to be 1 AD.
## **Note:** For leap years, start date is assumed to be 1 AD.
## counts the number of leap years up to January 1st of a given year.
## Keep in mind that if specified year is a leap year, the leap day
## has not happened before January 1st of that year.
@ -1239,13 +1262,14 @@ proc getDayOfWeek*(day, month, year: int): WeekDay =
y = year - a
m = month + (12*a) - 2
d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct
# for the WeekDay type.
# The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
# so we must correct for the WeekDay type.
if d == 0: return dSun
result = (d-1).WeekDay
proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
## Returns the day of the week enum from day, month and year, according to the Julian calendar.
## Returns the day of the week enum from day, month and year,
## according to the Julian calendar.
# Day & month start from one.
let
a = (14 - month) div 12
@ -1254,8 +1278,11 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay =
d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7
result = d.WeekDay
proc timeToTimeInfo*(t: Time): TimeInfo =
proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} =
## Converts a Time to TimeInfo.
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``getLocalTime`` or ``getGMTime`` instead.
let
secs = t.toSeconds().int
daysSinceEpoch = secs div secondsInDay
@ -1286,34 +1313,21 @@ proc timeToTimeInfo*(t: Time): TimeInfo =
s = daySeconds mod secondsInMin
result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s)
proc timeToTimeInterval*(t: Time): TimeInterval =
proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} =
## Converts a Time to a TimeInterval.
let
secs = t.toSeconds().int
daysSinceEpoch = secs div secondsInDay
(yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch)
daySeconds = secs mod secondsInDay
result.years = yearsSinceEpoch + epochStartYear
var
mon = mJan
days = daysRemaining
daysInMonth = getDaysInMonth(mon, result.years)
# calculate month and day remainder
while days > daysInMonth and mon <= mDec:
days -= daysInMonth
mon.inc
daysInMonth = getDaysInMonth(mon, result.years)
result.months = mon.int + 1 # month is 1 indexed int
result.days = days
result.hours = daySeconds div secondsInHour + 1
result.minutes = (daySeconds mod secondsInHour) div secondsInMin
result.seconds = daySeconds mod secondsInMin
##
## **Warning:** This procedure is deprecated since version 0.14.0.
## Use ``toTimeInterval`` instead.
# Milliseconds not available from Time
var tInfo = t.getLocalTime()
initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
proc toTimeInterval*(t: Time): TimeInterval =
## Converts a Time to a TimeInterval.
# Milliseconds not available from Time
var tInfo = t.getLocalTime()
initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year)
when isMainModule:
# this is testing non-exported function

View file

@ -28,6 +28,9 @@ template mulThreshold(x): expr {.immediate.} = x * 2
when defined(memProfiler):
proc nimProfile(requestedSize: int)
when hasThreadSupport:
import sharedlist
type
WalkOp = enum

View file

@ -769,7 +769,7 @@ proc getQueuedCompletionStatus*(CompletionPort: Handle,
dwMilliseconds: DWORD): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
proc getOverlappedResult*(hFile: Handle, lpOverlapped: OVERLAPPED,
proc getOverlappedResult*(hFile: Handle, lpOverlapped: POVERLAPPED,
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}

View file

@ -260,7 +260,7 @@ proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSS
proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
when not useWinVersion:
when not useWinVersion and not defined(macosx):
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl,
dynlib: DLLUtilName, importc.}
@ -532,7 +532,7 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
result = hexStr(buf)
proc md5_Str* (str:string): string {.raises:[IOError].} =
proc md5_Str*(str:string): string =
##Generate MD5 hash for a string. Result is a 32 character
#hex string with lowercase characters
var