Merge remote-tracking branch 'nim-lang/devel' into emscripten-support

This commit is contained in:
Andrey Sobolev
2015-09-30 14:23:25 +06:00
13 changed files with 338 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)
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()

View File

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

View File

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

View File

@@ -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
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].}
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):

View File

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

View File

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

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

View File

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

View File

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

View File

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