Merge: Loose Tokens
[nit.git] / lib / standard / exec.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
5 #
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
12 # another product.
13
14 # Invocation and management of operating system sub-processes.
15 # Standard input and output can be handled through streams.
16 module exec
17
18 import file
19
20 # Simple sub-process
21 class Process
22 # The pid of the process
23 fun id: Int do return data.id
24
25 # Is the process finished?
26 fun is_finished: Bool do return data.is_finished
27
28 # Wait the termination of the process
29 fun wait
30 do
31 data.wait
32 assert is_finished
33 end
34
35 # The status once finished
36 fun status: Int
37 do
38 assert is_finished
39 return data.status
40 end
41
42 # The executable run
43 # Is a filepath, or a executable found in PATH
44 var command: String
45
46 # The arguments of the command
47 # Starts with the first real arguments---ie. does not include the progname (`argv[0]`, in C)
48 var arguments: nullable Array[String]
49
50 # Launch a command with some arguments
51 init(command: String, arguments: String...) is old_style_init do
52 self.command = command
53 self.arguments = arguments
54 execute
55 end
56
57 # Launch a simple command with arguments passed as an array
58 init from_a(command: String, arguments: nullable Array[String])
59 do
60 self.command = command
61 self.arguments = arguments
62 execute
63 end
64
65 # flags used internally to know whith pipe to open
66 private fun pipeflags: Int do return 0
67
68 # Internal code to handle execution
69 protected fun execute
70 do
71 # The pass the arguments as a big C string where elements are separated with '\0'
72 var args = new FlatBuffer
73 var l = 1 # Number of elements in args
74 args.append(command)
75 if arguments != null then
76 for a in arguments do
77 args.add('\0')
78 #a.output_class_name
79 args.append(a)
80 end
81 l += arguments.length
82 end
83 data = basic_exec_execute(command.to_cstring, args.to_s.to_cstring, l, pipeflags)
84 end
85
86 private var data: NativeProcess
87 private fun basic_exec_execute(p: NativeString, av: NativeString, ac: Int, pf: Int): NativeProcess is extern "exec_Process_Process_basic_exec_execute_4"
88 end
89
90 # `Process` on which the `stdout` is readable like a `Reader`
91 class ProcessReader
92 super Process
93 super Reader
94
95 # File Descriptor used for the input.
96 var stream_in: FileReader is noinit
97
98 redef fun close do stream_in.close
99
100 redef fun read_char do return stream_in.read_char
101
102 redef fun read_byte do return stream_in.read_byte
103
104 redef fun eof do return stream_in.eof
105
106 redef fun pipeflags do return 2
107
108 redef fun execute
109 do
110 super
111 stream_in = new FileReader.from_fd(data.out_fd)
112 end
113 end
114
115 # `Process` on which `stdin` is writable like a `Writer`
116 class ProcessWriter
117 super Process
118 super Writer
119
120 # File Descriptor used for the output.
121 var stream_out: Writer is noinit
122
123 redef fun close do stream_out.close
124
125 redef fun is_writable do return stream_out.is_writable
126
127 redef fun write(s) do stream_out.write(s)
128
129 redef fun pipeflags do return 1
130
131 redef fun execute
132 do
133 super
134 var out = new FileWriter.from_fd(data.in_fd)
135 out.set_buffering_mode(0, sys.buffer_mode_none)
136 stream_out = out
137 end
138 end
139
140 # `Process` on which stdout can be read and stdin can be written to like a `Duplex`
141 class ProcessDuplex
142 super ProcessReader
143 super ProcessWriter
144 super Duplex
145
146 redef fun close
147 do
148 stream_in.close
149 stream_out.close
150 end
151
152 redef fun pipeflags do return 3
153
154 redef fun execute
155 do
156 super
157 end
158 end
159
160 redef class Sys
161 # Execute a shell command and return its error code
162 fun system(command: String): Int
163 do
164 return command.to_cstring.system
165 end
166 end
167
168 redef class NativeString
169 # Execute self as a shell command.
170 #
171 # See the posix function system(3).
172 fun system: Int is extern "string_NativeString_NativeString_system_0"
173 end
174
175 private extern class NativeProcess
176 fun id: Int is extern "exec_NativeProcess_NativeProcess_id_0"
177 fun is_finished: Bool is extern "exec_NativeProcess_NativeProcess_is_finished_0"
178 fun status: Int is extern "exec_NativeProcess_NativeProcess_status_0"
179 fun wait is extern "exec_NativeProcess_NativeProcess_wait_0"
180
181 fun in_fd: Int is extern "exec_NativeProcess_NativeProcess_in_fd_0"
182 fun out_fd: Int is extern "exec_NativeProcess_NativeProcess_out_fd_0"
183 fun err_fd: Int is extern "exec_NativeProcess_NativeProcess_err_fd_0"
184 end
185