about summary refs log tree commit diff
path: root/src/lib/Run_Program.rs
blob: 30c0ee9c9a2fca084394d068fbc5b8afa5caaa02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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) {
        Vec.push[sbuf](argptrs, Str.buf(arg));
    }
    Vec.push[sbuf](argptrs, 0 as sbuf);
    ret argptrs;
}

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;
        fn close_input();
        fn finish() -> int;
    };

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.new_reader(IO.FILE_buf_reader(out_file, false));
        }
        fn close_input() {
            OS.libc.close(in_fd);
        }
        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);
}

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: