diff options
author | dom96 <dominikpicheta@googlemail.com> | 2011-05-07 23:17:10 +0100 |
---|---|---|
committer | dom96 <dominikpicheta@googlemail.com> | 2011-05-07 23:17:10 +0100 |
commit | 0db6f3c00f7975d49b5d4d1c061d6f29162176af (patch) | |
tree | 70136af40049a5a83e7e6ddee7a3fe2a38d4a661 | |
parent | 73c355176653e5b643f2bbbdc4f967cc24b3ee3b (diff) | |
download | Nim-0db6f3c00f7975d49b5d4d1c061d6f29162176af.tar.gz |
select() for processes; copyDir() for os.
-rwxr-xr-x | lib/pure/os.nim | 46 | ||||
-rwxr-xr-x | lib/pure/osproc.nim | 82 | ||||
-rwxr-xr-x | lib/windows/windows.nim | 7 | ||||
-rwxr-xr-x | lib/windows/winlean.nim | 14 |
4 files changed, 129 insertions, 20 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e044fe605..81a038de7 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -147,6 +147,24 @@ const ## The character which separates the base filename from the extension; ## 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".} = ## raises an EOS exception with the given message ``msg``. ## 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``. ## If no error flag is set, the message ``unknown OS error`` is used. if len(msg) == 0: - when defined(Windows): - var err = GetLastError() - if err != 0'i32: - # 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)) + var m = OSErrorMsg() + if m != "": + raise newException(EOS, m) else: raise newException(EOS, "unknown OS error") 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)) 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] {. noSideEffect, rtl, extern: "nos$1".} = ## Splits a command line into several components; diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index e13f508b6..a539e5f39 100755 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2010 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -43,7 +43,7 @@ proc execProcess*(command: string, options: set[TProcessOption] = {poStdErrToStdOut, poUseShell}): string {. 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. 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".} ## 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".} ## returns ``p``'s input stream for writing to @@ -196,6 +199,12 @@ proc execProcesses*(cmds: openArray[string], var p = startProcessAux(cmds[i], options=options) 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): proc execProcess(command: string, options: set[TProcessOption] = {poStdErrToStdOut, @@ -366,6 +375,14 @@ when defined(Windows) and not defined(useNimRtl): result = res 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 = result = newFileHandleStream(p.inputHandle) @@ -398,6 +415,24 @@ when defined(Windows) and not defined(useNimRtl): result = -1 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): const readIdx = 0 @@ -435,7 +470,7 @@ elif not defined(useNimRtl): var p_stdin, p_stdout, p_stderr: array [0..1, cint] new(result) - result.exitCode = 3 # for ``waitForExit`` + result.exitCode = -3 # for ``waitForExit`` if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32: OSError("failed to create a pipe") var Pid = fork() @@ -504,13 +539,19 @@ elif not defined(useNimRtl): #if waitPid(p.id, p.exitCode, 0) == int(p.id): # ``waitPid`` fails if the process is not running anymore. But then # ``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 if waitPid(p.id, p.exitCode, 0) < 0: # failed, so restore old exitCode p.exitCode = oldExitCode 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 = var f: TFile if not open(f, p.inputHandle, fmWrite): OSError() @@ -531,6 +572,39 @@ elif not defined(useNimRtl): proc execCmd(command: string): int = 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: var x = execProcess("gcc -v") echo "ECHO ", x diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index 579775c2d..c8c977d9b 100755 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -360,6 +360,7 @@ type RASP_PppIp = 0x00008021, RASP_PppIpx = 0x0000802B, RASP_PppNbf = 0x0000803F, RASP_Amb = 0x00010000 SECURITY_IMPERSONATION_LEVEL* = enum + SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation SID_NAME_USE* = enum @@ -3761,6 +3762,7 @@ const SMTO_NORMAL* = 0 # SetBkMode OPAQUE* = 2 + TRANSPARENT* = 1 # SetDebugErrorLevel SLE_ERROR* = 1 @@ -16215,6 +16217,7 @@ when defined(winUnicode): proc GetEnvironmentStrings*(): LPWSTR{.stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".} proc FreeEnvironmentStrings*(para1: LPWSTR): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "FreeEnvironmentStringsW".} proc FormatMessage*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD, dwLanguageId: DWORD, lpBuffer: LPWSTR, nSize: DWORD, @@ -18715,9 +18718,7 @@ proc ReleaseMutex*(hMutex: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReleaseMutex".} proc WaitForSingleObject*(hHandle: HANDLE, dwMilliseconds: DWORD): DWORD{. 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", importc: "Sleep".} proc LoadResource*(hModule: HINST, hResInfo: HRSRC): HGLOBAL{.stdcall, diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index e8c93d8b1..75f2fc4df 100755 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -13,6 +13,7 @@ type THandle* = int WINBOOL* = int32 + DWORD* = int32 TSECURITY_ATTRIBUTES* {.final, pure.} = object nLength*: int32 @@ -52,7 +53,9 @@ const IDLE_PRIORITY_CLASS* = 64'i32 NORMAL_PRIORITY_CLASS* = 32'i32 REALTIME_PRIORITY_CLASS* = 256'i32 + WAIT_OBJECT_0* = 0'i32 WAIT_TIMEOUT* = 0x00000102'i32 + WAIT_FAILED* = 0xFFFFFFFF'i32 INFINITE* = -1'i32 STD_INPUT_HANDLE* = -10'i32 @@ -383,3 +386,14 @@ proc freeaddrinfo*(ai: ptr TAddrInfo) {. proc inet_ntoa*(i: TInAddr): cstring {. 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".} |