# Standard input and output can be handled through streams.
module exec
-import stream
+import file
# Simple sub-process
class Process
class IProcess
super Process
super IStream
- var stream_in: FDIStream is noinit
+ var stream_in: IFStream is noinit
redef fun close do stream_in.close
redef fun execute
do
super
- stream_in = new FDIStream(data.out_fd)
+ stream_in = new IFStream.from_fd(data.out_fd)
end
end
redef fun execute
do
super
- stream_out = new FDOStream(data.in_fd)
+ stream_out = new OFStream.from_fd(data.in_fd)
end
end
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
+ #include <poll.h>
+ #include <errno.h>
`}
# File Abstract Stream
end
end
+ init from_fd(fd: Int) do
+ self.path = ""
+ prepare_buffer(1)
+ _file = fd.fd_to_stream(read_only)
+ if _file.address_is_null then
+ last_error = new IOError("Error: Converting fd {fd} to stream failed with '{sys.errno.strerror}'")
+ end_reached = true
+ end
+ end
end
# File output stream
is_writable = false
end
end
+
+ # Creates a new File stream from a file descriptor
+ init from_fd(fd: Int) do
+ self.path = ""
+ _file = fd.fd_to_stream(wipe_write)
+ _is_writable = true
+ if _file.address_is_null then
+ last_error = new IOError("Error: Opening stream from file descriptor {fd} failed with '{sys.errno.strerror}'")
+ _is_writable = false
+ end
+ end
end
+redef class Int
+ # Creates a file stream from a file descriptor `fd` using the file access `mode`.
+ #
+ # NOTE: The `mode` specified must be compatible with the one used in the file descriptor.
+ private fun fd_to_stream(mode: NativeString): NativeFile is extern "file_int_fdtostream"
+end
+
+# Constant for read-only file streams
+private fun read_only: NativeString do return "r".to_cstring
+
+# Constant for write-only file streams
+#
+# If a stream is opened on a file with this method,
+# it will wipe the previous file if any.
+# Else, it will create the file.
+private fun wipe_write: NativeString do return "w".to_cstring
+
###############################################################################
class Stdin
# Standard output for errors
var stderr: OStream = new Stderr is protected writable
+ # Enumeration for buffer mode full (flushes when buffer is full)
+ fun buffer_mode_full: Int is extern "file_Sys_Sys_buffer_mode_full_0"
+ # Enumeration for buffer mode line (flushes when a `\n` is encountered)
+ fun buffer_mode_line: Int is extern "file_Sys_Sys_buffer_mode_line_0"
+ # Enumeration for buffer mode none (flushes ASAP when something is written)
+ fun buffer_mode_none: Int is extern "file_Sys_Sys_buffer_mode_none_0"
+
+ # returns first available stream to read or write to
+ # return null on interruption (possibly a signal)
+ protected fun poll( streams : Sequence[FStream] ) : nullable FStream
+ do
+ var in_fds = new Array[Int]
+ var out_fds = new Array[Int]
+ var fd_to_stream = new HashMap[Int,FStream]
+ for s in streams do
+ var fd = s.fd
+ if s isa IFStream then in_fds.add( fd )
+ if s isa OFStream then out_fds.add( fd )
+
+ fd_to_stream[fd] = s
+ end
+
+ var polled_fd = intern_poll( in_fds, out_fds )
+
+ if polled_fd == null then
+ return null
+ else
+ return fd_to_stream[polled_fd]
+ end
+ end
+
+ private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
+ int in_len, out_len, total_len;
+ struct pollfd *c_fds;
+ sigset_t sigmask;
+ int i;
+ int first_polled_fd = -1;
+ int result;
+
+ in_len = Array_of_Int_length( in_fds );
+ out_len = Array_of_Int_length( out_fds );
+ total_len = in_len + out_len;
+ c_fds = malloc( sizeof(struct pollfd) * total_len );
+
+ /* input streams */
+ for ( i=0; i<in_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( in_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLIN;
+ }
+
+ /* output streams */
+ for ( i=0; i<out_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( out_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLOUT;
+ }
+
+ /* poll all fds, unlimited timeout */
+ result = poll( c_fds, total_len, -1 );
+
+ if ( result > 0 ) {
+ /* analyse results */
+ for ( i=0; i<total_len; i++ )
+ if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
+ c_fds[i].revents & POLLHUP ) /* closed */
+ {
+ first_polled_fd = c_fds[i].fd;
+ break;
+ }
+
+ return Int_as_nullable( first_polled_fd );
+ }
+ else if ( result < 0 )
+ fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
+
+ return null_Int();
+ `}
+
end
# Print `objects` on the standard output (`stdout`).
}
return res > 0;
}
+
+FILE* file_int_fdtostream(int fd, char* mode){
+ return fdopen(fd, mode);
+}
extern void *string_NativeString_NativeString_file_stat_0(char *f);
extern void *file_NativeFile_NativeFile_file_stat_0(FILE *f);
extern int string_NativeString_NativeString_file_delete_0(char *f);
+FILE* file_int_fdtostream(int fd, char* mode);
#define file_NativeFile_NativeFile_io_read_2(p, b, l) fread((b), 1, (l), (FILE*)(p))
#define file_NativeFile_NativeFile_io_write_2(p, b, l) fwrite((b), 1, (l), (FILE*)(p))
in "C" `{
#include <unistd.h>
- #include <poll.h>
- #include <errno.h>
#include <string.h>
#include <signal.h>
`}
super OStream
end
-##############################################################"
-
-abstract class FDStream
- super IOS
- # File description
- var fd: Int
-
- redef fun close do native_close(fd)
-
- private fun native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1"
- private fun native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1"
- private fun native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3"
- private fun native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3"
- private fun native_write_char(i: Int, c: Char): Int is extern "stream_FDStream_FDStream_native_write_char_2"
-end
-
-class FDIStream
- super FDStream
- super IStream
- redef var eof: Bool = false
-
- redef fun read_char
- do
- var nb = native_read_char(fd)
- if nb == -1 then eof = true
- return nb
- end
-end
-
-class FDOStream
- super FDStream
- super OStream
- redef var is_writable = true
-
- redef fun write(s)
- do
- var nb = native_write(fd, s.to_cstring, s.length)
- if nb < s.length then is_writable = false
- end
-end
-
-class FDIOStream
- super FDIStream
- super FDOStream
- super IOStream
-end
-
-redef interface Object
- # returns first available stream to read or write to
- # return null on interruption (possibly a signal)
- protected fun poll( streams : Sequence[FDStream] ) : nullable FDStream
- do
- var in_fds = new Array[Int]
- var out_fds = new Array[Int]
- var fd_to_stream = new HashMap[Int,FDStream]
- for s in streams do
- var fd = s.fd
- if s isa FDIStream then in_fds.add( fd )
- if s isa FDOStream then out_fds.add( fd )
-
- fd_to_stream[fd] = s
- end
-
- var polled_fd = intern_poll( in_fds, out_fds )
-
- if polled_fd == null then
- return null
- else
- return fd_to_stream[polled_fd]
- end
- end
-
- private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
- int in_len, out_len, total_len;
- struct pollfd *c_fds;
- sigset_t sigmask;
- int i;
- int first_polled_fd = -1;
- int result;
-
- in_len = Array_of_Int_length( in_fds );
- out_len = Array_of_Int_length( out_fds );
- total_len = in_len + out_len;
- c_fds = malloc( sizeof(struct pollfd) * total_len );
-
- /* input streams */
- for ( i=0; i<in_len; i ++ ) {
- int fd;
- fd = Array_of_Int__index( in_fds, i );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLIN;
- }
-
- /* output streams */
- for ( i=0; i<out_len; i ++ ) {
- int fd;
- fd = Array_of_Int__index( out_fds, i );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLOUT;
- }
-
- /* poll all fds, unlimited timeout */
- result = poll( c_fds, total_len, -1 );
-
- if ( result > 0 ) {
- /* analyse results */
- for ( i=0; i<total_len; i++ )
- if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
- c_fds[i].revents & POLLHUP ) /* closed */
- {
- first_polled_fd = c_fds[i].fd;
- break;
- }
-
- return Int_as_nullable( first_polled_fd );
- }
- else if ( result < 0 )
- fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
-
- return null_Int();
- `}
-end
-
# Stream to a String.
#
# Mainly used for compatibility with OStream type and tests.
+++ /dev/null
-/* This file is part of NIT ( http://www.nitlanguage.org ).
- *
- * Copyright 2004-2008 Jean Privat <jean@pryen.org>
- *
- * This file is free software, which comes along with NIT. This software is
- * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. You can modify it is you want, provided this header
- * is kept unaltered, and a notification of the changes is added.
- * You are allowed to redistribute it and sell it, alone or is a part of
- * another product.
- */
-
-#include "stream_nit.h"
-
-int stream_FDStream_FDStream_native_read_char_1(void *s, int fd) {
- int result;
- char buf;
- ssize_t r = read(fd, &buf, 1);
- if (r == 0)
- result = -1;
- else
- result = buf;
- return result;
-}
+++ /dev/null
-#ifndef __STREAM_NIT_H
-#define __STREAM_NIT_H
-/* This file is part of NIT ( http://www.nitlanguage.org ).
- *
- * Copyright 2004-2008 Jean Privat <jean@pryen.org>
- *
- * This file is free software, which comes along with NIT. This software is
- * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. You can modify it is you want, provided this header
- * is kept unaltered, and a notification of the changes is added.
- * You are allowed to redistribute it and sell it, alone or is a part of
- * another product.
- */
-
-#include <unistd.h>
-
-int stream_FDStream_FDStream_native_read_char_1(void *s, int fd);
-
-#define stream_FDStream_FDStream_native_close_1(self, p0) (close(p0))
-#define stream_FDStream_FDStream_native_read_3(s, i, b, l) read((i), ((b)), ((l)))
-#define stream_FDStream_FDStream_native_write_3(s, i, b, l) write((i), ((b)), ((l)))
-#define stream_FDStream_FDStream_native_write_char_2(s, i, c) write((i), (char[]){(c)}, 1 )
-
-#endif
# See the License for the specific language governing permissions and
# limitations under the License.
-import stream
+import file
-var fd_in = new FDIStream(0)
-var fd_out = new FDOStream(1)
-var fd_err = new FDOStream(2)
+var fd_in = new IFStream.from_fd(0)
+var fd_out = new OFStream.from_fd(1)
+var fd_err = new OFStream.from_fd(2)
fd_out.write("Hello\n")
var s = fd_in.read_line
fd_out.write(s)
+fd_out.write("\n")
fd_err.write("World\n")
p2 = new IProcess( "sleep", "0.1" )
p3 = new IProcess( "sleep", "0.4" )
-var order = new Array[FDStream]
+var order = new Array[FStream]
var streams = [p1.stream_in, p2.stream_in, p3.stream_in]
while not streams.is_empty do
if s == null then continue # may have been interrupted
order.add( s )
- streams.remove( s.as(FDIStream ) )
+ streams.remove( s.as(IFStream ) )
end
print order[0] == p2.stream_in