mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
Merge remote-tracking branch 'nim-lang/devel' into emscripten-support
This commit is contained in:
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
language: c
|
||||
os: linux
|
||||
script:
|
||||
- git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
- cd csources && sh build.sh
|
||||
- ./bin/nim c koch
|
||||
- ./koch boot
|
||||
- ./koch boot -d:release
|
||||
after_script:
|
||||
- ./koch test
|
||||
@@ -48,7 +48,7 @@ proc handleCmdLine() =
|
||||
gProjectFull = canonicalizePath(gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
var p = splitFile(gProjectFull)
|
||||
let p = splitFile(gProjectFull)
|
||||
gProjectPath = p.dir
|
||||
gProjectName = p.name
|
||||
else:
|
||||
@@ -59,6 +59,9 @@ proc handleCmdLine() =
|
||||
runNimScript(scriptFile)
|
||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||
if scriptFile == gProjectFull: return
|
||||
elif fileExists(gProjectPath / "config.nims"):
|
||||
# directory wide NimScript file
|
||||
runNimScript(gProjectPath / "config.nims")
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
extccomp.initVars()
|
||||
|
||||
@@ -105,6 +105,13 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
|
||||
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
|
||||
cbconf setCommand:
|
||||
options.command = a.getString 0
|
||||
let arg = a.getString 1
|
||||
if arg.len > 0:
|
||||
gProjectName = arg
|
||||
try:
|
||||
gProjectFull = canonicalizePath(gProjectPath / gProjectName)
|
||||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
cbconf getCommand:
|
||||
setResult(a, options.command)
|
||||
cbconf switch:
|
||||
|
||||
@@ -1383,7 +1383,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||
elif arrayType == tyTypeDesc:
|
||||
c.genTypeLit(n.typ, dest)
|
||||
else:
|
||||
echo renderTree(n)
|
||||
genArrAccess2(c, n, dest, opcLdArr, flags)
|
||||
|
||||
proc getNullValueAux(obj: PNode, result: PNode) =
|
||||
|
||||
@@ -9,7 +9,8 @@ system.
|
||||
|
||||
So instead of a ``myproject.nim.cfg`` configuration file, you can use
|
||||
a ``myproject.nims`` file that simply contains Nim code controlling the
|
||||
compilation process.
|
||||
compilation process. For a directory wide configuration, use ``config.nims``
|
||||
instead of ``nim.cfg``.
|
||||
|
||||
The VM cannot deal with ``importc``, the FFI is not available, so there are not
|
||||
many stdlib modules that you can use with Nim's VM. However, at least the
|
||||
|
||||
71
lib/posix/kqueue.nim
Normal file
71
lib/posix/kqueue.nim
Normal file
@@ -0,0 +1,71 @@
|
||||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Adam Strzelecki
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
{.deadCodeElim:on.}
|
||||
|
||||
from posix import Timespec
|
||||
|
||||
# Filters:
|
||||
const
|
||||
EVFILT_READ* = -1
|
||||
EVFILT_WRITE* = -2
|
||||
EVFILT_AIO* = -3
|
||||
EVFILT_VNODE* = -4
|
||||
EVFILT_PROC* = -5
|
||||
EVFILT_SIGNAL* = -6
|
||||
EVFILT_TIMER* = -7
|
||||
EVFILT_MACHPORT* = -8
|
||||
EVFILT_FS* = -9
|
||||
EVFILT_USER* = -10
|
||||
# -11 is unused
|
||||
EVFILT_VM* = -12
|
||||
|
||||
# Actions:
|
||||
const
|
||||
EV_ADD* = 0x0001 ## Add event to queue (implies enable).
|
||||
## Re-adding an existing element modifies it.
|
||||
EV_DELETE* = 0x0002 ## Delete event from queue.
|
||||
EV_ENABLE* = 0x0004 ## Enable event.
|
||||
EV_DISABLE* = 0x0008 ## Disable event (not reported).
|
||||
|
||||
# Flags:
|
||||
const
|
||||
EV_ONESHOT* = 0x0010 ## Only report one occurrence.
|
||||
EV_CLEAR* = 0x0020 ## Clear event state after reporting.
|
||||
EV_RECEIPT* = 0x0040 ## Force EV_ERROR on success, data == 0
|
||||
EV_DISPATCH* = 0x0080 ## Disable event after reporting.
|
||||
|
||||
# Return values:
|
||||
const
|
||||
EV_EOF* = 0x8000 ## EOF detected
|
||||
EV_ERROR* = 0x4000 ## Error, data contains errno
|
||||
|
||||
type
|
||||
KEvent* {.importc: "struct kevent",
|
||||
header: "<sys/event.h>", pure, final.} = object
|
||||
ident*: cuint ## identifier for this event (uintptr_t)
|
||||
filter*: cshort ## filter for event
|
||||
flags*: cushort ## general flags
|
||||
fflags*: cuint ## filter-specific flags
|
||||
data*: cuint ## filter-specific data (intptr_t)
|
||||
#udata*: ptr void ## opaque user data identifier
|
||||
|
||||
proc kqueue*(): cint {.importc: "kqueue", header: "<sys/event.h>".}
|
||||
## Creates new queue and returns its descriptor.
|
||||
|
||||
proc kevent*(kqFD: cint,
|
||||
changelist: ptr KEvent, nchanges: cint,
|
||||
eventlist: ptr KEvent, nevents: cint, timeout: ptr Timespec): cint
|
||||
{.importc: "kevent", header: "<sys/event.h>".}
|
||||
## Manipulates queue for given ``kqFD`` descriptor.
|
||||
|
||||
proc EV_SET*(event: ptr KEvent, ident: cuint, filter: cshort, flags: cushort,
|
||||
fflags: cuint, data: cuint, udata: ptr void)
|
||||
{.importc: "EV_SET", header: "<sys/event.h>".}
|
||||
## Fills event with given data.
|
||||
@@ -810,11 +810,12 @@ type
|
||||
|
||||
{.deprecated: [TPathComponent: PathComponent].}
|
||||
|
||||
iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
|
||||
iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path: string] {.
|
||||
tags: [ReadDirEffect].} =
|
||||
## 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.
|
||||
## Walking is not recursive. If ``relative`` is true the resulting path is
|
||||
## shortened to be relative to ``dir``.
|
||||
## Example: This directory structure::
|
||||
## dirA / dirB / fileB1.txt
|
||||
## / dirC
|
||||
@@ -843,7 +844,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
|
||||
k = pcDir
|
||||
if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
|
||||
k = succ(k)
|
||||
yield (k, dir / extractFilename(getFilename(f)))
|
||||
let xx = if relative: extractFilename(getFilename(f))
|
||||
else: dir / extractFilename(getFilename(f))
|
||||
yield (k, xx)
|
||||
if findNextFile(h, f) == 0'i32: break
|
||||
findClose(h)
|
||||
else:
|
||||
@@ -855,7 +858,8 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
|
||||
var y = $x.d_name
|
||||
if y != "." and y != "..":
|
||||
var s: Stat
|
||||
y = dir / y
|
||||
if not relative:
|
||||
y = dir / y
|
||||
var k = pcFile
|
||||
|
||||
when defined(linux) or defined(macosx) or defined(bsd):
|
||||
|
||||
@@ -24,6 +24,20 @@ when defined(linux):
|
||||
import linux
|
||||
|
||||
type
|
||||
ProcessOption* = enum ## options that can be passed `startProcess`
|
||||
poEchoCmd, ## echo the command before execution
|
||||
poUsePath, ## Asks system to search for executable using PATH environment
|
||||
## variable.
|
||||
## On Windows, this is the default.
|
||||
poEvalCommand, ## Pass `command` directly to the shell, without quoting.
|
||||
## Use it only if `command` comes from trused source.
|
||||
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
|
||||
poParentStreams, ## use the parent's streams
|
||||
poInteractive ## optimize the buffer handling for responsiveness for
|
||||
## UI applications. Currently this only affects
|
||||
## Windows: Named pipes are used so that you can peek
|
||||
## at the process' output streams.
|
||||
|
||||
ProcessObj = object of RootObj
|
||||
when defined(windows):
|
||||
fProcessHandle: Handle
|
||||
@@ -34,18 +48,10 @@ type
|
||||
inStream, outStream, errStream: Stream
|
||||
id: Pid
|
||||
exitCode: cint
|
||||
options: set[ProcessOption]
|
||||
|
||||
Process* = ref ProcessObj ## represents an operating system process
|
||||
|
||||
ProcessOption* = enum ## options that can be passed `startProcess`
|
||||
poEchoCmd, ## echo the command before execution
|
||||
poUsePath, ## Asks system to search for executable using PATH environment
|
||||
## variable.
|
||||
## On Windows, this is the default.
|
||||
poEvalCommand, ## Pass `command` directly to the shell, without quoting.
|
||||
## Use it only if `command` comes from trused source.
|
||||
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
|
||||
poParentStreams ## use the parent's streams
|
||||
|
||||
{.deprecated: [TProcess: ProcessObj, PProcess: Process,
|
||||
TProcessOption: ProcessOption].}
|
||||
@@ -302,7 +308,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||
result = max(waitForExit(p), result)
|
||||
close(p)
|
||||
|
||||
proc select*(readfds: var seq[Process], timeout = 500): int
|
||||
proc select*(readfds: var seq[Process], timeout = 500): int {.benign.}
|
||||
## `select` with a sensible Nim interface. `timeout` is in milliseconds.
|
||||
## Specify -1 for no timeout. Returns the number of processes that are
|
||||
## ready to read from. The processes that are ready to be read from are
|
||||
@@ -394,13 +400,68 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
#var
|
||||
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
|
||||
# O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
|
||||
proc myDup(h: Handle; inherit: WinBool=1): Handle =
|
||||
let thisProc = getCurrentProcess()
|
||||
if duplicateHandle(thisProc, h,
|
||||
thisProc, addr result,0,inherit,
|
||||
DUPLICATE_SAME_ACCESS) == 0:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc createAllPipeHandles(si: var STARTUPINFO;
|
||||
stdin, stdout, stderr: var Handle) =
|
||||
var sa: SECURITY_ATTRIBUTES
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
|
||||
sa.lpSecurityDescriptor = nil
|
||||
sa.bInheritHandle = 1
|
||||
let pipeOutName = newWideCString(r"\\.\pipe\stdout")
|
||||
let pipeInName = newWideCString(r"\\.\pipe\stdin")
|
||||
let pipeOut = createNamedPipe(pipeOutName,
|
||||
dwOpenMode=PIPE_ACCESS_INBOUND or FILE_FLAG_WRITE_THROUGH,
|
||||
dwPipeMode=PIPE_NOWAIT,
|
||||
nMaxInstances=1,
|
||||
nOutBufferSize=1024, nInBufferSize=1024,
|
||||
nDefaultTimeOut=0,addr sa)
|
||||
if pipeOut == INVALID_HANDLE_VALUE:
|
||||
raiseOSError(osLastError())
|
||||
let pipeIn = createNamedPipe(pipeInName,
|
||||
dwOpenMode=PIPE_ACCESS_OUTBOUND or FILE_FLAG_WRITE_THROUGH,
|
||||
dwPipeMode=PIPE_NOWAIT,
|
||||
nMaxInstances=1,
|
||||
nOutBufferSize=1024, nInBufferSize=1024,
|
||||
nDefaultTimeOut=0,addr sa)
|
||||
if pipeIn == INVALID_HANDLE_VALUE:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
si.hStdOutput = createFileW(pipeOutName,
|
||||
FILE_WRITE_DATA or SYNCHRONIZE, 0, addr sa,
|
||||
OPEN_EXISTING, # very important flag!
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0 # no template file for OPEN_EXISTING
|
||||
)
|
||||
if si.hStdOutput == INVALID_HANDLE_VALUE:
|
||||
raiseOSError(osLastError())
|
||||
si.hStdError = myDup(si.hStdOutput)
|
||||
si.hStdInput = createFileW(pipeInName,
|
||||
FILE_READ_DATA or SYNCHRONIZE, 0, addr sa,
|
||||
OPEN_EXISTING, # very important flag!
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0 # no template file for OPEN_EXISTING
|
||||
)
|
||||
if si.hStdOutput == INVALID_HANDLE_VALUE:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
stdin = myDup(pipeIn, 0)
|
||||
stdout = myDup(pipeOut, 0)
|
||||
discard closeHandle(pipeIn)
|
||||
discard closeHandle(pipeOut)
|
||||
stderr = stdout
|
||||
|
||||
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
|
||||
var piInheritablePipe: SECURITY_ATTRIBUTES
|
||||
piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
|
||||
piInheritablePipe.lpSecurityDescriptor = nil
|
||||
piInheritablePipe.bInheritHandle = 1
|
||||
if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
|
||||
var sa: SECURITY_ATTRIBUTES
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
|
||||
sa.lpSecurityDescriptor = nil
|
||||
sa.bInheritHandle = 1
|
||||
if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc fileClose(h: Handle) {.inline.} =
|
||||
@@ -417,16 +478,20 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
success: int
|
||||
hi, ho, he: Handle
|
||||
new(result)
|
||||
result.options = options
|
||||
si.cb = sizeof(si).cint
|
||||
if poParentStreams notin options:
|
||||
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
|
||||
createPipeHandles(si.hStdInput, hi)
|
||||
createPipeHandles(ho, si.hStdOutput)
|
||||
if poStdErrToStdOut in options:
|
||||
si.hStdError = si.hStdOutput
|
||||
he = ho
|
||||
if poInteractive notin options:
|
||||
createPipeHandles(si.hStdInput, hi)
|
||||
createPipeHandles(ho, si.hStdOutput)
|
||||
if poStdErrToStdOut in options:
|
||||
si.hStdError = si.hStdOutput
|
||||
he = ho
|
||||
else:
|
||||
createPipeHandles(he, si.hStdError)
|
||||
else:
|
||||
createPipeHandles(he, si.hStdError)
|
||||
createAllPipeHandles(si, hi, ho, he)
|
||||
result.inHandle = FileHandle(hi)
|
||||
result.outHandle = FileHandle(ho)
|
||||
result.errHandle = FileHandle(he)
|
||||
@@ -469,6 +534,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
|
||||
if e != nil: dealloc(e)
|
||||
if success == 0:
|
||||
if poInteractive in result.options: close(result)
|
||||
const errInvalidParameter = 87.int
|
||||
const errFileNotFound = 2.int
|
||||
if lastError.int in {errInvalidParameter, errFileNotFound}:
|
||||
@@ -482,12 +548,12 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
result.id = procInfo.dwProcessId
|
||||
|
||||
proc close(p: Process) =
|
||||
when false:
|
||||
# somehow this does not work on Windows:
|
||||
if poInteractive in p.options:
|
||||
# somehow this is not always required on Windows:
|
||||
discard closeHandle(p.inHandle)
|
||||
discard closeHandle(p.outHandle)
|
||||
discard closeHandle(p.errHandle)
|
||||
discard closeHandle(p.FProcessHandle)
|
||||
#discard closeHandle(p.FProcessHandle)
|
||||
|
||||
proc suspend(p: Process) =
|
||||
discard suspendThread(p.fProcessHandle)
|
||||
@@ -564,7 +630,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
|
||||
var rfds: WOHandleArray
|
||||
for i in 0..readfds.len()-1:
|
||||
rfds[i] = readfds[i].fProcessHandle
|
||||
rfds[i] = readfds[i].outHandle #fProcessHandle
|
||||
|
||||
var ret = waitForMultipleObjects(readfds.len.int32,
|
||||
addr(rfds), 0'i32, timeout.int32)
|
||||
@@ -578,6 +644,11 @@ when defined(Windows) and not defined(useNimRtl):
|
||||
readfds.del(i)
|
||||
return 1
|
||||
|
||||
proc hasData*(p: Process): bool =
|
||||
var x: int32
|
||||
if peekNamedPipe(p.outHandle, lpTotalBytesAvail=addr x):
|
||||
result = x > 0
|
||||
|
||||
elif not defined(useNimRtl):
|
||||
const
|
||||
readIdx = 0
|
||||
@@ -635,6 +706,7 @@ elif not defined(useNimRtl):
|
||||
var
|
||||
pStdin, pStdout, pStderr: array [0..1, cint]
|
||||
new(result)
|
||||
result.options = options
|
||||
result.exitCode = -3 # for ``waitForExit``
|
||||
if poParentStreams notin options:
|
||||
if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
|
||||
@@ -960,6 +1032,15 @@ elif not defined(useNimRtl):
|
||||
|
||||
pruneProcessSet(readfds, (rd))
|
||||
|
||||
proc hasData*(p: Process): bool =
|
||||
var rd: TFdSet
|
||||
|
||||
FD_ZERO(rd)
|
||||
let m = max(0, int(p.outHandle))
|
||||
FD_SET(cint(p.outHandle), rd)
|
||||
|
||||
result = int(select(cint(m+1), addr(rd), nil, nil, nil)) == 1
|
||||
|
||||
|
||||
proc execCmdEx*(command: string, options: set[ProcessOption] = {
|
||||
poStdErrToStdOut, poUsePath}): tuple[
|
||||
|
||||
@@ -13,6 +13,8 @@ import os, unsigned, hashes
|
||||
|
||||
when defined(linux):
|
||||
import posix, epoll
|
||||
elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
|
||||
import posix, kqueue, times
|
||||
elif defined(windows):
|
||||
import winlean
|
||||
else:
|
||||
@@ -79,7 +81,6 @@ when defined(nimdoc):
|
||||
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
|
||||
## Retrieves the selector key for ``fd``.
|
||||
|
||||
|
||||
elif defined(linux):
|
||||
type
|
||||
Selector* = object
|
||||
@@ -99,15 +100,13 @@ elif defined(linux):
|
||||
result.data.fd = fd.cint
|
||||
|
||||
proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
|
||||
data: SelectorData) =
|
||||
data: SelectorData) =
|
||||
var event = createEventStruct(events, fd)
|
||||
if events != {}:
|
||||
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
var key = SelectorKey(fd: fd, events: events, data: data)
|
||||
|
||||
s.fds[fd] = key
|
||||
s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
|
||||
|
||||
proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
|
||||
if s.fds[fd].events != events:
|
||||
@@ -154,11 +153,6 @@ elif defined(linux):
|
||||
raiseOSError(err)
|
||||
|
||||
proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
|
||||
##
|
||||
## The ``events`` field of the returned ``key`` contains the original events
|
||||
## for which the ``fd`` was bound. This is contrary to the ``events`` field
|
||||
## of the ``TReadyInfo`` tuple which determines which events are ready
|
||||
## on the ``fd``.
|
||||
result = @[]
|
||||
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
|
||||
if evNum < 0:
|
||||
@@ -204,6 +198,86 @@ elif defined(linux):
|
||||
## Retrieves the selector key for ``fd``.
|
||||
return s.fds[fd]
|
||||
|
||||
elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
|
||||
type
|
||||
Selector* = object
|
||||
kqFD: cint
|
||||
events: array[64, KEvent]
|
||||
when MultiThreaded:
|
||||
fds: SharedTable[SocketHandle, SelectorKey]
|
||||
else:
|
||||
fds: Table[SocketHandle, SelectorKey]
|
||||
|
||||
template modifyKQueue(kqFD: cint, fd: SocketHandle, event: Event,
|
||||
op: cushort) =
|
||||
var kev = KEvent(ident: fd.cuint,
|
||||
filter: if event == EvRead: EVFILT_READ else: EVFILT_WRITE,
|
||||
flags: op)
|
||||
if kevent(kqFD, addr kev, 1, nil, 0, nil) == -1:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc register*(s: var Selector, fd: SocketHandle, events: set[Event],
|
||||
data: SelectorData) =
|
||||
for event in events:
|
||||
modifyKQueue(s.kqFD, fd, event, EV_ADD)
|
||||
s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
|
||||
|
||||
proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
|
||||
let previousEvents = s.fds[fd].events
|
||||
if previousEvents != events:
|
||||
for event in events-previousEvents:
|
||||
modifyKQueue(s.kqFD, fd, event, EV_ADD)
|
||||
for event in previousEvents-events:
|
||||
modifyKQueue(s.kqFD, fd, event, EV_DELETE)
|
||||
s.fds.mget(fd).events = events
|
||||
|
||||
proc unregister*(s: var Selector, fd: SocketHandle) =
|
||||
for event in s.fds[fd].events:
|
||||
modifyKQueue(s.kqFD, fd, event, EV_DELETE)
|
||||
s.fds.del(fd)
|
||||
|
||||
proc close*(s: var Selector) =
|
||||
when MultiThreaded: deinitSharedTable(s.fds)
|
||||
if s.kqFD.close() != 0: raiseOSError(osLastError())
|
||||
|
||||
proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
|
||||
result = @[]
|
||||
var tv = Timespec(tv_sec: timeout.Time, tv_nsec: 0)
|
||||
let evNum = kevent(s.kqFD, nil, 0, addr s.events[0], 64.cint, addr tv)
|
||||
if evNum < 0:
|
||||
let err = osLastError()
|
||||
if err.cint == EINTR:
|
||||
return @[]
|
||||
raiseOSError(err)
|
||||
if evNum == 0: return @[]
|
||||
for i in 0 .. <evNum:
|
||||
let fd = s.events[i].ident.SocketHandle
|
||||
|
||||
var evSet: set[Event] = {}
|
||||
if (s.events[i].flags and EV_EOF) != 0: evSet = evSet + {EvError}
|
||||
if s.events[i].filter == EVFILT_READ: evSet = evSet + {EvRead}
|
||||
elif s.events[i].filter == EVFILT_WRITE: evSet = evSet + {EvWrite}
|
||||
let selectorKey = s.fds[fd]
|
||||
assert selectorKey.fd != 0.SocketHandle
|
||||
result.add((selectorKey, evSet))
|
||||
|
||||
proc newSelector*(): Selector =
|
||||
result.kqFD = kqueue()
|
||||
if result.kqFD < 0:
|
||||
raiseOSError(osLastError())
|
||||
when MultiThreaded:
|
||||
result.fds = initSharedTable[SocketHandle, SelectorKey]()
|
||||
else:
|
||||
result.fds = initTable[SocketHandle, SelectorKey]()
|
||||
|
||||
proc contains*(s: Selector, fd: SocketHandle): bool =
|
||||
## Determines whether selector contains a file descriptor.
|
||||
s.fds.hasKey(fd) # and s.fds[fd].events != {}
|
||||
|
||||
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
|
||||
## Retrieves the selector key for ``fd``.
|
||||
return s.fds[fd]
|
||||
|
||||
elif not defined(nimdoc):
|
||||
# TODO: kqueue for bsd/mac os x.
|
||||
type
|
||||
|
||||
@@ -101,6 +101,18 @@ proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
|
||||
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||
result = s.readDataImpl(s, buffer, bufLen)
|
||||
|
||||
proc readAll*(s: Stream): string =
|
||||
## Reads all available data.
|
||||
result = newString(1000)
|
||||
var r = 0
|
||||
while true:
|
||||
let readBytes = readData(s, addr(result[r]), 1000)
|
||||
if readBytes < 1000:
|
||||
setLen(result, r+readBytes)
|
||||
break
|
||||
inc r, 1000
|
||||
setLen(result, r+1000)
|
||||
|
||||
proc readData*(s, unused: Stream, buffer: pointer,
|
||||
bufLen: int): int {.deprecated.} =
|
||||
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||
|
||||
@@ -1340,10 +1340,9 @@ proc lastRune*(s: string; last: int): (Rune, int) =
|
||||
else:
|
||||
var L = 0
|
||||
while last-L >= 0 and ord(s[last-L]) shr 6 == 0b10: inc(L)
|
||||
inc(L)
|
||||
var r: Rune
|
||||
fastRuneAt(s, last-L, r, false)
|
||||
result = (r, L)
|
||||
result = (r, L+1)
|
||||
|
||||
when isMainModule:
|
||||
let
|
||||
|
||||
@@ -56,7 +56,7 @@ proc getCommand*(): string =
|
||||
## "c", "js", "build", "help".
|
||||
builtin
|
||||
|
||||
proc setCommand*(cmd: string) =
|
||||
proc setCommand*(cmd: string; project="") =
|
||||
## Sets the Nim command that should be continued with after this Nimscript
|
||||
## has finished.
|
||||
builtin
|
||||
|
||||
@@ -108,6 +108,13 @@ const
|
||||
|
||||
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
|
||||
|
||||
PIPE_ACCESS_DUPLEX* = 0x00000003'i32
|
||||
PIPE_ACCESS_INBOUND* = 1'i32
|
||||
PIPE_ACCESS_OUTBOUND* = 2'i32
|
||||
PIPE_NOWAIT* = 0x00000001'i32
|
||||
SYNCHRONIZE* = 0x00100000'i32
|
||||
FILE_FLAG_WRITE_THROUGH* = 0x80000000'i32
|
||||
|
||||
proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "CloseHandle".}
|
||||
|
||||
@@ -125,6 +132,19 @@ proc createPipe*(hReadPipe, hWritePipe: var Handle,
|
||||
nSize: int32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
|
||||
|
||||
proc createNamedPipe*(lpName: WideCString,
|
||||
dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize,
|
||||
nInBufferSize, nDefaultTimeOut: int32,
|
||||
lpSecurityAttributes: ptr SECURITY_ATTRIBUTES): Handle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateNamedPipeW".}
|
||||
|
||||
proc peekNamedPipe*(hNamedPipe: Handle, lpBuffer: pointer=nil,
|
||||
nBufferSize: int32 = 0,
|
||||
lpBytesRead: ptr int32 = nil,
|
||||
lpTotalBytesAvail: ptr int32 = nil,
|
||||
lpBytesLeftThisMessage: ptr int32 = nil): bool {.
|
||||
stdcall, dynlib: "kernel32", importc: "PeekNamedPipe".}
|
||||
|
||||
when useWinUnicode:
|
||||
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
|
||||
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
|
||||
@@ -615,12 +635,24 @@ const
|
||||
|
||||
FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
|
||||
FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'i32
|
||||
DUPLICATE_SAME_ACCESS* = 2
|
||||
FILE_READ_DATA* = 0x00000001 # file & pipe
|
||||
FILE_WRITE_DATA* = 0x00000002 # file & pipe
|
||||
|
||||
# Error Constants
|
||||
const
|
||||
ERROR_ACCESS_DENIED* = 5
|
||||
ERROR_HANDLE_EOF* = 38
|
||||
|
||||
proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE,
|
||||
hTargetProcessHandle: HANDLE,
|
||||
lpTargetHandle: ptr HANDLE,
|
||||
dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,
|
||||
dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",
|
||||
importc: "DuplicateHandle".}
|
||||
proc getCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32",
|
||||
importc: "GetCurrentProcess".}
|
||||
|
||||
when useWinUnicode:
|
||||
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
|
||||
lpSecurityAttributes: pointer,
|
||||
|
||||
Reference in New Issue
Block a user