diff options
| author | Marijn Haverbeke <[email protected]> | 2011-03-11 13:30:18 +0100 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2011-03-14 14:57:13 -0700 |
| commit | ea5dc54c3f0444fd3f20191fa1b1d94372c74c65 (patch) | |
| tree | 0a80b98563553f56962cc956e94210462a9d66e2 /src/lib | |
| parent | Extend stream functionality (diff) | |
| download | rust-ea5dc54c3f0444fd3f20191fa1b1d94372c74c65.tar.xz rust-ea5dc54c3f0444fd3f20191fa1b1d94372c74c65.zip | |
Add functionality for running external programs to the std lib
See lib/run_program.rs.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/io.rs | 19 | ||||
| -rw-r--r-- | src/lib/linux_os.rs | 23 | ||||
| -rw-r--r-- | src/lib/macos_os.rs | 20 | ||||
| -rw-r--r-- | src/lib/run_program.rs | 96 | ||||
| -rw-r--r-- | src/lib/std.rc | 4 | ||||
| -rw-r--r-- | src/lib/win32_os.rs | 22 |
6 files changed, 182 insertions, 2 deletions
diff --git a/src/lib/io.rs b/src/lib/io.rs index 45bdb4a0..7135c2bc 100644 --- a/src/lib/io.rs +++ b/src/lib/io.rs @@ -17,6 +17,8 @@ type reader = impure fn read_bytes(uint len) -> vec[u8]; impure fn read_char() -> int; impure fn unread_char(int i); + impure fn eof() -> bool; + impure fn read_line() -> str; impure fn read_c_str() -> str; impure fn read_le_uint(uint size) -> uint; impure fn read_le_int(uint size) -> int; @@ -31,7 +33,7 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) { impure fn read_bytes(uint len) -> vec[u8] { auto buf = _vec.alloc[u8](len); auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f); - check(read == len); + _vec.len_set[u8](buf, read); ret buf; } impure fn read_char() -> int { @@ -40,6 +42,21 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) { impure fn unread_char(int ch) { os.libc.ungetc(ch, f); } + impure fn eof() -> bool { + auto ch = os.libc.fgetc(f); + if (ch == -1) {ret true;} + os.libc.ungetc(ch, f); + ret false; + } + impure fn read_line() -> str { + auto buf = ""; + while (true) { + auto ch = os.libc.fgetc(f); + if (ch == -1) {break;} if (ch == 10) {break;} + buf += _str.unsafe_from_bytes(vec(ch as u8)); + } + ret buf; + } impure fn read_c_str() -> str { auto buf = ""; while (true) { diff --git a/src/lib/linux_os.rs b/src/lib/linux_os.rs index bed8fdbc..6695377d 100644 --- a/src/lib/linux_os.rs +++ b/src/lib/linux_os.rs @@ -1,6 +1,9 @@ import _str.sbuf; import _vec.vbuf; +// FIXE Somehow merge stuff duplicated here and macosx_os.rs. Made difficult +// by https://github.com/graydon/rust/issues#issue/268 + native mod libc = "libc.so.6" { fn open(sbuf s, int flags, uint mode) -> int; @@ -10,6 +13,7 @@ native mod libc = "libc.so.6" { type FILE; fn fopen(sbuf path, sbuf mode) -> FILE; + fn fdopen(int fd, sbuf mode) -> FILE; fn fclose(FILE f); fn fgetc(FILE f) -> int; fn ungetc(int c, FILE f); @@ -25,6 +29,9 @@ native mod libc = "libc.so.6" { fn getenv(sbuf n) -> sbuf; fn setenv(sbuf n, sbuf v, int overwrite) -> int; fn unsetenv(sbuf n) -> int; + + fn pipe(vbuf buf) -> int; + fn waitpid(int pid, vbuf status, int options) -> int; } mod libc_constants { @@ -50,6 +57,22 @@ fn target_os() -> str { ret "linux"; } +fn pipe() -> tup(int, int) { + let vec[mutable int] fds = vec(mutable 0, 0); + check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0); + ret tup(fds.(0), fds.(1)); +} + +fn fd_FILE(int fd) -> libc.FILE { + ret libc.fdopen(fd, _str.buf("r")); +} + +fn waitpid(int pid) -> int { + let vec[mutable int] status = vec(mutable 0); + check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1); + ret status.(0); +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/lib/macos_os.rs b/src/lib/macos_os.rs index bacf2d8a..a484f72b 100644 --- a/src/lib/macos_os.rs +++ b/src/lib/macos_os.rs @@ -9,6 +9,7 @@ native mod libc = "libc.dylib" { type FILE; fn fopen(sbuf path, sbuf mode) -> FILE; + fn fdopen(int fd, sbuf mode) -> FILE; fn fclose(FILE f); fn fgetc(FILE f) -> int; fn ungetc(int c, FILE f); @@ -24,6 +25,9 @@ native mod libc = "libc.dylib" { fn getenv(sbuf n) -> sbuf; fn setenv(sbuf n, sbuf v, int overwrite) -> int; fn unsetenv(sbuf n) -> int; + + fn pipe(vbuf buf) -> int; + fn waitpid(int pid, vbuf status, int options) -> int; } mod libc_constants { @@ -49,6 +53,22 @@ fn target_os() -> str { ret "macos"; } +fn pipe() -> tup(int, int) { + let vec[mutable int] fds = vec(mutable 0, 0); + check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0); + ret tup(fds.(0), fds.(1)); +} + +fn fd_FILE(int fd) -> libc.FILE { + ret libc.fdopen(fd, _str.buf("r")); +} + +fn waitpid(int pid) -> int { + let vec[mutable int] status = vec(mutable 0); + check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1); + ret status.(0); +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/lib/run_program.rs b/src/lib/run_program.rs new file mode 100644 index 00000000..bd9edbc8 --- /dev/null +++ b/src/lib/run_program.rs @@ -0,0 +1,96 @@ +import _str.sbuf; +import _vec.vbuf; + +native "rust" mod rustrt { + fn rust_run_program(vbuf argv, int in_fd, int out_fd, int err_fd) -> int; +} + +fn argvec(str prog, vec[str] args) -> vec[sbuf] { + auto argptrs = vec(_str.buf(prog)); + for (str arg in args) { + argptrs = _vec.push[sbuf](argptrs, _str.buf(arg)); + } + argptrs = _vec.push[sbuf](argptrs, 0 as sbuf); + ret argptrs; +} + +impure fn run_program(str prog, vec[str] args) -> int { + auto pid = rustrt.rust_run_program(_vec.buf[sbuf](argvec(prog, args)), + 0, 0, 0); + ret os.waitpid(pid); +} + +type program = + state obj { + fn get_id() -> int; + fn input() -> io.writer; + fn output() -> io.reader; + impure fn close_input(); + impure fn finish() -> int; + }; + +impure fn start_program(str prog, vec[str] args) -> @program { + auto pipe_input = os.pipe(); + auto pipe_output = os.pipe(); + auto pid = rustrt.rust_run_program + (_vec.buf[sbuf](argvec(prog, args)), + pipe_input._0, pipe_output._1, 0); + if (pid == -1) {fail;} + os.libc.close(pipe_input._0); + os.libc.close(pipe_output._1); + + state obj new_program(int pid, + int in_fd, + os.libc.FILE out_file, + mutable bool finished) { + fn get_id() -> int {ret pid;} + fn input() -> io.writer { + ret io.new_writer(io.fd_buf_writer(in_fd, false)); + } + fn output() -> io.reader { + ret io.FILE_reader(out_file, false); + } + impure fn close_input() { + os.libc.close(in_fd); + } + impure fn finish() -> int { + if (finished) {ret 0;} + finished = true; + os.libc.close(in_fd); + ret os.waitpid(pid); + } + drop { + if (!finished) { + os.libc.close(in_fd); + os.waitpid(pid); + } + os.libc.fclose(out_file); + } + } + ret @new_program(pid, pipe_input._1, + os.fd_FILE(pipe_output._0), + false); +} + +impure fn program_output(str prog, vec[str] args) + -> rec(int status, str out) { + auto pr = start_program(prog, args); + pr.close_input(); + auto out = pr.output(); + auto buf = ""; + while (!out.eof()) { + auto bytes = out.read_bytes(4096u); + buf += _str.unsafe_from_bytes(bytes); + } + ret rec(status=pr.finish(), out=buf); +} + + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/lib/std.rc b/src/lib/std.rc index 8098a4e9..a339fd85 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -27,7 +27,9 @@ mod util; auth io = unsafe; auth fs = unsafe; +auth os = unsafe; auth os_fs = unsafe; +auth run = unsafe; auth _str = unsafe; auth _vec = unsafe; auth _task = unsafe; @@ -52,9 +54,9 @@ alt (target_os) { mod os_fs = "posix_fs.rs"; } } +mod run = "run_program.rs"; mod fs; - // FIXME: parametric mod map; mod deque; diff --git a/src/lib/win32_os.rs b/src/lib/win32_os.rs index 1c037c77..56c65bfc 100644 --- a/src/lib/win32_os.rs +++ b/src/lib/win32_os.rs @@ -9,11 +9,14 @@ native mod libc = "msvcrt.dll" { type FILE; fn fopen(sbuf path, sbuf mode) -> FILE; + fn _fdopen(int fd, sbuf mode) -> FILE; fn fclose(FILE f); fn fgetc(FILE f) -> int; fn ungetc(int c, FILE f); fn fread(vbuf buf, uint size, uint n, FILE f) -> uint; fn fseek(FILE f, int offset, int whence) -> int; + + fn _pipe(vbuf fds, uint size, int mode) -> int; } mod libc_constants { @@ -39,6 +42,25 @@ fn target_os() -> str { ret "win32"; } +fn pipe() -> tup(int, int) { + let vec[mutable int] fds = vec(mutable 0, 0); + check(os.libc._pipe(_vec.buf[mutable int](fds), 1024u, + libc_constants.O_BINARY()) == 0); + ret tup(fds.(0), fds.(1)); +} + +fn fd_FILE(int fd) -> libc.FILE { + ret libc._fdopen(fd, _str.buf("r")); +} + +native "rust" mod rustrt { + fn rust_process_wait(int handle) -> int; +} + +fn waitpid(int pid) -> int { + ret rustrt.rust_process_wait(pid); +} + // Local Variables: // mode: rust; // fill-column: 78; |