/* * Copyright © 2005 Bart Massey. * All Rights Reserved. See the file COPYING in this directory * for licensing information. */ /* * Implementation of process manipulation functions. */ namespace Process { import File, Thread; public void system(string cmd, string args ...) /* Fork a separate process. The string cmd is the actual command to be executed, whereas args forms the argument vector. */ { file[3] descs = {stdin, stdout, stderr}; int pid = filter(cmd, args, descs); } public void copy(file readfd, file writefd) /* Generic copy-input-to-output sometimes useful in process manipulation. */ { while (!end(readfd)) putb(getb(readfd), writefd); } public typedef void(file) agent; public void run_process(agent writer, agent reader, string cmd, string args ...) /* Run a separate process, invoking an extra thread so that the process can be concurrently written to and read from. The writer should accept a file descriptor suitable for writing, the reader a file descriptor suitable for reading. The string cmd is the actual command to be executed, whereas args forms the argument vector. Return when both the writer and reader have returned. */ { file[*] inpipe = mkpipe(); file[*] outpipe = mkpipe(); file[3] descs = {inpipe[0], outpipe[1], stderr}; int pid = filter(cmd, args, descs); close(inpipe[0]); close(outpipe[1]); thread t = fork(reader(outpipe[0])); writer(inpipe[1]); close(inpipe[1]); join(t); close(outpipe[0]); } public typedef enum { read, write } popen_direction; public file popen(popen_direction d, bool nullf, string cmd, string args ...) /* Return a file descriptor suitable for reading (when d = read) or writing (when d = write) a separate process. If nullf is true, the unused descriptor will be connected to /dev/null. Otherwise, it will be connected to standard input (when d = read) or standard output (when d = write). The string cmd is the actual command to be executed, whereas args forms the argument vector. */ { switch(nullf) { case true: switch(d) { case popen_direction.read: twixt(file[*] pipe = mkpipe(); close(pipe[1])) { twixt(file nullf = open("/dev/null", "r"); close(nullf)) { file[3] descs = {nullf, pipe[1], stderr}; filter(cmd, args, descs); } return pipe[0]; } case popen_direction.write: twixt(file[*] pipe = mkpipe(); close(pipe[0])) { twixt(file nullf = open("/dev/null", "w"); close(nullf)) { file[3] descs = {pipe[0], nullf, stderr}; filter(cmd, args, descs); } return pipe[1]; } } break; case false: switch(d) { case popen_direction.read: twixt(file[*] pipe = mkpipe(); close(pipe[1])) { file[3] descs = {stdin, pipe[1], stderr}; filter(cmd, args, descs); return pipe[0]; } case popen_direction.write: twixt(file[*] pipe = mkpipe(); close(pipe[0])) { file[3] descs = {pipe[0], stdout, stderr}; filter(cmd, args, descs); return pipe[1]; } } break; } abort("bad popen state"); } }