diff options
author | Araq <rumpf_a@web.de> | 2017-03-14 15:56:08 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2017-03-14 15:56:08 +0100 |
commit | b1c494a1504921a21f5578782db72f274efadd95 (patch) | |
tree | b26c5e92edbc87e8f38cb8994e6e01f897d77494 /lib | |
parent | 142b604c1353926208220aa7ce0b7724a72958c3 (diff) | |
parent | 0510c0cecefb50dedd691de82151bc629b35d816 (diff) | |
download | Nim-b1c494a1504921a21f5578782db72f274efadd95.tar.gz |
Merge branch 'devel' of github.com:nim-lang/Nim into devel
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/collections/critbits.nim | 3 | ||||
-rw-r--r-- | lib/pure/collections/sequtils.nim | 3 | ||||
-rw-r--r-- | lib/pure/memfiles.nim | 28 | ||||
-rw-r--r-- | lib/pure/ospaths.nim | 4 | ||||
-rw-r--r-- | lib/pure/smtp.nim | 172 | ||||
-rw-r--r-- | lib/system.nim | 56 |
6 files changed, 110 insertions, 156 deletions
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index bb234565b..519c58653 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -8,8 +8,9 @@ # ## This module implements a `crit bit tree`:idx: which is an efficient -## container for a set or a mapping of strings. Based on the excellent paper +## container for a sorted set of strings, or for a sorted mapping of strings. Based on the excellent paper ## by Adam Langley. +## (A crit bit tree is a form of `radix tree`:idx: or `patricia trie`:idx:.) include "system/inclrtl" diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 45a148fbf..19512d5f4 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -16,9 +16,6 @@ ## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing. ## Anonymous procs can use `the special do notation <manual.html#do-notation>`_ ## which is more convenient in certain situations. -## -## **Note**: This interface will change as soon as the compiler supports -## closures and proper coroutines. include "system/inclrtl" diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index c6322c7bb..b6154d8de 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -83,7 +83,8 @@ proc unmapMem*(f: var MemFile, p: pointer, size: int) = proc open*(filename: string, mode: FileMode = fmRead, - mappedSize = -1, offset = 0, newFileSize = -1): MemFile = + mappedSize = -1, offset = 0, newFileSize = -1, + allowRemap = false): MemFile = ## opens a memory mapped file. If this fails, ``EOS`` is raised. ## ## ``newFileSize`` can only be set if the file does not exist and is opened @@ -95,6 +96,9 @@ proc open*(filename: string, mode: FileMode = fmRead, ## ``offset`` must be multiples of the PAGE SIZE of your OS ## (usually 4K or 8K but is unique to your OS) ## + ## ``allowRemap`` only needs to be true if you want to call ``mapMem`` on + ## the resulting MemFile; else file handles are not kept open. + ## ## Example: ## ## .. code-block:: nim @@ -189,11 +193,14 @@ proc open*(filename: string, mode: FileMode = fmRead, else: result.size = fileSize.int result.wasOpened = true + if not allowRemap and result.fHandle != INVALID_HANDLE_VALUE: + if closeHandle(result.fHandle) == 0: + result.fHandle = INVALID_HANDLE_VALUE else: template fail(errCode: OSErrorCode, msg: expr) = rollback() - if result.handle != 0: discard close(result.handle) + if result.handle != -1: discard close(result.handle) raiseOSError(errCode) var flags = if readonly: O_RDONLY else: O_RDWR @@ -236,6 +243,10 @@ proc open*(filename: string, mode: FileMode = fmRead, if result.mem == cast[pointer](MAP_FAILED): fail(osLastError(), "file mapping failed") + if not allowRemap and result.handle != -1: + if close(result.handle) == 0: + result.handle = -1 + proc close*(f: var MemFile) = ## closes the memory mapped file `f`. All changes are written back to the ## file system, if `f` was opened with write access. @@ -244,15 +255,16 @@ proc close*(f: var MemFile) = var lastErr: OSErrorCode when defined(windows): - if f.fHandle != INVALID_HANDLE_VALUE and f.wasOpened: + if f.wasOpened: error = unmapViewOfFile(f.mem) == 0 lastErr = osLastError() error = (closeHandle(f.mapHandle) == 0) or error - error = (closeHandle(f.fHandle) == 0) or error + if f.fHandle != INVALID_HANDLE_VALUE: + error = (closeHandle(f.fHandle) == 0) or error else: - if f.handle != 0: - error = munmap(f.mem, f.size) != 0 - lastErr = osLastError() + error = munmap(f.mem, f.size) != 0 + lastErr = osLastError() + if f.handle != -1: error = (close(f.handle) != 0) or error f.size = 0 @@ -263,7 +275,7 @@ proc close*(f: var MemFile) = f.mapHandle = 0 f.wasOpened = false else: - f.handle = 0 + f.handle = -1 if error: raiseOSError(lastErr) diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 87ece2582..71991e35a 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -25,8 +25,8 @@ when not declared(getEnv) or defined(nimscript): WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write ## to an environment variable - ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write - ## operation to the directory + ReadDirEffect* = object of ReadIOEffect ## effect that denotes a read + ## operation from the directory ## structure WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write ## operation to diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 87865c005..08e6c8112 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -20,7 +20,8 @@ ## var msg = createMessage("Hello from Nim's SMTP", ## "Hello!.\n Is this awesome or what?", ## @["foo@gmail.com"]) -## var smtpConn = connect("smtp.gmail.com", Port 465, true, true) +## let smtpConn = newSmtp(useSsl = true, debug=true) +## smtpConn.connect("smtp.gmail.com", Port 465) ## smtpConn.auth("username", "password") ## smtpConn.sendmail("username@gmail.com", @["foo@gmail.com"], $msg) ## @@ -34,10 +35,6 @@ import asyncnet, asyncdispatch export Port type - Smtp* = object - sock: Socket - debug: bool - Message* = object msgTo: seq[string] msgCc: seq[string] @@ -47,37 +44,29 @@ type ReplyError* = object of IOError - AsyncSmtp* = ref object - sock: AsyncSocket - address: string - port: Port - useSsl: bool + SmtpBase[SocketType] = ref object + sock: SocketType debug: bool + Smtp* = SmtpBase[Socket] + AsyncSmtp* = SmtpBase[AsyncSocket] + {.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].} -proc debugSend(smtp: Smtp, cmd: string) = +proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = if smtp.debug: echo("C:" & cmd) - smtp.sock.send(cmd) - -proc debugRecv(smtp: var Smtp): TaintedString = - var line = TaintedString"" - smtp.sock.readLine(line) + await smtp.sock.send(cmd) +proc debugRecv(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = + result = await smtp.sock.recvLine() if smtp.debug: - echo("S:" & line.string) - return line + echo("S:" & result.string) proc quitExcpt(smtp: Smtp, msg: string) = smtp.debugSend("QUIT") raise newException(ReplyError, msg) -proc checkReply(smtp: var Smtp, reply: string) = - var line = smtp.debugRecv() - if not line.string.startswith(reply): - quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string) - const compiledWithSsl = defined(ssl) when not defined(ssl): @@ -86,63 +75,6 @@ when not defined(ssl): else: let defaultSSLContext = newContext(verifyMode = CVerifyNone) -proc connect*(address: string, port = Port(25), - ssl = false, debug = false, - sslContext = defaultSSLContext): Smtp = - ## Establishes a connection with a SMTP server. - ## May fail with ReplyError or with a socket error. - result.sock = newSocket() - if ssl: - when compiledWithSsl: - sslContext.wrapSocket(result.sock) - else: - raise newException(ESystem, - "SMTP module compiled without SSL support") - result.sock.connect(address, port) - result.debug = debug - - result.checkReply("220") - result.debugSend("HELO " & address & "\c\L") - result.checkReply("250") - -proc auth*(smtp: var Smtp, username, password: string) = - ## Sends an AUTH command to the server to login as the `username` - ## using `password`. - ## May fail with ReplyError. - - smtp.debugSend("AUTH LOGIN\c\L") - smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:" - # i.e "334 VXNlcm5hbWU6" - smtp.debugSend(encode(username) & "\c\L") - smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?) - - smtp.debugSend(encode(password) & "\c\L") - smtp.checkReply("235") # Check whether the authentification was successful. - -proc sendmail*(smtp: var Smtp, fromaddr: string, - toaddrs: seq[string], msg: string) = - ## Sends `msg` from `fromaddr` to `toaddr`. - ## Messages may be formed using ``createMessage`` by converting the - ## Message into a string. - - smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L") - smtp.checkReply("250") - for address in items(toaddrs): - smtp.debugSend("RCPT TO:<" & address & ">\c\L") - smtp.checkReply("250") - - # Send the message - smtp.debugSend("DATA " & "\c\L") - smtp.checkReply("354") - smtp.debugSend(msg & "\c\L") - smtp.debugSend(".\c\L") - smtp.checkReply("250") - -proc close*(smtp: Smtp) = - ## Disconnects from the SMTP server and closes the socket. - smtp.debugSend("QUIT\c\L") - smtp.sock.close() - proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], otherHeaders: openarray[tuple[name, value: string]]): Message = ## Creates a new MIME compliant message. @@ -178,81 +110,94 @@ proc `$`*(msg: Message): string = result.add("\c\L") result.add(msg.msgBody) -proc newAsyncSmtp*(address: string, port: Port, useSsl = false, +proc newSmtp*(useSsl = false, debug=false, + sslContext = defaultSslContext): Smtp = + ## Creates a new ``Smtp`` instance. + new result + result.debug = debug + + result.sock = newSocket() + if useSsl: + when compiledWithSsl: + sslContext.wrapSocket(result.sock) + else: + raise newException(SystemError, + "SMTP module compiled without SSL support") + +proc newAsyncSmtp*(useSsl = false, debug=false, sslContext = defaultSslContext): AsyncSmtp = ## Creates a new ``AsyncSmtp`` instance. new result - result.address = address - result.port = port - result.useSsl = useSsl + result.debug = debug result.sock = newAsyncSocket() if useSsl: when compiledWithSsl: sslContext.wrapSocket(result.sock) else: - raise newException(ESystem, + raise newException(SystemError, "SMTP module compiled without SSL support") proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = var retFuture = newFuture[void]() - var sendFut = smtp.sock.send("QUIT") + var sendFut = smtp.debugSend("QUIT") sendFut.callback = proc () = # TODO: Fix this in async procs. raise newException(ReplyError, msg) return retFuture -proc checkReply(smtp: AsyncSmtp, reply: string) {.async.} = - var line = await smtp.sock.recvLine() - if not line.string.startswith(reply): - await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string) +proc checkReply(smtp: Smtp | AsyncSmtp, reply: string) {.multisync.} = + var line = await smtp.debugRecv() + if not line.startswith(reply): + await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line) -proc connect*(smtp: AsyncSmtp) {.async.} = +proc connect*(smtp: Smtp | AsyncSmtp, + address: string, port: Port) {.multisync.} = ## Establishes a connection with a SMTP server. ## May fail with ReplyError or with a socket error. - await smtp.sock.connect(smtp.address, smtp.port) + await smtp.sock.connect(address, port) await smtp.checkReply("220") - await smtp.sock.send("HELO " & smtp.address & "\c\L") + await smtp.debugSend("HELO " & address & "\c\L") await smtp.checkReply("250") -proc auth*(smtp: AsyncSmtp, username, password: string) {.async.} = +proc auth*(smtp: Smtp | AsyncSmtp, username, password: string) {.multisync.} = ## Sends an AUTH command to the server to login as the `username` ## using `password`. ## May fail with ReplyError. - await smtp.sock.send("AUTH LOGIN\c\L") + await smtp.debugSend("AUTH LOGIN\c\L") await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:" # i.e "334 VXNlcm5hbWU6" - await smtp.sock.send(encode(username) & "\c\L") + await smtp.debugSend(encode(username) & "\c\L") await smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?) - await smtp.sock.send(encode(password) & "\c\L") + await smtp.debugSend(encode(password) & "\c\L") await smtp.checkReply("235") # Check whether the authentification was successful. -proc sendMail*(smtp: AsyncSmtp, fromAddr: string, - toAddrs: seq[string], msg: string) {.async.} = +proc sendMail*(smtp: Smtp | AsyncSmtp, fromAddr: string, + toAddrs: seq[string], msg: string) {.multisync.} = ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``. ## Messages may be formed using ``createMessage`` by converting the ## Message into a string. - await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L") + await smtp.debugSend("MAIL FROM:<" & fromAddr & ">\c\L") await smtp.checkReply("250") for address in items(toAddrs): - await smtp.sock.send("RCPT TO:<" & address & ">\c\L") + await smtp.debugSend("RCPT TO:<" & address & ">\c\L") await smtp.checkReply("250") # Send the message - await smtp.sock.send("DATA " & "\c\L") + await smtp.debugSend("DATA " & "\c\L") await smtp.checkReply("354") await smtp.sock.send(msg & "\c\L") - await smtp.sock.send(".\c\L") + await smtp.debugSend(".\c\L") await smtp.checkReply("250") -proc close*(smtp: AsyncSmtp) {.async.} = +proc close*(smtp: Smtp | AsyncSmtp) {.multisync.} = ## Disconnects from the SMTP server and closes the socket. - await smtp.sock.send("QUIT\c\L") + await smtp.debugSend("QUIT\c\L") smtp.sock.close() when not defined(testing) and isMainModule: @@ -278,25 +223,24 @@ when not defined(testing) and isMainModule: proc async_test() {.async.} = let client = newAsyncSmtp( - conf["smtphost"], - conf["port"].parseInt.Port, - conf["use_tls"].parseBool + conf["use_tls"].parseBool, + debug=true ) - await client.connect() + await client.connect(conf["smtphost"], conf["port"].parseInt.Port) await client.auth(conf["username"], conf["password"]) await client.sendMail(conf["sender"], @[conf["recipient"]], $msg) await client.close() echo "async email sent" proc sync_test() = - var smtpConn = connect( - conf["smtphost"], - conf["port"].parseInt.Port, + var smtpConn = newSmtp( conf["use_tls"].parseBool, - true, # debug + debug=true ) + smtpConn.connect(conf["smtphost"], conf["port"].parseInt.Port) smtpConn.auth(conf["username"], conf["password"]) - smtpConn.sendmail(conf["sender"], @[conf["recipient"]], $msg) + smtpConn.sendMail(conf["sender"], @[conf["recipient"]], $msg) + smtpConn.close() echo "sync email sent" waitFor async_test() diff --git a/lib/system.nim b/lib/system.nim index 74dca461a..b7e2c6eba 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -417,7 +417,7 @@ type ## Base exception class. ## ## Each exception has to inherit from `Exception`. See the full `exception - ## hierarchy`_. + ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_. parent*: ref Exception ## parent exception (can be used as a stack) name*: cstring ## The exception's name is its Nim identifier. ## This field is filled automatically in the @@ -430,51 +430,51 @@ type SystemError* = object of Exception ## \ ## Abstract class for exceptions that the runtime system raises. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. IOError* = object of SystemError ## \ ## Raised if an IO error occurred. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. EOFError* = object of IOError ## \ ## Raised if an IO "end of file" error occurred. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. OSError* = object of SystemError ## \ ## Raised if an operating system service failed. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. errorCode*: int32 ## OS-defined error code describing this error. LibraryError* = object of OSError ## \ ## Raised if a dynamic library could not be loaded. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ResourceExhaustedError* = object of SystemError ## \ ## Raised if a resource request could not be fulfilled. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ArithmeticError* = object of Exception ## \ ## Raised if any kind of arithmetic error occurred. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. OverflowError* = object of ArithmeticError ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the - ## provided bits. See the full `exception hierarchy`_. + ## provided bits. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. AccessViolationError* = object of Exception ## \ ## Raised for invalid memory access errors ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. AssertionError* = object of Exception ## \ ## Raised when assertion is proved wrong. ## ## Usually the result of using the `assert() template <#assert>`_. See the - ## full `exception hierarchy`_. + ## full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ValueError* = object of Exception ## \ ## Raised for string and object conversion errors. KeyError* = object of ValueError ## \ @@ -482,66 +482,66 @@ type ## ## Mostly used by the `tables <tables.html>`_ module, it can also be raised ## by other collection modules like `sets <sets.html>`_ or `strtabs - ## <strtabs.html>`_. See the full `exception hierarchy`_. + ## <strtabs.html>`_. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. OutOfMemError* = object of SystemError ## \ ## Raised for unsuccessful attempts to allocate memory. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. IndexError* = object of Exception ## \ ## Raised if an array index is out of bounds. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FieldError* = object of Exception ## \ ## Raised if a record field is not accessible because its dicriminant's ## value does not fit. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. RangeError* = object of Exception ## \ ## Raised if a range check error occurred. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. StackOverflowError* = object of SystemError ## \ ## Raised if the hardware stack used for subroutine calls overflowed. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ReraiseError* = object of Exception ## \ ## Raised if there is no exception to reraise. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ObjectAssignmentError* = object of Exception ## \ ## Raised if an object gets assigned to its parent's object. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. ObjectConversionError* = object of Exception ## \ ## Raised if an object is converted to an incompatible object type. ## You can use ``of`` operator to check if conversion will succeed. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatingPointError* = object of Exception ## \ ## Base class for floating point exceptions. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatInvalidOpError* = object of FloatingPointError ## \ ## Raised by invalid operations according to IEEE. ## ## Raised by ``0.0/0.0``, for example. See the full `exception - ## hierarchy`_. + ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatDivByZeroError* = object of FloatingPointError ## \ ## Raised by division by zero. ## ## Divisor is zero and dividend is a finite nonzero number. See the full - ## `exception hierarchy`_. + ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatOverflowError* = object of FloatingPointError ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatUnderflowError* = object of FloatingPointError ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a - ## normal number. See the full `exception hierarchy`_. + ## normal number. See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. FloatInexactError* = object of FloatingPointError ## \ ## Raised for inexact results. ## @@ -549,11 +549,11 @@ type ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## ## **NOTE**: Nim currently does not detect these! See the full - ## `exception hierarchy`_. + ## `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. DeadThreadError* = object of Exception ## \ ## Raised if it is attempted to send a message to a dead thread. ## - ## See the full `exception hierarchy`_. + ## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_. {.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect, FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect, |