Merge remote-tracking branch 'origin/devel' into bitsize-pragma
This commit is contained in:
commit
e5ba94b1f8
14 changed files with 348 additions and 45 deletions
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)
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
except OSError:
|
except OSError:
|
||||||
gProjectFull = gProjectName
|
gProjectFull = gProjectName
|
||||||
var p = splitFile(gProjectFull)
|
let p = splitFile(gProjectFull)
|
||||||
gProjectPath = p.dir
|
gProjectPath = p.dir
|
||||||
gProjectName = p.name
|
gProjectName = p.name
|
||||||
else:
|
else:
|
||||||
|
|
@ -59,6 +59,9 @@ proc handleCmdLine() =
|
||||||
runNimScript(scriptFile)
|
runNimScript(scriptFile)
|
||||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||||
if scriptFile == gProjectFull: return
|
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
|
# now process command line arguments again, because some options in the
|
||||||
# command line can overwite the config file's settings
|
# command line can overwite the config file's settings
|
||||||
extccomp.initVars()
|
extccomp.initVars()
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,13 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
|
||||||
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
|
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
|
||||||
cbconf setCommand:
|
cbconf setCommand:
|
||||||
options.command = a.getString 0
|
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:
|
cbconf getCommand:
|
||||||
setResult(a, options.command)
|
setResult(a, options.command)
|
||||||
cbconf switch:
|
cbconf switch:
|
||||||
|
|
|
||||||
|
|
@ -1383,7 +1383,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
elif arrayType == tyTypeDesc:
|
elif arrayType == tyTypeDesc:
|
||||||
c.genTypeLit(n.typ, dest)
|
c.genTypeLit(n.typ, dest)
|
||||||
else:
|
else:
|
||||||
echo renderTree(n)
|
|
||||||
genArrAccess2(c, n, dest, opcLdArr, flags)
|
genArrAccess2(c, n, dest, opcLdArr, flags)
|
||||||
|
|
||||||
proc getNullValueAux(obj: PNode, result: PNode) =
|
proc getNullValueAux(obj: PNode, result: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ system.
|
||||||
|
|
||||||
So instead of a ``myproject.nim.cfg`` configuration file, you can use
|
So instead of a ``myproject.nim.cfg`` configuration file, you can use
|
||||||
a ``myproject.nims`` file that simply contains Nim code controlling the
|
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
|
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
|
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].}
|
{.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].} =
|
tags: [ReadDirEffect].} =
|
||||||
## walks over the directory `dir` and yields for each directory or file in
|
## 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.
|
## `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::
|
## Example: This directory structure::
|
||||||
## dirA / dirB / fileB1.txt
|
## dirA / dirB / fileB1.txt
|
||||||
## / dirC
|
## / dirC
|
||||||
|
|
@ -843,7 +844,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
|
||||||
k = pcDir
|
k = pcDir
|
||||||
if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
|
if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
|
||||||
k = succ(k)
|
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
|
if findNextFile(h, f) == 0'i32: break
|
||||||
findClose(h)
|
findClose(h)
|
||||||
else:
|
else:
|
||||||
|
|
@ -855,6 +858,7 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
|
||||||
var y = $x.d_name
|
var y = $x.d_name
|
||||||
if y != "." and y != "..":
|
if y != "." and y != "..":
|
||||||
var s: Stat
|
var s: Stat
|
||||||
|
if not relative:
|
||||||
y = dir / y
|
y = dir / y
|
||||||
var k = pcFile
|
var k = pcFile
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,20 @@ when defined(linux):
|
||||||
import linux
|
import linux
|
||||||
|
|
||||||
type
|
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
|
ProcessObj = object of RootObj
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
fProcessHandle: Handle
|
fProcessHandle: Handle
|
||||||
|
|
@ -34,18 +48,10 @@ type
|
||||||
inStream, outStream, errStream: Stream
|
inStream, outStream, errStream: Stream
|
||||||
id: Pid
|
id: Pid
|
||||||
exitCode: cint
|
exitCode: cint
|
||||||
|
options: set[ProcessOption]
|
||||||
|
|
||||||
Process* = ref ProcessObj ## represents an operating system process
|
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,
|
{.deprecated: [TProcess: ProcessObj, PProcess: Process,
|
||||||
TProcessOption: ProcessOption].}
|
TProcessOption: ProcessOption].}
|
||||||
|
|
@ -302,7 +308,7 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
result = max(waitForExit(p), result)
|
result = max(waitForExit(p), result)
|
||||||
close(p)
|
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.
|
## `select` with a sensible Nim interface. `timeout` is in milliseconds.
|
||||||
## Specify -1 for no timeout. Returns the number of processes that are
|
## 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
|
## 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
|
#var
|
||||||
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
|
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
|
||||||
# O_RDONLY {.importc: "_O_RDONLY", 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) =
|
proc createPipeHandles(rdHandle, wrHandle: var Handle) =
|
||||||
var piInheritablePipe: SECURITY_ATTRIBUTES
|
var sa: SECURITY_ATTRIBUTES
|
||||||
piInheritablePipe.nLength = sizeof(SECURITY_ATTRIBUTES).cint
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
|
||||||
piInheritablePipe.lpSecurityDescriptor = nil
|
sa.lpSecurityDescriptor = nil
|
||||||
piInheritablePipe.bInheritHandle = 1
|
sa.bInheritHandle = 1
|
||||||
if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
|
if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
proc fileClose(h: Handle) {.inline.} =
|
proc fileClose(h: Handle) {.inline.} =
|
||||||
|
|
@ -417,9 +478,11 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
success: int
|
success: int
|
||||||
hi, ho, he: Handle
|
hi, ho, he: Handle
|
||||||
new(result)
|
new(result)
|
||||||
|
result.options = options
|
||||||
si.cb = sizeof(si).cint
|
si.cb = sizeof(si).cint
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
|
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
|
||||||
|
if poInteractive notin options:
|
||||||
createPipeHandles(si.hStdInput, hi)
|
createPipeHandles(si.hStdInput, hi)
|
||||||
createPipeHandles(ho, si.hStdOutput)
|
createPipeHandles(ho, si.hStdOutput)
|
||||||
if poStdErrToStdOut in options:
|
if poStdErrToStdOut in options:
|
||||||
|
|
@ -427,6 +490,8 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
he = ho
|
he = ho
|
||||||
else:
|
else:
|
||||||
createPipeHandles(he, si.hStdError)
|
createPipeHandles(he, si.hStdError)
|
||||||
|
else:
|
||||||
|
createAllPipeHandles(si, hi, ho, he)
|
||||||
result.inHandle = FileHandle(hi)
|
result.inHandle = FileHandle(hi)
|
||||||
result.outHandle = FileHandle(ho)
|
result.outHandle = FileHandle(ho)
|
||||||
result.errHandle = FileHandle(he)
|
result.errHandle = FileHandle(he)
|
||||||
|
|
@ -469,6 +534,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
|
|
||||||
if e != nil: dealloc(e)
|
if e != nil: dealloc(e)
|
||||||
if success == 0:
|
if success == 0:
|
||||||
|
if poInteractive in result.options: close(result)
|
||||||
const errInvalidParameter = 87.int
|
const errInvalidParameter = 87.int
|
||||||
const errFileNotFound = 2.int
|
const errFileNotFound = 2.int
|
||||||
if lastError.int in {errInvalidParameter, errFileNotFound}:
|
if lastError.int in {errInvalidParameter, errFileNotFound}:
|
||||||
|
|
@ -482,12 +548,12 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
result.id = procInfo.dwProcessId
|
result.id = procInfo.dwProcessId
|
||||||
|
|
||||||
proc close(p: Process) =
|
proc close(p: Process) =
|
||||||
when false:
|
if poInteractive in p.options:
|
||||||
# somehow this does not work on Windows:
|
# somehow this is not always required on Windows:
|
||||||
discard closeHandle(p.inHandle)
|
discard closeHandle(p.inHandle)
|
||||||
discard closeHandle(p.outHandle)
|
discard closeHandle(p.outHandle)
|
||||||
discard closeHandle(p.errHandle)
|
discard closeHandle(p.errHandle)
|
||||||
discard closeHandle(p.FProcessHandle)
|
#discard closeHandle(p.FProcessHandle)
|
||||||
|
|
||||||
proc suspend(p: Process) =
|
proc suspend(p: Process) =
|
||||||
discard suspendThread(p.fProcessHandle)
|
discard suspendThread(p.fProcessHandle)
|
||||||
|
|
@ -564,7 +630,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
|
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
|
||||||
var rfds: WOHandleArray
|
var rfds: WOHandleArray
|
||||||
for i in 0..readfds.len()-1:
|
for i in 0..readfds.len()-1:
|
||||||
rfds[i] = readfds[i].fProcessHandle
|
rfds[i] = readfds[i].outHandle #fProcessHandle
|
||||||
|
|
||||||
var ret = waitForMultipleObjects(readfds.len.int32,
|
var ret = waitForMultipleObjects(readfds.len.int32,
|
||||||
addr(rfds), 0'i32, timeout.int32)
|
addr(rfds), 0'i32, timeout.int32)
|
||||||
|
|
@ -578,6 +644,11 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
readfds.del(i)
|
readfds.del(i)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
proc hasData*(p: Process): bool =
|
||||||
|
var x: int32
|
||||||
|
if peekNamedPipe(p.outHandle, lpTotalBytesAvail=addr x):
|
||||||
|
result = x > 0
|
||||||
|
|
||||||
elif not defined(useNimRtl):
|
elif not defined(useNimRtl):
|
||||||
const
|
const
|
||||||
readIdx = 0
|
readIdx = 0
|
||||||
|
|
@ -635,6 +706,7 @@ elif not defined(useNimRtl):
|
||||||
var
|
var
|
||||||
pStdin, pStdout, pStderr: array [0..1, cint]
|
pStdin, pStdout, pStderr: array [0..1, cint]
|
||||||
new(result)
|
new(result)
|
||||||
|
result.options = options
|
||||||
result.exitCode = -3 # for ``waitForExit``
|
result.exitCode = -3 # for ``waitForExit``
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
|
if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
|
||||||
|
|
@ -960,6 +1032,15 @@ elif not defined(useNimRtl):
|
||||||
|
|
||||||
pruneProcessSet(readfds, (rd))
|
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] = {
|
proc execCmdEx*(command: string, options: set[ProcessOption] = {
|
||||||
poStdErrToStdOut, poUsePath}): tuple[
|
poStdErrToStdOut, poUsePath}): tuple[
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import os, unsigned, hashes
|
||||||
|
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
import posix, epoll
|
import posix, epoll
|
||||||
|
elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
|
||||||
|
import posix, kqueue, times
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
import winlean
|
import winlean
|
||||||
else:
|
else:
|
||||||
|
|
@ -79,7 +81,6 @@ when defined(nimdoc):
|
||||||
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
|
proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
|
||||||
## Retrieves the selector key for ``fd``.
|
## Retrieves the selector key for ``fd``.
|
||||||
|
|
||||||
|
|
||||||
elif defined(linux):
|
elif defined(linux):
|
||||||
type
|
type
|
||||||
Selector* = object
|
Selector* = object
|
||||||
|
|
@ -105,9 +106,7 @@ elif defined(linux):
|
||||||
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
|
if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
var key = SelectorKey(fd: fd, events: events, data: data)
|
s.fds[fd] = SelectorKey(fd: fd, events: events, data: data)
|
||||||
|
|
||||||
s.fds[fd] = key
|
|
||||||
|
|
||||||
proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
|
proc update*(s: var Selector, fd: SocketHandle, events: set[Event]) =
|
||||||
if s.fds[fd].events != events:
|
if s.fds[fd].events != events:
|
||||||
|
|
@ -154,11 +153,6 @@ elif defined(linux):
|
||||||
raiseOSError(err)
|
raiseOSError(err)
|
||||||
|
|
||||||
proc select*(s: var Selector, timeout: int): seq[ReadyInfo] =
|
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 = @[]
|
result = @[]
|
||||||
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
|
let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
|
||||||
if evNum < 0:
|
if evNum < 0:
|
||||||
|
|
@ -204,6 +198,86 @@ elif defined(linux):
|
||||||
## Retrieves the selector key for ``fd``.
|
## Retrieves the selector key for ``fd``.
|
||||||
return s.fds[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):
|
elif not defined(nimdoc):
|
||||||
# TODO: kqueue for bsd/mac os x.
|
# TODO: kqueue for bsd/mac os x.
|
||||||
type
|
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.
|
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
||||||
result = s.readDataImpl(s, buffer, bufLen)
|
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,
|
proc readData*(s, unused: Stream, buffer: pointer,
|
||||||
bufLen: int): int {.deprecated.} =
|
bufLen: int): int {.deprecated.} =
|
||||||
## low level proc that reads data into an untyped `buffer` of `bufLen` size.
|
## 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:
|
else:
|
||||||
var L = 0
|
var L = 0
|
||||||
while last-L >= 0 and ord(s[last-L]) shr 6 == 0b10: inc(L)
|
while last-L >= 0 and ord(s[last-L]) shr 6 == 0b10: inc(L)
|
||||||
inc(L)
|
|
||||||
var r: Rune
|
var r: Rune
|
||||||
fastRuneAt(s, last-L, r, false)
|
fastRuneAt(s, last-L, r, false)
|
||||||
result = (r, L)
|
result = (r, L+1)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
let
|
let
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ proc parseUri*(uri: string): Uri =
|
||||||
parseUri(uri, result)
|
parseUri(uri, result)
|
||||||
|
|
||||||
proc removeDotSegments(path: string): string =
|
proc removeDotSegments(path: string): string =
|
||||||
|
if path.len == 0: return ""
|
||||||
var collection: seq[string] = @[]
|
var collection: seq[string] = @[]
|
||||||
let endsWithSlash = path[path.len-1] == '/'
|
let endsWithSlash = path[path.len-1] == '/'
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -432,3 +433,12 @@ when isMainModule:
|
||||||
block:
|
block:
|
||||||
let test = parseUri("http://example.com/foo/") / "/bar/asd"
|
let test = parseUri("http://example.com/foo/") / "/bar/asd"
|
||||||
doAssert test.path == "/foo/bar/asd"
|
doAssert test.path == "/foo/bar/asd"
|
||||||
|
|
||||||
|
# removeDotSegments tests
|
||||||
|
block:
|
||||||
|
# empty test
|
||||||
|
doAssert removeDotSegments("") == ""
|
||||||
|
|
||||||
|
# bug #3207
|
||||||
|
block:
|
||||||
|
doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq"
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ proc getCommand*(): string =
|
||||||
## "c", "js", "build", "help".
|
## "c", "js", "build", "help".
|
||||||
builtin
|
builtin
|
||||||
|
|
||||||
proc setCommand*(cmd: string) =
|
proc setCommand*(cmd: string; project="") =
|
||||||
## Sets the Nim command that should be continued with after this Nimscript
|
## Sets the Nim command that should be continued with after this Nimscript
|
||||||
## has finished.
|
## has finished.
|
||||||
builtin
|
builtin
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,13 @@ const
|
||||||
|
|
||||||
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
|
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",
|
proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||||
importc: "CloseHandle".}
|
importc: "CloseHandle".}
|
||||||
|
|
||||||
|
|
@ -125,6 +132,19 @@ proc createPipe*(hReadPipe, hWritePipe: var Handle,
|
||||||
nSize: int32): WINBOOL{.
|
nSize: int32): WINBOOL{.
|
||||||
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
|
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:
|
when useWinUnicode:
|
||||||
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
|
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
|
||||||
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
|
lpProcessAttributes: ptr SECURITY_ATTRIBUTES,
|
||||||
|
|
@ -615,12 +635,24 @@ const
|
||||||
|
|
||||||
FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
|
FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
|
||||||
FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'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
|
# Error Constants
|
||||||
const
|
const
|
||||||
ERROR_ACCESS_DENIED* = 5
|
ERROR_ACCESS_DENIED* = 5
|
||||||
ERROR_HANDLE_EOF* = 38
|
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:
|
when useWinUnicode:
|
||||||
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
|
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
|
||||||
lpSecurityAttributes: pointer,
|
lpSecurityAttributes: pointer,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue