Skip to content

Commit ea5dc54

Browse files
marijnhgraydon
authored andcommitted
Add functionality for running external programs to the std lib
See lib/run_program.rs.
1 parent 441697a commit ea5dc54

10 files changed

+280
-9
lines changed

src/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
255255
rt/sync/lock_and_signal.cpp \
256256
rt/rust.cpp \
257257
rt/rust_builtin.cpp \
258+
rt/rust_run_program.cpp \
258259
rt/rust_crate.cpp \
259260
rt/rust_crate_cache.cpp \
260261
rt/rust_crate_reader.cpp \

src/lib/io.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ type reader =
1717
impure fn read_bytes(uint len) -> vec[u8];
1818
impure fn read_char() -> int;
1919
impure fn unread_char(int i);
20+
impure fn eof() -> bool;
21+
impure fn read_line() -> str;
2022
impure fn read_c_str() -> str;
2123
impure fn read_le_uint(uint size) -> uint;
2224
impure fn read_le_int(uint size) -> int;
@@ -31,7 +33,7 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
3133
impure fn read_bytes(uint len) -> vec[u8] {
3234
auto buf = _vec.alloc[u8](len);
3335
auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f);
34-
check(read == len);
36+
_vec.len_set[u8](buf, read);
3537
ret buf;
3638
}
3739
impure fn read_char() -> int {
@@ -40,6 +42,21 @@ state obj FILE_reader(os.libc.FILE f, bool must_close) {
4042
impure fn unread_char(int ch) {
4143
os.libc.ungetc(ch, f);
4244
}
45+
impure fn eof() -> bool {
46+
auto ch = os.libc.fgetc(f);
47+
if (ch == -1) {ret true;}
48+
os.libc.ungetc(ch, f);
49+
ret false;
50+
}
51+
impure fn read_line() -> str {
52+
auto buf = "";
53+
while (true) {
54+
auto ch = os.libc.fgetc(f);
55+
if (ch == -1) {break;} if (ch == 10) {break;}
56+
buf += _str.unsafe_from_bytes(vec(ch as u8));
57+
}
58+
ret buf;
59+
}
4360
impure fn read_c_str() -> str {
4461
auto buf = "";
4562
while (true) {

src/lib/linux_os.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import _str.sbuf;
22
import _vec.vbuf;
33

4+
// FIXE Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
5+
// by https://github.com/graydon/rust/issues#issue/268
6+
47
native mod libc = "libc.so.6" {
58

69
fn open(sbuf s, int flags, uint mode) -> int;
@@ -10,6 +13,7 @@ native mod libc = "libc.so.6" {
1013

1114
type FILE;
1215
fn fopen(sbuf path, sbuf mode) -> FILE;
16+
fn fdopen(int fd, sbuf mode) -> FILE;
1317
fn fclose(FILE f);
1418
fn fgetc(FILE f) -> int;
1519
fn ungetc(int c, FILE f);
@@ -25,6 +29,9 @@ native mod libc = "libc.so.6" {
2529
fn getenv(sbuf n) -> sbuf;
2630
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
2731
fn unsetenv(sbuf n) -> int;
32+
33+
fn pipe(vbuf buf) -> int;
34+
fn waitpid(int pid, vbuf status, int options) -> int;
2835
}
2936

3037
mod libc_constants {
@@ -50,6 +57,22 @@ fn target_os() -> str {
5057
ret "linux";
5158
}
5259

60+
fn pipe() -> tup(int, int) {
61+
let vec[mutable int] fds = vec(mutable 0, 0);
62+
check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
63+
ret tup(fds.(0), fds.(1));
64+
}
65+
66+
fn fd_FILE(int fd) -> libc.FILE {
67+
ret libc.fdopen(fd, _str.buf("r"));
68+
}
69+
70+
fn waitpid(int pid) -> int {
71+
let vec[mutable int] status = vec(mutable 0);
72+
check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
73+
ret status.(0);
74+
}
75+
5376
// Local Variables:
5477
// mode: rust;
5578
// fill-column: 78;

src/lib/macos_os.rs

+20
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ native mod libc = "libc.dylib" {
99

1010
type FILE;
1111
fn fopen(sbuf path, sbuf mode) -> FILE;
12+
fn fdopen(int fd, sbuf mode) -> FILE;
1213
fn fclose(FILE f);
1314
fn fgetc(FILE f) -> int;
1415
fn ungetc(int c, FILE f);
@@ -24,6 +25,9 @@ native mod libc = "libc.dylib" {
2425
fn getenv(sbuf n) -> sbuf;
2526
fn setenv(sbuf n, sbuf v, int overwrite) -> int;
2627
fn unsetenv(sbuf n) -> int;
28+
29+
fn pipe(vbuf buf) -> int;
30+
fn waitpid(int pid, vbuf status, int options) -> int;
2731
}
2832

2933
mod libc_constants {
@@ -49,6 +53,22 @@ fn target_os() -> str {
4953
ret "macos";
5054
}
5155

56+
fn pipe() -> tup(int, int) {
57+
let vec[mutable int] fds = vec(mutable 0, 0);
58+
check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
59+
ret tup(fds.(0), fds.(1));
60+
}
61+
62+
fn fd_FILE(int fd) -> libc.FILE {
63+
ret libc.fdopen(fd, _str.buf("r"));
64+
}
65+
66+
fn waitpid(int pid) -> int {
67+
let vec[mutable int] status = vec(mutable 0);
68+
check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
69+
ret status.(0);
70+
}
71+
5272
// Local Variables:
5373
// mode: rust;
5474
// fill-column: 78;

src/lib/run_program.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import _str.sbuf;
2+
import _vec.vbuf;
3+
4+
native "rust" mod rustrt {
5+
fn rust_run_program(vbuf argv, int in_fd, int out_fd, int err_fd) -> int;
6+
}
7+
8+
fn argvec(str prog, vec[str] args) -> vec[sbuf] {
9+
auto argptrs = vec(_str.buf(prog));
10+
for (str arg in args) {
11+
argptrs = _vec.push[sbuf](argptrs, _str.buf(arg));
12+
}
13+
argptrs = _vec.push[sbuf](argptrs, 0 as sbuf);
14+
ret argptrs;
15+
}
16+
17+
impure fn run_program(str prog, vec[str] args) -> int {
18+
auto pid = rustrt.rust_run_program(_vec.buf[sbuf](argvec(prog, args)),
19+
0, 0, 0);
20+
ret os.waitpid(pid);
21+
}
22+
23+
type program =
24+
state obj {
25+
fn get_id() -> int;
26+
fn input() -> io.writer;
27+
fn output() -> io.reader;
28+
impure fn close_input();
29+
impure fn finish() -> int;
30+
};
31+
32+
impure fn start_program(str prog, vec[str] args) -> @program {
33+
auto pipe_input = os.pipe();
34+
auto pipe_output = os.pipe();
35+
auto pid = rustrt.rust_run_program
36+
(_vec.buf[sbuf](argvec(prog, args)),
37+
pipe_input._0, pipe_output._1, 0);
38+
if (pid == -1) {fail;}
39+
os.libc.close(pipe_input._0);
40+
os.libc.close(pipe_output._1);
41+
42+
state obj new_program(int pid,
43+
int in_fd,
44+
os.libc.FILE out_file,
45+
mutable bool finished) {
46+
fn get_id() -> int {ret pid;}
47+
fn input() -> io.writer {
48+
ret io.new_writer(io.fd_buf_writer(in_fd, false));
49+
}
50+
fn output() -> io.reader {
51+
ret io.FILE_reader(out_file, false);
52+
}
53+
impure fn close_input() {
54+
os.libc.close(in_fd);
55+
}
56+
impure fn finish() -> int {
57+
if (finished) {ret 0;}
58+
finished = true;
59+
os.libc.close(in_fd);
60+
ret os.waitpid(pid);
61+
}
62+
drop {
63+
if (!finished) {
64+
os.libc.close(in_fd);
65+
os.waitpid(pid);
66+
}
67+
os.libc.fclose(out_file);
68+
}
69+
}
70+
ret @new_program(pid, pipe_input._1,
71+
os.fd_FILE(pipe_output._0),
72+
false);
73+
}
74+
75+
impure fn program_output(str prog, vec[str] args)
76+
-> rec(int status, str out) {
77+
auto pr = start_program(prog, args);
78+
pr.close_input();
79+
auto out = pr.output();
80+
auto buf = "";
81+
while (!out.eof()) {
82+
auto bytes = out.read_bytes(4096u);
83+
buf += _str.unsafe_from_bytes(bytes);
84+
}
85+
ret rec(status=pr.finish(), out=buf);
86+
}
87+
88+
89+
// Local Variables:
90+
// mode: rust
91+
// fill-column: 78;
92+
// indent-tabs-mode: nil
93+
// c-basic-offset: 4
94+
// buffer-file-coding-system: utf-8-unix
95+
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
96+
// End:

src/lib/std.rc

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ mod util;
2727

2828
auth io = unsafe;
2929
auth fs = unsafe;
30+
auth os = unsafe;
3031
auth os_fs = unsafe;
32+
auth run = unsafe;
3133
auth _str = unsafe;
3234
auth _vec = unsafe;
3335
auth _task = unsafe;
@@ -52,9 +54,9 @@ alt (target_os) {
5254
mod os_fs = "posix_fs.rs";
5355
}
5456
}
57+
mod run = "run_program.rs";
5558
mod fs;
5659

57-
5860
// FIXME: parametric
5961
mod map;
6062
mod deque;

src/lib/win32_os.rs

+22
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ native mod libc = "msvcrt.dll" {
99

1010
type FILE;
1111
fn fopen(sbuf path, sbuf mode) -> FILE;
12+
fn _fdopen(int fd, sbuf mode) -> FILE;
1213
fn fclose(FILE f);
1314
fn fgetc(FILE f) -> int;
1415
fn ungetc(int c, FILE f);
1516
fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
1617
fn fseek(FILE f, int offset, int whence) -> int;
18+
19+
fn _pipe(vbuf fds, uint size, int mode) -> int;
1720
}
1821

1922
mod libc_constants {
@@ -39,6 +42,25 @@ fn target_os() -> str {
3942
ret "win32";
4043
}
4144

45+
fn pipe() -> tup(int, int) {
46+
let vec[mutable int] fds = vec(mutable 0, 0);
47+
check(os.libc._pipe(_vec.buf[mutable int](fds), 1024u,
48+
libc_constants.O_BINARY()) == 0);
49+
ret tup(fds.(0), fds.(1));
50+
}
51+
52+
fn fd_FILE(int fd) -> libc.FILE {
53+
ret libc._fdopen(fd, _str.buf("r"));
54+
}
55+
56+
native "rust" mod rustrt {
57+
fn rust_process_wait(int handle) -> int;
58+
}
59+
60+
fn waitpid(int pid) -> int {
61+
ret rustrt.rust_process_wait(pid);
62+
}
63+
4264
// Local Variables:
4365
// mode: rust;
4466
// fill-column: 78;

src/rt/rust_builtin.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11

2-
#include <dirent.h>
3-
#include <sys/types.h>
4-
#include <sys/stat.h>
52
#include "rust_internal.h"
63

74
/* Native builtins. */

src/rt/rust_internal.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
#include <stdint.h>
1212
#include <inttypes.h>
1313
#include <stdarg.h>
14-
14+
#include <sys/types.h>
15+
#include <sys/stat.h>
1516
#include <stdio.h>
1617
#include <string.h>
18+
#include <fcntl.h>
19+
1720
#include "rust.h"
1821
#include "rand.h"
1922
#include "uthash.h"
@@ -26,12 +29,10 @@ extern "C" {
2629
}
2730
#elif defined(__GNUC__)
2831
#include <unistd.h>
29-
#include <sys/types.h>
30-
#include <sys/stat.h>
31-
#include <fcntl.h>
3232
#include <dlfcn.h>
3333
#include <pthread.h>
3434
#include <errno.h>
35+
#include <dirent.h>
3536
#else
3637
#error "Platform not supported."
3738
#endif

0 commit comments

Comments
 (0)