select() for processes; copyDir() for os.
This commit is contained in:
parent
73c3551766
commit
0db6f3c00f
4 changed files with 129 additions and 20 deletions
|
|
@ -147,6 +147,24 @@ const
|
||||||
## The character which separates the base filename from the extension;
|
## The character which separates the base filename from the extension;
|
||||||
## for example, the '.' in ``os.nim``.
|
## for example, the '.' in ``os.nim``.
|
||||||
|
|
||||||
|
proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
||||||
|
## Retrieves the operating system's error flag, ``errno`` on Posix and
|
||||||
|
## ``GetLastError`` on Windows.
|
||||||
|
result = ""
|
||||||
|
when defined(Windows):
|
||||||
|
var err = GetLastError()
|
||||||
|
if err != 0'i32:
|
||||||
|
var msgbuf: cstring
|
||||||
|
if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
|
||||||
|
nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
|
||||||
|
var m = $msgbuf
|
||||||
|
if msgbuf != nil:
|
||||||
|
LocalFree(msgbuf)
|
||||||
|
result = m
|
||||||
|
else:
|
||||||
|
if errno != 0'i32:
|
||||||
|
result = $os.strerror(errno)
|
||||||
|
|
||||||
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
|
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
|
||||||
## raises an EOS exception with the given message ``msg``.
|
## raises an EOS exception with the given message ``msg``.
|
||||||
## If ``msg == ""``, the operating system's error flag
|
## If ``msg == ""``, the operating system's error flag
|
||||||
|
|
@ -154,19 +172,9 @@ proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
|
||||||
## ``GetLastError`` is checked before ``errno``.
|
## ``GetLastError`` is checked before ``errno``.
|
||||||
## If no error flag is set, the message ``unknown OS error`` is used.
|
## If no error flag is set, the message ``unknown OS error`` is used.
|
||||||
if len(msg) == 0:
|
if len(msg) == 0:
|
||||||
when defined(Windows):
|
var m = OSErrorMsg()
|
||||||
var err = GetLastError()
|
if m != "":
|
||||||
if err != 0'i32:
|
raise newException(EOS, m)
|
||||||
# sigh, why is this is so difficult?
|
|
||||||
var msgbuf: cstring
|
|
||||||
if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
|
|
||||||
nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
|
|
||||||
var m = $msgbuf
|
|
||||||
if msgbuf != nil:
|
|
||||||
LocalFree(msgbuf)
|
|
||||||
raise newException(EOS, m)
|
|
||||||
if errno != 0'i32:
|
|
||||||
raise newException(EOS, $os.strerror(errno))
|
|
||||||
else:
|
else:
|
||||||
raise newException(EOS, "unknown OS error")
|
raise newException(EOS, "unknown OS error")
|
||||||
else:
|
else:
|
||||||
|
|
@ -942,6 +950,18 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1".} =
|
||||||
if dir[i] in {dirsep, altsep}: rawCreateDir(copy(dir, 0, i-1))
|
if dir[i] in {dirsep, altsep}: rawCreateDir(copy(dir, 0, i-1))
|
||||||
rawCreateDir(dir)
|
rawCreateDir(dir)
|
||||||
|
|
||||||
|
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1".} =
|
||||||
|
## Copies a directory from `source` to `dest`. If this fails, `EOS` is raised.
|
||||||
|
createDir(dest)
|
||||||
|
for kind, path in walkDir(source):
|
||||||
|
var noSource = path.copy(source.len()+1)
|
||||||
|
case kind
|
||||||
|
of pcFile:
|
||||||
|
copyFile(path, dest / noSource)
|
||||||
|
of pcDir:
|
||||||
|
copyDir(path, dest / noSource)
|
||||||
|
else: nil
|
||||||
|
|
||||||
proc parseCmdLine*(c: string): seq[string] {.
|
proc parseCmdLine*(c: string): seq[string] {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
noSideEffect, rtl, extern: "nos$1".} =
|
||||||
## Splits a command line into several components;
|
## Splits a command line into several components;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -43,7 +43,7 @@ proc execProcess*(command: string,
|
||||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||||
poUseShell}): string {.
|
poUseShell}): string {.
|
||||||
rtl, extern: "nosp$1".}
|
rtl, extern: "nosp$1".}
|
||||||
## A convience procedure that executes ``command`` with ``startProcess``
|
## A convenience procedure that executes ``command`` with ``startProcess``
|
||||||
## and returns its output as a string.
|
## and returns its output as a string.
|
||||||
|
|
||||||
proc executeProcess*(command: string,
|
proc executeProcess*(command: string,
|
||||||
|
|
@ -101,6 +101,9 @@ proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
|
||||||
proc waitForExit*(p: PProcess): int {.rtl, extern: "nosp$1".}
|
proc waitForExit*(p: PProcess): int {.rtl, extern: "nosp$1".}
|
||||||
## waits for the process to finish and returns `p`'s error code.
|
## waits for the process to finish and returns `p`'s error code.
|
||||||
|
|
||||||
|
proc peekExitCode*(p: PProcess): int
|
||||||
|
## return -1 if the process is still running. Otherwise the process' exit code
|
||||||
|
|
||||||
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
|
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1".}
|
||||||
## returns ``p``'s input stream for writing to
|
## returns ``p``'s input stream for writing to
|
||||||
|
|
||||||
|
|
@ -196,6 +199,12 @@ proc execProcesses*(cmds: openArray[string],
|
||||||
var p = startProcessAux(cmds[i], options=options)
|
var p = startProcessAux(cmds[i], options=options)
|
||||||
result = max(waitForExit(p), result)
|
result = max(waitForExit(p), result)
|
||||||
|
|
||||||
|
proc select*(readfds: var seq[PProcess], timeout = 500): int
|
||||||
|
## select with a sensible Nimrod interface. `timeout` is in miliseconds.
|
||||||
|
## Specify -1 for no timeout. Returns the number of file handles that are
|
||||||
|
## ready. The processes that are ready to be read from are removed from
|
||||||
|
## `readfds`.
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc execProcess(command: string,
|
proc execProcess(command: string,
|
||||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||||
|
|
@ -366,6 +375,14 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
result = res
|
result = res
|
||||||
discard CloseHandle(p.FProcessHandle)
|
discard CloseHandle(p.FProcessHandle)
|
||||||
|
|
||||||
|
proc peekExitCode(p: PProcess): int =
|
||||||
|
var b = waitForSingleObject(p.FProcessHandle, 50) == WAIT_TIMEOUT
|
||||||
|
if b: result = -1
|
||||||
|
else:
|
||||||
|
var res: int32
|
||||||
|
discard GetExitCodeProcess(p.FProcessHandle, res)
|
||||||
|
return res
|
||||||
|
|
||||||
proc inputStream(p: PProcess): PStream =
|
proc inputStream(p: PProcess): PStream =
|
||||||
result = newFileHandleStream(p.inputHandle)
|
result = newFileHandleStream(p.inputHandle)
|
||||||
|
|
||||||
|
|
@ -398,6 +415,24 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
result = -1
|
result = -1
|
||||||
discard CloseHandle(Process)
|
discard CloseHandle(Process)
|
||||||
|
|
||||||
|
proc select(readfds: var seq[PProcess], timeout = 500): int =
|
||||||
|
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
|
||||||
|
var rfds: TWOHandleArray
|
||||||
|
for i in 0..readfds.len()-1:
|
||||||
|
rfds[i] = readfds[i].FProcessHandle
|
||||||
|
|
||||||
|
var ret = waitForMultipleObjects(readfds.len,
|
||||||
|
addr(rfds), 0'i32, timeout)
|
||||||
|
case ret
|
||||||
|
of WAIT_TIMEOUT:
|
||||||
|
return 0
|
||||||
|
of WAIT_FAILED:
|
||||||
|
OSError()
|
||||||
|
else:
|
||||||
|
var i = ret - WAIT_OBJECT_0
|
||||||
|
readfds.del(i)
|
||||||
|
return 1
|
||||||
|
|
||||||
elif not defined(useNimRtl):
|
elif not defined(useNimRtl):
|
||||||
const
|
const
|
||||||
readIdx = 0
|
readIdx = 0
|
||||||
|
|
@ -435,7 +470,7 @@ elif not defined(useNimRtl):
|
||||||
var
|
var
|
||||||
p_stdin, p_stdout, p_stderr: array [0..1, cint]
|
p_stdin, p_stdout, p_stderr: array [0..1, cint]
|
||||||
new(result)
|
new(result)
|
||||||
result.exitCode = 3 # for ``waitForExit``
|
result.exitCode = -3 # for ``waitForExit``
|
||||||
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32:
|
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32:
|
||||||
OSError("failed to create a pipe")
|
OSError("failed to create a pipe")
|
||||||
var Pid = fork()
|
var Pid = fork()
|
||||||
|
|
@ -504,13 +539,19 @@ elif not defined(useNimRtl):
|
||||||
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
|
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
|
||||||
# ``waitPid`` fails if the process is not running anymore. But then
|
# ``waitPid`` fails if the process is not running anymore. But then
|
||||||
# ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is
|
# ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is
|
||||||
# initialized with 3, wrong success exit codes are prevented.
|
# initialized with -3, wrong success exit codes are prevented.
|
||||||
var oldExitCode = p.exitCode
|
var oldExitCode = p.exitCode
|
||||||
if waitPid(p.id, p.exitCode, 0) < 0:
|
if waitPid(p.id, p.exitCode, 0) < 0:
|
||||||
# failed, so restore old exitCode
|
# failed, so restore old exitCode
|
||||||
p.exitCode = oldExitCode
|
p.exitCode = oldExitCode
|
||||||
result = int(p.exitCode)
|
result = int(p.exitCode)
|
||||||
|
|
||||||
|
proc peekExitCode(p: PProcess): int =
|
||||||
|
var b = waitPid(p.id, p.exitCode, WNOHANG) == int(p.id)
|
||||||
|
if b: result = -1
|
||||||
|
elif p.exitCode == -3: result = -1
|
||||||
|
else: result = p.exitCode
|
||||||
|
|
||||||
proc inputStream(p: PProcess): PStream =
|
proc inputStream(p: PProcess): PStream =
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if not open(f, p.inputHandle, fmWrite): OSError()
|
if not open(f, p.inputHandle, fmWrite): OSError()
|
||||||
|
|
@ -531,6 +572,39 @@ elif not defined(useNimRtl):
|
||||||
proc execCmd(command: string): int =
|
proc execCmd(command: string): int =
|
||||||
result = csystem(command)
|
result = csystem(command)
|
||||||
|
|
||||||
|
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
|
||||||
|
FD_ZERO(fd)
|
||||||
|
for i in items(s):
|
||||||
|
m = max(m, int(i.outputHandle))
|
||||||
|
FD_SET(cint(i.outputHandle), fd)
|
||||||
|
|
||||||
|
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
|
||||||
|
var i = 0
|
||||||
|
var L = s.len
|
||||||
|
while i < L:
|
||||||
|
if FD_ISSET(cint(s[i].outputHandle), fd) != 0'i32:
|
||||||
|
s[i] = s[L-1]
|
||||||
|
dec(L)
|
||||||
|
else:
|
||||||
|
inc(i)
|
||||||
|
setLen(s, L)
|
||||||
|
|
||||||
|
proc select(readfds: var seq[PProcess], timeout = 500): int =
|
||||||
|
var tv: TTimeVal
|
||||||
|
tv.tv_sec = 0
|
||||||
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
||||||
|
var rd: TFdSet
|
||||||
|
var m = 0
|
||||||
|
createFdSet((rd), readfds, m)
|
||||||
|
|
||||||
|
if timeout != -1:
|
||||||
|
result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
|
||||||
|
else:
|
||||||
|
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
|
||||||
|
|
||||||
|
pruneProcessSet(readfds, (rd))
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
var x = execProcess("gcc -v")
|
var x = execProcess("gcc -v")
|
||||||
echo "ECHO ", x
|
echo "ECHO ", x
|
||||||
|
|
|
||||||
|
|
@ -360,6 +360,7 @@ type
|
||||||
RASP_PppIp = 0x00008021, RASP_PppIpx = 0x0000802B, RASP_PppNbf = 0x0000803F,
|
RASP_PppIp = 0x00008021, RASP_PppIpx = 0x0000802B, RASP_PppNbf = 0x0000803F,
|
||||||
RASP_Amb = 0x00010000
|
RASP_Amb = 0x00010000
|
||||||
SECURITY_IMPERSONATION_LEVEL* = enum
|
SECURITY_IMPERSONATION_LEVEL* = enum
|
||||||
|
|
||||||
SecurityAnonymous, SecurityIdentification, SecurityImpersonation,
|
SecurityAnonymous, SecurityIdentification, SecurityImpersonation,
|
||||||
SecurityDelegation
|
SecurityDelegation
|
||||||
SID_NAME_USE* = enum
|
SID_NAME_USE* = enum
|
||||||
|
|
@ -3761,6 +3762,7 @@ const
|
||||||
SMTO_NORMAL* = 0
|
SMTO_NORMAL* = 0
|
||||||
# SetBkMode
|
# SetBkMode
|
||||||
OPAQUE* = 2
|
OPAQUE* = 2
|
||||||
|
|
||||||
TRANSPARENT* = 1
|
TRANSPARENT* = 1
|
||||||
# SetDebugErrorLevel
|
# SetDebugErrorLevel
|
||||||
SLE_ERROR* = 1
|
SLE_ERROR* = 1
|
||||||
|
|
@ -16215,6 +16217,7 @@ when defined(winUnicode):
|
||||||
proc GetEnvironmentStrings*(): LPWSTR{.stdcall, dynlib: "kernel32",
|
proc GetEnvironmentStrings*(): LPWSTR{.stdcall, dynlib: "kernel32",
|
||||||
importc: "GetEnvironmentStringsW".}
|
importc: "GetEnvironmentStringsW".}
|
||||||
proc FreeEnvironmentStrings*(para1: LPWSTR): WINBOOL{.stdcall,
|
proc FreeEnvironmentStrings*(para1: LPWSTR): WINBOOL{.stdcall,
|
||||||
|
|
||||||
dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}
|
dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}
|
||||||
proc FormatMessage*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,
|
proc FormatMessage*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,
|
||||||
dwLanguageId: DWORD, lpBuffer: LPWSTR, nSize: DWORD,
|
dwLanguageId: DWORD, lpBuffer: LPWSTR, nSize: DWORD,
|
||||||
|
|
@ -18715,9 +18718,7 @@ proc ReleaseMutex*(hMutex: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",
|
||||||
importc: "ReleaseMutex".}
|
importc: "ReleaseMutex".}
|
||||||
proc WaitForSingleObject*(hHandle: HANDLE, dwMilliseconds: DWORD): DWORD{.
|
proc WaitForSingleObject*(hHandle: HANDLE, dwMilliseconds: DWORD): DWORD{.
|
||||||
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
|
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
|
||||||
proc WaitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
|
|
||||||
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
|
|
||||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
|
||||||
proc Sleep*(dwMilliseconds: DWORD){.stdcall, dynlib: "kernel32",
|
proc Sleep*(dwMilliseconds: DWORD){.stdcall, dynlib: "kernel32",
|
||||||
importc: "Sleep".}
|
importc: "Sleep".}
|
||||||
proc LoadResource*(hModule: HINST, hResInfo: HRSRC): HGLOBAL{.stdcall,
|
proc LoadResource*(hModule: HINST, hResInfo: HRSRC): HGLOBAL{.stdcall,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
type
|
type
|
||||||
THandle* = int
|
THandle* = int
|
||||||
WINBOOL* = int32
|
WINBOOL* = int32
|
||||||
|
DWORD* = int32
|
||||||
|
|
||||||
TSECURITY_ATTRIBUTES* {.final, pure.} = object
|
TSECURITY_ATTRIBUTES* {.final, pure.} = object
|
||||||
nLength*: int32
|
nLength*: int32
|
||||||
|
|
@ -52,7 +53,9 @@ const
|
||||||
IDLE_PRIORITY_CLASS* = 64'i32
|
IDLE_PRIORITY_CLASS* = 64'i32
|
||||||
NORMAL_PRIORITY_CLASS* = 32'i32
|
NORMAL_PRIORITY_CLASS* = 32'i32
|
||||||
REALTIME_PRIORITY_CLASS* = 256'i32
|
REALTIME_PRIORITY_CLASS* = 256'i32
|
||||||
|
WAIT_OBJECT_0* = 0'i32
|
||||||
WAIT_TIMEOUT* = 0x00000102'i32
|
WAIT_TIMEOUT* = 0x00000102'i32
|
||||||
|
WAIT_FAILED* = 0xFFFFFFFF'i32
|
||||||
INFINITE* = -1'i32
|
INFINITE* = -1'i32
|
||||||
|
|
||||||
STD_INPUT_HANDLE* = -10'i32
|
STD_INPUT_HANDLE* = -10'i32
|
||||||
|
|
@ -383,3 +386,14 @@ proc freeaddrinfo*(ai: ptr TAddrInfo) {.
|
||||||
|
|
||||||
proc inet_ntoa*(i: TInAddr): cstring {.
|
proc inet_ntoa*(i: TInAddr): cstring {.
|
||||||
stdcall, importc, dynlib: ws2dll.}
|
stdcall, importc, dynlib: ws2dll.}
|
||||||
|
|
||||||
|
const
|
||||||
|
MAXIMUM_WAIT_OBJECTS* = 0x00000040
|
||||||
|
|
||||||
|
type
|
||||||
|
TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THANDLE]
|
||||||
|
PWOHandleArray* = ptr TWOHandleArray
|
||||||
|
|
||||||
|
proc WaitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
|
||||||
|
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
|
||||||
|
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue