mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 15:31:28 +00:00
annotated effects of modules: os, sockets, times
This commit is contained in:
100
lib/pure/os.nim
100
lib/pure/os.nim
@@ -28,6 +28,17 @@ else:
|
||||
|
||||
include "system/ansi_c"
|
||||
|
||||
type
|
||||
FReadEnv* = object of FReadIO ## effect that denotes a read
|
||||
## from an environment variable
|
||||
FWriteEnv* = object of FWriteIO ## effect that denotes a write
|
||||
## to an environment variable
|
||||
|
||||
FReadDir* = object of FReadIO ## effect that denotes a write operation to
|
||||
## the directory structure
|
||||
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
|
||||
## the directory structure
|
||||
|
||||
const
|
||||
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
||||
# DOS-like filesystem
|
||||
@@ -275,7 +286,8 @@ when defined(windows):
|
||||
|
||||
template getFilename(f: expr): expr = $f.cFilename
|
||||
|
||||
proc existsFile*(filename: string): bool {.rtl, extern: "nos$1".} =
|
||||
proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
|
||||
tags: [FReadDir].} =
|
||||
## Returns true if the file exists, false otherwise.
|
||||
when defined(windows):
|
||||
when useWinUnicode:
|
||||
@@ -288,7 +300,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1".} =
|
||||
var res: TStat
|
||||
return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
|
||||
|
||||
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1".} =
|
||||
proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} =
|
||||
## Returns true iff the directory `dir` exists. If `dir` is a file, false
|
||||
## is returned.
|
||||
when defined(windows):
|
||||
@@ -346,7 +358,7 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
|
||||
## modification time is later than `b`'s.
|
||||
result = getLastModificationTime(a) - getLastModificationTime(b) > 0
|
||||
|
||||
proc getCurrentDir*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
|
||||
## Returns the `current working directory`:idx:.
|
||||
const bufsize = 512 # should be enough
|
||||
when defined(windows):
|
||||
@@ -368,7 +380,7 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1".} =
|
||||
else:
|
||||
OSError()
|
||||
|
||||
proc setCurrentDir*(newDir: string) {.inline.} =
|
||||
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||
## Sets the `current working directory`:idx:; `EOS` is raised if
|
||||
## `newDir` cannot been set.
|
||||
when defined(Windows):
|
||||
@@ -559,7 +571,8 @@ proc extractFilename*(path: string): string {.
|
||||
else:
|
||||
result = splitPath(path).tail
|
||||
|
||||
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1".} =
|
||||
proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||
tags: [FReadDir].} =
|
||||
## Returns the full path of `filename`, raises EOS in case of an error.
|
||||
when defined(windows):
|
||||
const bufsize = 3072'i32
|
||||
@@ -647,7 +660,8 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
|
||||
elif defined(posix):
|
||||
result = path[0] == '/'
|
||||
|
||||
proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
|
||||
proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||
tags: [FReadDir].} =
|
||||
## Returns True if both pathname arguments refer to the same physical
|
||||
## file or directory. Raises an exception if any of the files does not
|
||||
## exist or information about it can not be obtained.
|
||||
@@ -702,7 +716,8 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
|
||||
else:
|
||||
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
|
||||
|
||||
proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
|
||||
proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO].} =
|
||||
## Returns True if both pathname arguments refer to files with identical
|
||||
## binary content.
|
||||
const
|
||||
@@ -732,7 +747,8 @@ proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1".} =
|
||||
close(a)
|
||||
close(b)
|
||||
|
||||
proc copyFile*(source, dest: string) {.rtl, extern: "nos$1".} =
|
||||
proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO, FWriteIO].} =
|
||||
## Copies a file from `source` to `dest`. If this fails,
|
||||
## `EOS` is raised.
|
||||
when defined(Windows):
|
||||
@@ -768,19 +784,21 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1".} =
|
||||
close(s)
|
||||
close(d)
|
||||
|
||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1".} =
|
||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO, FWriteIO].} =
|
||||
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
|
||||
if crename(source, dest) != 0'i32: OSError()
|
||||
|
||||
when not defined(ENOENT):
|
||||
var ENOENT* {.importc, header: "<errno.h>".}: cint
|
||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1".} =
|
||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
||||
## if the file never existed in the first place.
|
||||
if cremove(file) != 0'i32 and errno != ENOENT: OSError()
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1".} =
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||
tags: [FExecIO].} =
|
||||
## Executes a `shell command`:idx:.
|
||||
##
|
||||
## Command has the form 'program args' where args are the command
|
||||
@@ -873,7 +891,7 @@ proc findEnvVar(key: string): int =
|
||||
if startsWith(environment[i], temp): return i
|
||||
return -1
|
||||
|
||||
proc getEnv*(key: string): TaintedString =
|
||||
proc getEnv*(key: string): TaintedString {.tags: [FReadEnv].} =
|
||||
## Returns the value of the `environment variable`:idx: named `key`.
|
||||
##
|
||||
## If the variable does not exist, "" is returned. To distinguish
|
||||
@@ -887,13 +905,13 @@ proc getEnv*(key: string): TaintedString =
|
||||
if env == nil: return TaintedString("")
|
||||
result = TaintedString($env)
|
||||
|
||||
proc existsEnv*(key: string): bool =
|
||||
proc existsEnv*(key: string): bool {.tags: [FReadEnv].} =
|
||||
## Checks whether the environment variable named `key` exists.
|
||||
## Returns true if it exists, false otherwise.
|
||||
if cgetenv(key) != nil: return true
|
||||
else: return findEnvVar(key) >= 0
|
||||
|
||||
proc putEnv*(key, val: string) =
|
||||
proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
|
||||
## Sets the value of the `environment variable`:idx: named `key` to `val`.
|
||||
## If an error occurs, `EInvalidEnvVar` is raised.
|
||||
|
||||
@@ -921,7 +939,7 @@ proc putEnv*(key, val: string) =
|
||||
else:
|
||||
if SetEnvironmentVariableA(key, val) == 0'i32: OSError()
|
||||
|
||||
iterator envPairs*(): tuple[key, value: TaintedString] =
|
||||
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
||||
## Iterate over all `environments variables`:idx:. In the first component
|
||||
## of the tuple is the name of the current variable stored, in the second
|
||||
## its value.
|
||||
@@ -931,7 +949,7 @@ iterator envPairs*(): tuple[key, value: TaintedString] =
|
||||
yield (TaintedString(substr(environment[i], 0, p-1)),
|
||||
TaintedString(substr(environment[i], p+1)))
|
||||
|
||||
iterator walkFiles*(pattern: string): string =
|
||||
iterator walkFiles*(pattern: string): string {.tags: [FReadDir].} =
|
||||
## Iterate over all the files that match the `pattern`. On POSIX this uses
|
||||
## the `glob`:idx: call.
|
||||
##
|
||||
@@ -969,7 +987,8 @@ type
|
||||
pcDir, ## path refers to a directory
|
||||
pcLinkToDir ## path refers to a symbolic link to a directory
|
||||
|
||||
iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] =
|
||||
iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
|
||||
tags: [FReadDir].} =
|
||||
## walks over the directory `dir` and yields for each directory or file in
|
||||
## `dir`. The component type and full path for each item is returned.
|
||||
## Walking is not recursive.
|
||||
@@ -1019,7 +1038,8 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] =
|
||||
yield (k, y)
|
||||
discard closeDir(d)
|
||||
|
||||
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string =
|
||||
iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
|
||||
tags: [FReadDir].} =
|
||||
## walks over the directory `dir` and yields for each file in `dir`. The
|
||||
## full path for each file is returned.
|
||||
## Walking is recursive. `filter` controls the behaviour of the iterator:
|
||||
@@ -1052,7 +1072,8 @@ proc rawRemoveDir(dir: string) =
|
||||
else:
|
||||
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
|
||||
|
||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1".} =
|
||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||
FWriteDir, FReadDir].} =
|
||||
## Removes the directory `dir` including all subdirectories and files
|
||||
## in `dir` (recursively). If this fails, `EOS` is raised. This does not fail
|
||||
## if the directory never existed in the first place.
|
||||
@@ -1074,7 +1095,7 @@ proc rawCreateDir(dir: string) =
|
||||
if res == 0'i32 and GetLastError() != 183'i32:
|
||||
OSError()
|
||||
|
||||
proc createDir*(dir: string) {.rtl, extern: "nos$1".} =
|
||||
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## Creates the `directory`:idx: `dir`.
|
||||
##
|
||||
## The directory may contain several subdirectories that do not exist yet.
|
||||
@@ -1085,7 +1106,8 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1".} =
|
||||
if dir[i] in {dirsep, altsep}: rawCreateDir(substr(dir, 0, i-1))
|
||||
rawCreateDir(dir)
|
||||
|
||||
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1".} =
|
||||
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
|
||||
tags: [FWriteIO, FReadIO].} =
|
||||
## Copies a directory from `source` to `dest`. If this fails, `EOS` is raised.
|
||||
createDir(dest)
|
||||
for kind, path in walkDir(source):
|
||||
@@ -1199,7 +1221,7 @@ type
|
||||
fpOthersRead ## read access for others
|
||||
|
||||
proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||
rtl, extern: "nos$1".} =
|
||||
rtl, extern: "nos$1", tags: [FReadDir].} =
|
||||
## retrieves file permissions for `filename`. `OSError` is raised in case of
|
||||
## an error. On Windows, only the ``readonly`` flag is checked, every other
|
||||
## permission is available in any case.
|
||||
@@ -1231,7 +1253,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||
result = {fpUserExec..fpOthersRead}
|
||||
|
||||
proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||
rtl, extern: "nos$1".} =
|
||||
rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||
## sets the file permissions for `filename`. `OSError` is raised in case of
|
||||
## an error. On Windows, only the ``readonly`` flag is changed, depending on
|
||||
## ``fpUserWrite``.
|
||||
@@ -1268,7 +1290,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||
|
||||
proc inclFilePermissions*(filename: string,
|
||||
permissions: set[TFilePermission]) {.
|
||||
rtl, extern: "nos$1".} =
|
||||
rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} =
|
||||
## a convenience procedure for:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
@@ -1277,24 +1299,24 @@ proc inclFilePermissions*(filename: string,
|
||||
|
||||
proc exclFilePermissions*(filename: string,
|
||||
permissions: set[TFilePermission]) {.
|
||||
rtl, extern: "nos$1".} =
|
||||
rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} =
|
||||
## a convenience procedure for:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
||||
setFilePermissions(filename, getFilePermissions(filename)-permissions)
|
||||
|
||||
proc getHomeDir*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
|
||||
## Returns the home directory of the current user.
|
||||
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
|
||||
else: return string(getEnv("HOME")) & "/"
|
||||
|
||||
proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
|
||||
## Returns the config directory of the current user for applications.
|
||||
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||
else: return string(getEnv("HOME")) & "/.config/"
|
||||
|
||||
proc getTempDir*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} =
|
||||
## Returns the temporary directory of the current user for applications to
|
||||
## save temporary files in.
|
||||
when defined(windows): return string(getEnv("TEMP")) & "\\"
|
||||
@@ -1309,13 +1331,14 @@ when defined(windows):
|
||||
var
|
||||
ownArgv: seq[string]
|
||||
|
||||
proc paramCount*(): int {.rtl, extern: "nos$1".} =
|
||||
proc paramCount*(): int {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||
## Returns the number of `command line arguments`:idx: given to the
|
||||
## application.
|
||||
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
|
||||
result = ownArgv.len-1
|
||||
|
||||
proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1".} =
|
||||
proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO].} =
|
||||
## Returns the `i`-th `command line argument`:idx: given to the
|
||||
## application.
|
||||
##
|
||||
@@ -1330,11 +1353,11 @@ elif not defined(createNimRtl):
|
||||
cmdCount {.importc: "cmdCount".}: cint
|
||||
cmdLine {.importc: "cmdLine".}: cstringArray
|
||||
|
||||
proc paramStr*(i: int): TaintedString =
|
||||
proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} =
|
||||
if i < cmdCount and i >= 0: return TaintedString($cmdLine[i])
|
||||
raise newException(EInvalidIndex, "invalid index")
|
||||
|
||||
proc paramCount*(): int = return cmdCount-1
|
||||
proc paramCount*(): int {.tags: [FReadIO].} = return cmdCount-1
|
||||
|
||||
when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
|
||||
proc getApplAux(procPath: string): string =
|
||||
@@ -1357,7 +1380,7 @@ when defined(macosx):
|
||||
proc getExecPath2(c: cstring, size: var cuint32): bool {.
|
||||
importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
|
||||
|
||||
proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||
## Returns the filename of the application's executable.
|
||||
## **Note**: This does not work reliably on BSD.
|
||||
|
||||
@@ -1413,12 +1436,12 @@ proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} =
|
||||
## instead.
|
||||
result = splitFile(getAppFilename()).dir
|
||||
|
||||
proc getAppDir*(): string {.rtl, extern: "nos$1".} =
|
||||
proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} =
|
||||
## Returns the directory of the application's executable.
|
||||
## **Note**: This does not work reliably on BSD.
|
||||
result = splitFile(getAppFilename()).dir
|
||||
|
||||
proc sleep*(milsecs: int) {.rtl, extern: "nos$1".} =
|
||||
proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [FTime].} =
|
||||
## sleeps `milsecs` milliseconds.
|
||||
when defined(windows):
|
||||
winlean.sleep(int32(milsecs))
|
||||
@@ -1428,7 +1451,8 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1".} =
|
||||
a.tv_nsec = (milsecs mod 1000) * 1000
|
||||
discard posix.nanosleep(a, b)
|
||||
|
||||
proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1".} =
|
||||
proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||
tags: [FReadIO].} =
|
||||
## returns the file size of `file`. Can raise ``EOS``.
|
||||
when defined(windows):
|
||||
var a: TWin32FindData
|
||||
@@ -1443,7 +1467,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1".} =
|
||||
close(f)
|
||||
else: OSError()
|
||||
|
||||
proc findExe*(exe: string): string =
|
||||
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
||||
## Searches for `exe` in the current working directory and then
|
||||
## in directories listed in the ``PATH`` environment variable.
|
||||
## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
|
||||
|
||||
@@ -58,7 +58,7 @@ proc startProcess*(command: string,
|
||||
args: openarray[string] = [],
|
||||
env: PStringTable = nil,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut}):
|
||||
PProcess {.rtl, extern: "nosp$1", tags: [FExecIO].}
|
||||
PProcess {.rtl, extern: "nosp$1", tags: [FExecIO, FReadEnv].}
|
||||
## Starts a process. `Command` is the executable file, `workingDir` is the
|
||||
## process's working directory. If ``workingDir == ""`` the current directory
|
||||
## is used. `args` are the command line arguments that are passed to the
|
||||
@@ -74,7 +74,8 @@ proc startProcess*(command: string,
|
||||
## but ``EOS`` is raised in case of an error.
|
||||
|
||||
proc startCmd*(command: string, options: set[TProcessOption] = {
|
||||
poStdErrToStdOut, poUseShell}): PProcess {.tags: [FExecIO].} =
|
||||
poStdErrToStdOut, poUseShell}): PProcess {.
|
||||
tags: [FExecIO, FReadEnv].} =
|
||||
## a simpler version of `startProcess` that parses the command line into
|
||||
## program and arguments and then calls `startProcess` with the empty string
|
||||
## for `workingDir` and the nil string table for `env`.
|
||||
@@ -159,7 +160,7 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
|
||||
proc execProcesses*(cmds: openArray[string],
|
||||
options = {poStdErrToStdOut, poParentStreams},
|
||||
n = countProcessors()): int {.rtl, extern: "nosp$1",
|
||||
tags: [FExecIO].} =
|
||||
tags: [FExecIO, FTime, FReadEnv].} =
|
||||
## executes the commands `cmds` in parallel. Creates `n` processes
|
||||
## that execute in parallel. The highest return value of all processes
|
||||
## is returned.
|
||||
|
||||
@@ -242,9 +242,10 @@ when defined(ssl):
|
||||
## are available with the addition of ``ProtSSLv23`` which allows for
|
||||
## compatibility with all of them.
|
||||
##
|
||||
## There are currently only two options for verify mode; one is ``CVerifyNone``
|
||||
## and with it certificates will not be verified the other is ``CVerifyPeer``
|
||||
## and certificates will be verified for it, ``CVerifyPeer`` is the safest choice.
|
||||
## There are currently only two options for verify mode;
|
||||
## one is ``CVerifyNone`` and with it certificates will not be verified
|
||||
## the other is ``CVerifyPeer`` and certificates will be verified for
|
||||
## it, ``CVerifyPeer`` is the safest choice.
|
||||
##
|
||||
## The last two parameters specify the certificate file path and the key file
|
||||
## path, a server socket will most likely not work without these.
|
||||
@@ -291,7 +292,7 @@ when defined(ssl):
|
||||
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
|
||||
SSLError()
|
||||
|
||||
proc listen*(socket: TSocket, backlog = SOMAXCONN) =
|
||||
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
||||
## Marks ``socket`` as accepting connections.
|
||||
## ``Backlog`` specifies the maximum length of the
|
||||
## queue of pending connections.
|
||||
@@ -335,7 +336,8 @@ template gaiNim(a, p, h, list: expr): stmt =
|
||||
else:
|
||||
OSError($gai_strerror(gaiResult))
|
||||
|
||||
proc bindAddr*(socket: TSocket, port = TPort(0), address = "") =
|
||||
proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||
tags: [FReadIO].} =
|
||||
## binds an address/port number to a socket.
|
||||
## Use address string in dotted decimal form like "a.b.c.d"
|
||||
## or leave "" for any address.
|
||||
@@ -390,15 +392,6 @@ proc getSockName*(socket: TSocket): TPort =
|
||||
OSError()
|
||||
result = TPort(sockets.ntohs(name.sin_port))
|
||||
|
||||
proc selectWrite*(writefds: var seq[TSocket], timeout = 500): int
|
||||
## When a socket in ``writefds`` is ready to be written to then a non-zero
|
||||
## value will be returned specifying the count of the sockets which can be
|
||||
## written to. The sockets which can be written to will also be removed
|
||||
## from ``writefds``.
|
||||
##
|
||||
## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
|
||||
## an unlimited time.
|
||||
|
||||
template acceptAddrPlain(noClientRet, successRet: expr,
|
||||
sslImplementation: stmt): stmt {.immediate.} =
|
||||
assert(client != nil)
|
||||
@@ -439,7 +432,8 @@ template acceptAddrPlain(noClientRet, successRet: expr,
|
||||
else:
|
||||
return successRet
|
||||
|
||||
proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) =
|
||||
proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
|
||||
tags: [FReadIO].} =
|
||||
## Blocks until a connection is being made from a client. When a connection
|
||||
## is made sets ``client`` to the client socket and ``address`` to the address
|
||||
## of the connecting client.
|
||||
@@ -482,7 +476,8 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) =
|
||||
proc setBlocking*(s: TSocket, blocking: bool)
|
||||
when defined(ssl):
|
||||
proc acceptAddrSSL*(server: TSocket, client: var TSocket,
|
||||
address: var string): TSSLAcceptResult =
|
||||
address: var string): TSSLAcceptResult {.
|
||||
tags: [FReadIO].} =
|
||||
## This procedure should only be used for non-blocking **SSL** sockets.
|
||||
## It will immediately return with one of the following values:
|
||||
##
|
||||
@@ -531,7 +526,7 @@ when defined(ssl):
|
||||
acceptAddrPlain(AcceptNoClient, AcceptSuccess):
|
||||
doHandshake()
|
||||
|
||||
proc accept*(server: TSocket, client: var TSocket) =
|
||||
proc accept*(server: TSocket, client: var TSocket) {.tags: [FReadIO].} =
|
||||
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
|
||||
## socket.
|
||||
##
|
||||
@@ -541,7 +536,8 @@ proc accept*(server: TSocket, client: var TSocket) =
|
||||
var addrDummy = ""
|
||||
acceptAddr(server, client, addrDummy)
|
||||
|
||||
proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] {.deprecated.} =
|
||||
proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] {.
|
||||
deprecated, tags: [FReadIO].} =
|
||||
## Slightly different version of ``acceptAddr``.
|
||||
##
|
||||
## **Deprecated since version 0.9.0:** Please use the function above.
|
||||
@@ -551,7 +547,7 @@ proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] {.dep
|
||||
acceptAddr(server, client, address)
|
||||
return (client, address)
|
||||
|
||||
proc accept*(server: TSocket): TSocket {.deprecated.} =
|
||||
proc accept*(server: TSocket): TSocket {.deprecated, tags: [FReadIO].} =
|
||||
## **Deprecated since version 0.9.0:** Please use the function above.
|
||||
new(result)
|
||||
var address = ""
|
||||
@@ -568,7 +564,7 @@ proc close*(socket: TSocket) =
|
||||
if socket.isSSL:
|
||||
discard SSLShutdown(socket.sslHandle)
|
||||
|
||||
proc getServByName*(name, proto: string): TServent =
|
||||
proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
||||
## well-known getservbyname proc.
|
||||
when defined(Windows):
|
||||
var s = winlean.getservbyname(name, proto)
|
||||
@@ -580,7 +576,7 @@ proc getServByName*(name, proto: string): TServent =
|
||||
result.port = TPort(s.s_port)
|
||||
result.proto = $s.s_proto
|
||||
|
||||
proc getServByPort*(port: TPort, proto: string): TServent =
|
||||
proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
|
||||
## well-known getservbyport proc.
|
||||
when defined(Windows):
|
||||
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||
@@ -592,7 +588,7 @@ proc getServByPort*(port: TPort, proto: string): TServent =
|
||||
result.port = TPort(s.s_port)
|
||||
result.proto = $s.s_proto
|
||||
|
||||
proc getHostByAddr*(ip: string): THostEnt =
|
||||
proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||
## This function will lookup the hostname of an IP Address.
|
||||
var myaddr: TInAddr
|
||||
myaddr.s_addr = inet_addr(ip)
|
||||
@@ -621,7 +617,7 @@ proc getHostByAddr*(ip: string): THostEnt =
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
proc getHostByName*(name: string): THostEnt =
|
||||
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||
## well-known gethostbyname proc.
|
||||
when defined(Windows):
|
||||
var s = winlean.gethostbyname(name)
|
||||
@@ -642,7 +638,8 @@ proc getHostByName*(name: string): THostEnt =
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
proc getSockOptInt*(socket: TSocket, level, optname: int): int =
|
||||
proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
|
||||
tags: [FReadIO].} =
|
||||
## getsockopt for integer options.
|
||||
var res: cint
|
||||
var size = sizeof(res).TSockLen
|
||||
@@ -651,7 +648,8 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int =
|
||||
OSError()
|
||||
result = int(res)
|
||||
|
||||
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) =
|
||||
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||
tags: [FWriteIO].} =
|
||||
## setsockopt for integer options.
|
||||
var value = cint(optval)
|
||||
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
||||
@@ -659,7 +657,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) =
|
||||
OSError()
|
||||
|
||||
proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||
af: TDomain = AF_INET) =
|
||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||
## Connects socket to ``name``:``port``. ``Name`` can be an IP address or a
|
||||
## 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
|
||||
@@ -719,7 +717,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
|
||||
OSError()
|
||||
|
||||
proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||
af: TDomain = AF_INET) =
|
||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||
## A variant of ``connect`` for non-blocking sockets.
|
||||
##
|
||||
## This procedure will immediatelly return, it will not block until a connection
|
||||
@@ -764,7 +762,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||
socket.sslNoHandshake = true
|
||||
|
||||
when defined(ssl):
|
||||
proc handshake*(socket: TSocket): bool =
|
||||
proc handshake*(socket: TSocket): bool {.tags: [FReadIO, RWriteIO].} =
|
||||
## 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.
|
||||
@@ -854,7 +852,7 @@ proc checkBuffer(readfds: var seq[TSocket]): int =
|
||||
readfds = res
|
||||
|
||||
proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||
timeout = 500): int =
|
||||
timeout = 500): int {.tags: [FReadIO].} =
|
||||
## Traditional select function. This function will return the number of
|
||||
## sockets that are ready to be read from, written to, or which have errors
|
||||
## if there are none; 0 is returned.
|
||||
@@ -884,7 +882,7 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
|
||||
pruneSocketSet(exceptfds, (ex))
|
||||
|
||||
proc select*(readfds, writefds: var seq[TSocket],
|
||||
timeout = 500): int =
|
||||
timeout = 500): int {.tags: [FReadIO].} =
|
||||
## variant of select with only a read and write list.
|
||||
let buffersFilled = checkBuffer(readfds)
|
||||
if buffersFilled > 0:
|
||||
@@ -905,7 +903,14 @@ proc select*(readfds, writefds: var seq[TSocket],
|
||||
pruneSocketSet(writefds, (wr))
|
||||
|
||||
proc selectWrite*(writefds: var seq[TSocket],
|
||||
timeout = 500): int =
|
||||
timeout = 500): int {.tags: [FReadIO].} =
|
||||
## When a socket in ``writefds`` is ready to be written to then a non-zero
|
||||
## value will be returned specifying the count of the sockets which can be
|
||||
## written to. The sockets which can be written to will also be removed
|
||||
## from ``writefds``.
|
||||
##
|
||||
## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
|
||||
## an unlimited time.
|
||||
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
|
||||
|
||||
var wr: TFdSet
|
||||
@@ -961,7 +966,7 @@ template retRead(flags, readBytes: int) =
|
||||
else:
|
||||
return res
|
||||
|
||||
proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||
proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} =
|
||||
## receives data from a socket
|
||||
if socket.isBuffered:
|
||||
if socket.bufLen == 0:
|
||||
@@ -999,7 +1004,8 @@ proc recv*(socket: TSocket, data: pointer, size: int): int =
|
||||
else:
|
||||
result = recv(socket.fd, data, size.cint, 0'i32)
|
||||
|
||||
proc waitFor(socket: TSocket, waited: var float, timeout: int): int =
|
||||
proc waitFor(socket: TSocket, waited: var float, timeout: int): int {.
|
||||
tags: [FTime].} =
|
||||
## returns the number of characters available to be read. In unbuffered
|
||||
## sockets this is always 1, otherwise this may as big as the buffer, currently
|
||||
## 4000.
|
||||
@@ -1015,7 +1021,8 @@ proc waitFor(socket: TSocket, waited: var float, timeout: int): int =
|
||||
raise newException(ETimeout, "Call to recv() timed out.")
|
||||
waited += (epochTime() - startTime)
|
||||
|
||||
proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int =
|
||||
proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {.
|
||||
tags: [FReadIO, FTime].} =
|
||||
## overload with a ``timeout`` parameter in miliseconds.
|
||||
var waited = 0.0 # number of seconds already waited
|
||||
|
||||
@@ -1031,7 +1038,7 @@ proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int =
|
||||
|
||||
result = read
|
||||
|
||||
proc peekChar(socket: TSocket, c: var char): int =
|
||||
proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} =
|
||||
if socket.isBuffered:
|
||||
result = 1
|
||||
if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
|
||||
@@ -1047,7 +1054,8 @@ proc peekChar(socket: TSocket, c: var char): int =
|
||||
|
||||
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
|
||||
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString): bool {.
|
||||
tags: [FReadIO].} =
|
||||
## retrieves a line from ``socket``. If a full line is received ``\r\L`` is not
|
||||
## added to ``line``, however if solely ``\r\L`` is received then ``line``
|
||||
## will be set to it.
|
||||
@@ -1082,7 +1090,8 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
|
||||
return true
|
||||
add(line.string, c)
|
||||
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
|
||||
proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool {.
|
||||
tags: [FReadIO, FTime].} =
|
||||
## variant with a ``timeout`` parameter, the timeout parameter specifies
|
||||
## how many miliseconds to wait for data.
|
||||
template addNLIfEmpty(): stmt =
|
||||
@@ -1111,7 +1120,8 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
|
||||
return true
|
||||
add(line.string, c)
|
||||
|
||||
proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||
proc recvLineAsync*(socket: TSocket,
|
||||
line: var TaintedString): TRecvLineResult {.tags: [FReadIO].} =
|
||||
## similar to ``recvLine`` but for non-blocking sockets.
|
||||
## The values of the returned enum should be pretty self explanatory:
|
||||
## If a full line has been retrieved; ``RecvFullLine`` is returned.
|
||||
@@ -1136,7 +1146,7 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
|
||||
elif c == '\L': return RecvFullLine
|
||||
add(line.string, c)
|
||||
|
||||
proc recv*(socket: TSocket): TaintedString =
|
||||
proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO].} =
|
||||
## receives all the available data from the socket.
|
||||
## Socket errors will result in an ``EOS`` error.
|
||||
## If socket is not a connectionless socket and socket is not connected
|
||||
@@ -1165,7 +1175,8 @@ proc recv*(socket: TSocket): TaintedString =
|
||||
add(result.string, buf)
|
||||
if bytesRead != bufSize-1: break
|
||||
|
||||
proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
|
||||
proc recvTimeout*(socket: TSocket, timeout: int): TaintedString {.
|
||||
tags: [FReadIO].} =
|
||||
## overloaded variant to support a ``timeout`` parameter, the ``timeout``
|
||||
## parameter specifies the amount of miliseconds to wait for data on the
|
||||
## socket.
|
||||
@@ -1176,7 +1187,8 @@ proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
|
||||
|
||||
return socket.recv
|
||||
|
||||
proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
||||
proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
|
||||
tags: [FReadIO].} =
|
||||
## receives all the data from a non-blocking socket. If socket is non-blocking
|
||||
## and there are no messages available, `False` will be returned.
|
||||
## Other socket errors will result in an ``EOS`` error.
|
||||
@@ -1226,7 +1238,8 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
|
||||
result = True
|
||||
|
||||
proc recvFrom*(socket: TSocket, data: var string, length: int,
|
||||
address: var string, port: var TPort, flags = 0'i32): int =
|
||||
address: var string, port: var TPort, flags = 0'i32): int {.
|
||||
tags: [FReadIO].} =
|
||||
## Receives data from ``socket``. This function should normally be used with
|
||||
## connection-less sockets (UDP sockets).
|
||||
##
|
||||
@@ -1248,7 +1261,8 @@ proc recvFrom*(socket: TSocket, data: var string, length: int,
|
||||
port = ntohs(sockAddress.sin_port).TPort
|
||||
|
||||
proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||
address: var string, port: var TPort, flags = 0'i32): bool =
|
||||
address: var string, port: var TPort,
|
||||
flags = 0'i32): bool {.tags: [FReadIO].} =
|
||||
## Similar to ``recvFrom`` but raises an EOS error when an error occurs and
|
||||
## is also meant for non-blocking sockets.
|
||||
## Returns False if no messages could be received from ``socket``.
|
||||
@@ -1266,14 +1280,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||
return False
|
||||
else: OSError()
|
||||
|
||||
proc skip*(socket: TSocket) =
|
||||
proc skip*(socket: TSocket) {.tags: [FReadIO].} =
|
||||
## skips all the data that is pending for the socket
|
||||
const bufSize = 1000
|
||||
var buf = alloc(bufSize)
|
||||
while recv(socket, buf, bufSize) == bufSize: nil
|
||||
dealloc(buf)
|
||||
|
||||
proc send*(socket: TSocket, data: pointer, size: int): int =
|
||||
proc send*(socket: TSocket, data: pointer, size: int): int {.
|
||||
tags: [FWriteIO].} =
|
||||
## sends data to a socket.
|
||||
when defined(ssl):
|
||||
if socket.isSSL:
|
||||
@@ -1284,7 +1299,7 @@ proc send*(socket: TSocket, data: pointer, size: int): int =
|
||||
else:
|
||||
result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
|
||||
|
||||
proc send*(socket: TSocket, data: string) =
|
||||
proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
|
||||
## sends data to a socket.
|
||||
if send(socket, cstring(data), data.len) != data.len:
|
||||
when defined(ssl):
|
||||
@@ -1293,7 +1308,7 @@ proc send*(socket: TSocket, data: string) =
|
||||
|
||||
OSError()
|
||||
|
||||
proc sendAsync*(socket: TSocket, data: string): bool =
|
||||
proc sendAsync*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
||||
## sends data to a non-blocking socket. Returns whether ``data`` was sent.
|
||||
result = true
|
||||
var bytesSent = send(socket, cstring(data), data.len)
|
||||
@@ -1327,13 +1342,14 @@ proc sendAsync*(socket: TSocket, data: string): bool =
|
||||
return false
|
||||
else: OSError()
|
||||
|
||||
proc trySend*(socket: TSocket, data: string): bool =
|
||||
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
||||
## safe alternative to ``send``. Does not raise an EOS when an error occurs,
|
||||
## and instead returns ``false`` on failure.
|
||||
result = send(socket, cstring(data), data.len) == data.len
|
||||
|
||||
proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer,
|
||||
size: int, af: TDomain = AF_INET, flags = 0'i32): int =
|
||||
size: int, af: TDomain = AF_INET, flags = 0'i32): int {.
|
||||
tags: [FWriteIO].} =
|
||||
## low-level sendTo proc. This proc sends ``data`` to the specified ``address``,
|
||||
## which may be an IP address or a hostname, if a hostname is specified
|
||||
## this function will try each IP of that hostname.
|
||||
@@ -1359,7 +1375,8 @@ proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer,
|
||||
|
||||
freeaddrinfo(aiList)
|
||||
|
||||
proc sendTo*(socket: TSocket, address: string, port: TPort, data: string): int =
|
||||
proc sendTo*(socket: TSocket, address: string, port: TPort,
|
||||
data: string): int {.tags: [FWriteIO].} =
|
||||
## Friendlier version of the low-level ``sendTo``.
|
||||
result = socket.sendTo(address, port, cstring(data), data.len)
|
||||
|
||||
@@ -1391,7 +1408,7 @@ proc setBlocking*(s: TSocket, blocking: bool) =
|
||||
OSError()
|
||||
|
||||
proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),
|
||||
af: TDomain = AF_INET) =
|
||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||
## 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.
|
||||
|
||||
@@ -131,7 +131,7 @@ type
|
||||
months*: int ## The number of months
|
||||
years*: int ## The number of years
|
||||
|
||||
proc getTime*(): TTime ## gets the current calendar time
|
||||
proc getTime*(): TTime {.tags: [FTime].} ## gets the current calendar time
|
||||
proc getLocalTime*(t: TTime): TTimeInfo
|
||||
## converts the calendar time `t` to broken-time representation,
|
||||
## expressed relative to the user's specified time zone.
|
||||
@@ -164,14 +164,14 @@ proc `<=` * (a, b: TTime): bool {.
|
||||
## returns true iff ``a <= b``.
|
||||
result = a - b <= 0
|
||||
|
||||
proc getTzname*(): tuple[nonDST, DST: string]
|
||||
proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime].}
|
||||
## returns the local timezone; ``nonDST`` is the name of the local non-DST
|
||||
## timezone, ``DST`` is the name of the local DST timezone.
|
||||
|
||||
proc getTimezone*(): int
|
||||
proc getTimezone*(): int {.tags: [FTime].}
|
||||
## returns the offset of the local (non-DST) timezone in seconds west of UTC.
|
||||
|
||||
proc getStartMilsecs*(): int {.deprecated.}
|
||||
proc getStartMilsecs*(): int {.deprecated, tags: [FTime].}
|
||||
## get the miliseconds from the start of the program. **Deprecated since
|
||||
## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
|
||||
|
||||
@@ -247,12 +247,12 @@ proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
|
||||
result = getLocalTime(TTime(float(t) - secs))
|
||||
|
||||
when not defined(ECMAScript):
|
||||
proc epochTime*(): float {.rtl, extern: "nt$1".}
|
||||
proc epochTime*(): float {.rtl, extern: "nt$1", tags: [FTime].}
|
||||
## gets time after the UNIX epoch (1970) in seconds. It is a float
|
||||
## because sub-second resolution is likely to be supported (depending
|
||||
## on the hardware/OS).
|
||||
|
||||
proc cpuTime*(): float {.rtl, extern: "nt$1".}
|
||||
proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [FTime].}
|
||||
## gets time spent that the CPU spent to run the current process in
|
||||
## seconds. This may be more useful for benchmarking than ``epochTime``.
|
||||
## However, it may measure the real time instead (depending on the OS).
|
||||
@@ -478,13 +478,13 @@ else:
|
||||
return int(getTime() - startMilsecs)
|
||||
|
||||
|
||||
proc getDateStr*(): string {.rtl, extern: "nt$1".} =
|
||||
proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} =
|
||||
## gets the current date as a string of the format ``YYYY-MM-DD``.
|
||||
var ti = getLocalTime(getTime())
|
||||
result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
|
||||
'-' & intToStr(ti.monthDay, 2)
|
||||
|
||||
proc getClockStr*(): string {.rtl, extern: "nt$1".} =
|
||||
proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} =
|
||||
## gets the current clock time as a string of the format ``HH:MM:SS``.
|
||||
var ti = getLocalTime(getTime())
|
||||
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
line: 47
|
||||
line: 49
|
||||
file: "sysio.nim"
|
||||
errormsg: "can raise an unlisted exception: ref EIO"
|
||||
"""
|
||||
|
||||
@@ -11,7 +11,7 @@ type
|
||||
|
||||
EIO2 = ref object of EIO
|
||||
|
||||
proc raiser(): int {.tags: [TObj].} =
|
||||
proc raiser(): int {.tags: [TObj, FWriteIO].} =
|
||||
writeln stdout, "arg"
|
||||
|
||||
var o: TObjB
|
||||
|
||||
6
todo.txt
6
todo.txt
@@ -1,7 +1,11 @@
|
||||
version 0.9.2
|
||||
=============
|
||||
|
||||
- make the stdlib aware of tags: sockets, os
|
||||
- improve 'doc2':
|
||||
* respect output directory
|
||||
* write only 1 file unless requested 'whole project'
|
||||
* make it work for the 'system' module
|
||||
* the documentation system should default to 'doc2'
|
||||
- test&finish first class iterators:
|
||||
* allow return in first class iterators
|
||||
* nested iterators
|
||||
|
||||
@@ -8,9 +8,10 @@ Please choose your platform:
|
||||
(includes GCC and everything else you need)
|
||||
|
||||
The source-based installation has been tested on these systems:
|
||||
* Linux: i386, AMD64, PowerPC
|
||||
* Linux: i386, AMD64, PowerPC, ARM
|
||||
* BSD: AMD64
|
||||
* Mac OS X: i386, AMD64
|
||||
* Solaris: AMD64
|
||||
|
||||
Other UNIX-based operating systems may work.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user