Merge remote-tracking branch 'origin/devel' into bitsize-pragma

This commit is contained in:
Aman Gupta 2015-09-29 15:38:30 -07:00
commit e5ba94b1f8
14 changed files with 348 additions and 45 deletions

10
.travis.yml Normal file
View 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

View file

@ -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()

View file

@ -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:

View file

@ -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) =

View file

@ -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
View 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.

View file

@ -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

View file

@ -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[

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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,