module arsd.exec; import std.stdio; import std.string; static import linux = std.c.linux.linux; extern(C) int execve(const(char)*, const(char)**, const(char)**); /** executes an external program, with stdin and stdout of that program optionally going to/from strings args - an array of command line arguments to pass (may be empty or null to pass nothing) input - a string that contains the data pass to standard input of the program (null is no override) output - a pointer to a string that will receive standard output from the program (null is no override) environment - a string of additional environment variables to send (null is none) [NOT YET IMPLEMENTED] returns return value of program ran throws exceptions on error */ int exec(string program, string[] args = null, string input = null, string* output = null, string* error = null, string[] environment = null){ int[2] newStdin; int[2] newStdout; int[2] newStderr; if(input !is null) if(linux.pipe(newStdin) != 0) throw new Exception("pipe stdin"); if(output !is null) if(linux.pipe(newStdout) != 0) throw new Exception("pipe stdout"); if(error !is null) if(linux.pipe(newStderr) != 0) throw new Exception("pipe stderr"); int pid = linux.fork(); if(pid == 0){ // child if(input !is null){ linux.close(newStdin[1]); linux.close(0); linux.dup(newStdin[0]); } if(output !is null){ linux.close(1); linux.dup(newStdout[1]); } if(error !is null){ linux.close(2); linux.dup(newStderr[1]); } const(char)*[] argv; argv.length = 2 + args.length; int a = 1; argv[0] = toStringz(program); if(args !is null) foreach(arg; args){ argv[a] = toStringz(arg); a++; } argv[a] = null; const(char)*[] envp; envp.length = 1 + environment.length; a = 0; if(environment !is null) foreach(arg; environment){ envp[a] = toStringz(arg); a++; } envp[a] = null; if(execve(toStringz(program), argv.ptr, envp.ptr) == -1) throw new Exception("Execute"); } else { // parent if(input !is null) linux.close(newStdin[0]); if(output !is null) linux.close(newStdout[1]); if(error !is null) linux.close(newStderr[1]); int s; if(input !is null){ do{ s = linux.write(newStdin[1], input.ptr, input.length); if(s < input.length) input = input[s..$]; else s = 0; } while (s > 0); linux.close(newStdin[1]); } if(output !is null){ ubyte[1024] buffer; do { s = linux.read(newStdout[0], buffer.ptr, 1024); (*output) ~= buffer[0..s]; } while (s > 0); linux.close(newStdout[0]); } if(error !is null){ ubyte[1024] buffer; do { s = linux.read(newStderr[0], buffer.ptr, 1024); (*error) ~= buffer[0..s]; } while (s > 0); linux.close(newStderr[0]); } int i; linux.wait(&i); return i; } return 0; // never reached }