diff options
Diffstat (limited to 'lib/osproc.nim')
-rw-r--r-- | lib/osproc.nim | 92 |
1 files changed, 62 insertions, 30 deletions
diff --git a/lib/osproc.nim b/lib/osproc.nim index 2282e802d..205460614 100644 --- a/lib/osproc.nim +++ b/lib/osproc.nim @@ -1,20 +1,21 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2008 Andreas Rumpf +# (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module implements an advanced facility for executing OS processes. -## On Windows this module is currently broken. Please help! +## This module implements an advanced facility for executing OS processes +## and process communication. +## **On Windows this module does not work properly. Please help!** import os, strtabs, streams when defined(windows): - import windows + import winlean type TProcess = object of TObject @@ -41,6 +42,10 @@ proc executeProcess*(command: string, ## A convience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. +proc executeCommand*(command: string): int + ## Executes ``command`` and returns its error code. Standard input, output, + ## error streams are inherited from the calling process. + proc startProcess*(command: string, workingDir: string = "", args: openarray[string] = [], @@ -133,14 +138,14 @@ when defined(Windows): proc hsReadData(s: PFileHandleStream, buffer: pointer, bufLen: int): int = var br: int32 - var a = windows.ReadFile(s.handle, buffer, bufLen, br, nil) + var a = winlean.ReadFile(s.handle, buffer, bufLen, br, nil) if a == 0: OSError() result = br #atEnd = bytesRead < bufLen proc hsWriteData(s: PFileHandleStream, buffer: pointer, bufLen: int) = var bytesWritten: int32 - var a = windows.writeFile(s.handle, buffer, bufLen, bytesWritten, nil) + var a = winlean.writeFile(s.handle, buffer, bufLen, bytesWritten, nil) if a == 0: OSError() proc newFileHandleStream(handle: THandle): PFileHandleStream = @@ -180,12 +185,12 @@ when defined(Windows): # O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int # O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int - proc CreatePipeHandles(Inhandle, OutHandle: ptr THandle) = + proc CreatePipeHandles(Inhandle, OutHandle: var THandle) = var piInheritablePipe: TSecurityAttributes piInheritablePipe.nlength = SizeOF(TSecurityAttributes) - piInheritablePipe.lpSecurityDescriptor = Nil + piInheritablePipe.lpSecurityDescriptor = nil piInheritablePipe.Binherithandle = 1 - if CreatePipe(Inhandle, Outhandle, addr(piInheritablePipe), 0) == 0'i32: + if CreatePipe(Inhandle, Outhandle, piInheritablePipe, 0) == 0'i32: OSError() proc startProcess*(command: string, @@ -201,15 +206,15 @@ when defined(Windows): hi, ho, he: THandle SI.cb = SizeOf(SI) SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES - CreatePipeHandles(addr(SI.hStdInput), addr(HI)) - CreatePipeHandles(addr(HO), addr(Si.hStdOutput)) + CreatePipeHandles(SI.hStdInput, HI) + CreatePipeHandles(HO, Si.hStdOutput) #SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE()) #SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE()) if poStdErrToStdOut in options: SI.hStdError = SI.hStdOutput HE = HO else: - CreatePipeHandles(addr(HE), addr(Si.hStdError)) + CreatePipeHandles(HE, Si.hStdError) #SI.hStdError = GetStdHandle(STD_ERROR_HANDLE()) #result.inputHandle = open_osfhandle(HI, O_WRONLY) #if result.inputHandle == -1'i32: OSError() @@ -224,16 +229,12 @@ when defined(Windows): var wd: cstring = nil if len(workingDir) > 0: wd = workingDir if env == nil: - success = Windows.CreateProcess(nil, - cmdl, nil, nil, 0, - NORMAL_PRIORITY_CLASS, nil, wd, - addr(SI), addr(ProcInfo)) + success = winlean.CreateProcess(nil, + cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, nil, wd, SI, ProcInfo) else: var e = buildEnv(env) - success = Windows.CreateProcess(nil, - cmdl, nil, nil, 0, - NORMAL_PRIORITY_CLASS, e, wd, - addr(SI), addr(ProcInfo)) + success = winlean.CreateProcess(nil, + cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo) dealloc(e) dealloc(cmdl) if success == 0: @@ -249,7 +250,7 @@ when defined(Windows): discard ResumeThread(p.FThreadHandle) proc running(p: PProcess): bool = - var x = waitForSingleObject(p.FThreadHandle, 50) + var x = waitForSingleObject(p.FProcessHandle, 50) return x == WAIT_TIMEOUT proc terminate(p: PProcess) = @@ -257,11 +258,11 @@ when defined(Windows): discard TerminateProcess(p.FProcessHandle, 0) proc waitForExit(p: PProcess): int = - discard WaitForSingleObject(p.FThreadHandle, Infinite) - var res: dword + discard CloseHandle(p.FThreadHandle) + discard WaitForSingleObject(p.FProcessHandle, Infinite) + var res: int32 discard GetExitCodeProcess(p.FProcessHandle, res) result = res - discard CloseHandle(p.FThreadHandle) discard CloseHandle(p.FProcessHandle) proc inputStream(p: PProcess): PStream = @@ -273,6 +274,29 @@ when defined(Windows): proc errorStream(p: PProcess): PStream = result = newFileHandleStream(p.errorHandle) + proc executeCommand(command: string): int = + var + SI: TStartupInfo + ProcInfo: TProcessInformation + process: THandle + L: int32 + SI.cb = SizeOf(SI) + SI.hStdError = GetStdHandle(STD_ERROR_HANDLE) + SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE) + SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE) + if winlean.CreateProcess(nil, command, nil, nil, 0, + NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo) == 0: + OSError() + else: + Process = ProcInfo.hProcess + discard CloseHandle(ProcInfo.hThread) + if WaitForSingleObject(Process, INFINITE) != -1: + discard GetExitCodeProcess(Process, L) + result = int(L) + else: + result = -1 + discard CloseHandle(Process) + else: import posix @@ -321,15 +345,15 @@ else: if pid == 0: ## child process: discard close(p_stdin[writeIdx]) - discard dup2(p_stdin[readIdx], readIdx) + if dup2(p_stdin[readIdx], readIdx) < 0: OSError() discard close(p_stdout[readIdx]) - discard dup2(p_stdout[writeIdx], writeIdx) + if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError() if poStdErrToStdOut in options: - discard dup2(p_stdout[writeIdx], 2) + if dup2(p_stdout[writeIdx], 2) < 0: OSError() else: if pipe(p_stderr) != 0'i32: OSError("failed to create a pipe") discard close(p_stderr[readIdx]) - discard dup2(p_stderr[writeIdx], 2) + if dup2(p_stderr[writeIdx], 2) < 0: OSError() if workingDir.len > 0: os.setCurrentDir(workingDir) @@ -347,8 +371,7 @@ else: else: discard execve("/bin/sh", a, ToCStringArray(env)) # too risky to raise an exception here: - echo("execve call failed: " & $strerror(errno)) - quit(1) + quit("execve call failed: " & $strerror(errno)) # Parent process. Copy process information. result.id = pid @@ -376,6 +399,7 @@ else: if running(p): discard kill(p.id, SIGKILL) proc waitForExit(p: PProcess): int = + result = 1 if waitPid(p.id, p.exitCode, 0) == int(p.id): result = p.exitCode @@ -393,3 +417,11 @@ else: var f: TFile if not openFile(f, p.errorHandle, fmRead): OSError() result = newFileStream(f) + + proc csystem(cmd: cstring): cint {.nodecl, importc: "system".} + + proc executeCommand(command: string): int = + result = csystem(command) + +when isMainModule: + echo executeCommand("gcc -v") |