diff --git a/src/c/file.d b/src/c/file.d index df87a3999..3f72dba91 100755 --- a/src/c/file.d +++ b/src/c/file.d @@ -5299,6 +5299,12 @@ ecl_open_stream(cl_object fn, enum ecl_smmode smm, cl_object if_exists, if_exists != @':overwrite') { FEinvalid_option(@':if-exists', if_exists); } + if (flags & ECL_STREAM_CLOSE_ON_EXEC) { + open_flags |= O_CLOEXEC; + } + if (flags & ECL_STREAM_NONBLOCK) { + open_flags |= O_NONBLOCK; + } fd = safe_open(fname, open_flags, mode); if (fd < 0) { @@ -5367,6 +5373,8 @@ ecl_open_stream(cl_object fn, enum ecl_smmode smm, cl_object if_exists, (if_does_not_exist ECL_NIL idnesp) (external_format @':default') (cstream ECL_T) + (close_on_exec ECL_T) + (nonblock ECL_NIL) &aux strm) enum ecl_smmode smm; int flags = 0; @@ -5414,6 +5422,12 @@ ecl_open_stream(cl_object fn, enum ecl_smmode smm, cl_object if_exists, if (!Null(cstream)) { flags |= ECL_STREAM_C_STREAM; } + if (!Null(close_on_exec)) { + flags |= ECL_STREAM_CLOSE_ON_EXEC; + } + if (!Null(nonblock)) { + flags |= ECL_STREAM_NONBLOCK; + } strm = ecl_open_stream(filename, smm, if_exists, if_does_not_exist, byte_size, flags, external_format); @(return strm); diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h index 4666ba636..d18cdd07f 100755 --- a/src/c/symbols_list.h +++ b/src/c/symbols_list.h @@ -1359,6 +1359,7 @@ cl_symbols[] = { {KEY_ "CATCH" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "CASE" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "CIRCLE" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, +{KEY_ "CLOSE-ON-EXEC" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "COMPILE-TOPLEVEL" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "COMMON" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "CONC-NAME" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, @@ -1435,6 +1436,7 @@ cl_symbols[] = { {KEY_ "NEW-VERSION" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "NEWEST" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "NICKNAMES" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, +{KEY_ "NONBLOCK" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "OBJECT" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "OFFSET" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, {KEY_ "OPERATION" ECL_FUN(NULL, NULL, -1) ECL_VAR(KEYWORD, OBJNULL)}, diff --git a/src/doc/manual/extensions/osi.txi b/src/doc/manual/extensions/osi.txi index 68a225096..1fe6495f1 100644 --- a/src/doc/manual/extensions/osi.txi +++ b/src/doc/manual/extensions/osi.txi @@ -293,11 +293,11 @@ Controls escaping of the arguments passed to @code{CreateProcess}. @subsection FIFO files (named pipes) Named pipe (known as fifo) may be created on UNIX with a shell command -mkfifo. ECL opens such files in non-blocking -mode. @coderef{ext:file-kind} will return for such file -@code{:fifo}. Since it is impossible to guess how many characters are -available in this special file @code{file-length} function will return -NIL. +mkfifo. They can be opened in non-blocking mode by using @code{:nonblock +t} option for @coderef{open}. @coderef{ext:file-kind} will return for +such file @code{:fifo}. Since it is impossible to guess how many +characters are available in this special file @code{file-length} +function will return @code{nil}. @node Operating System Interface Reference @subsection Operating System Interface Reference diff --git a/src/doc/manual/standards/streams.txi b/src/doc/manual/standards/streams.txi index 56cbc1494..698578d08 100644 --- a/src/doc/manual/standards/streams.txi +++ b/src/doc/manual/standards/streams.txi @@ -108,59 +108,23 @@ and the table of known symbols is shown below. Note how some symbols (@code{:cr} @node Streams - Dictionary @subsection Dictionary -@subsubsection Sequence Streams - -@lspdef ext:sequence-stream -@deftp {System Class} ext:sequence-stream - -@paragraph Class Precedence List -@coderef{ext:sequence-stream}, @code{stream}, @code{t} - -@paragraph Description -Sequence streams work similar to string streams for vectors. The -supplied vectors that the streams read from or write to must have a -byte sized element type, i.e. @code{(signed-byte 8)}, -@code{(unsigned-byte 8)} or @code{base-char}. - -The semantics depend on the vector element type and the external -format of the stream. If no external format is supplied and the -element type is an integer type, the stream is a binary stream and -accepts only integers of the same type as the element type of the -vector. Otherwise, the stream accepts both characters and integers and -converts them using the given external format. If the element type is -@code{base-char}, the elements of the vectors are treated as bytes. -This means that writing a character may use multiple elements of the -vector, whose @code{char-code}s will be equal to the values of the -bytes comprising the character in the given external format. -@end deftp - -@lspdef ext:make-sequence-input-stream -@defun ext:make-sequence-input-stream vector &key (start 0) (end nil) (external-format nil) -Create a sequence input stream with the subsequence bounded by -@var{start} and @var{end} of the given vector. -@end defun -@lspdef ext:make-sequence-output-stream -@defun ext:make-sequence-output-stream vector &key (external-format nil) -Create a sequence output stream. -@end defun - -@exindex Using sequence streams -Example: - -Using sequence streams to convert to a UTF8 encoded base string -@lisp -CL-USER> (defvar *output* (make-array 20 :element-type 'base-char :adjustable t :fill-pointer 0)) -*OUTPUT* -CL-USER> (defvar *stream* (ext:make-sequence-output-stream *output* :external-format :utf-8)) -*STREAM* -CL-USER> (write-string "Spätzle mit Soß'" *stream*) -"Spätzle mit Soß'" -CL-USER> *output* -"Spätzle mit SoÃ\237'" -@end lisp - @subsubsection File Stream Extensions +@lspdef open +@defun open filespec &key direction element-type if-exists if-does-not-exist external-format close-on-exec nonblock +Additional options for @clhs{f_open.htm,open} include: +@table @code +@item :close-on-exec +Child processes don't inherit a copy of this stream: new processes +created by @code{fork} and @code{exec} (for example by calling +@coderef{ext:run-program}) close the stream after calling @code{exec}. +Defaults to @code{t}. +@item :nonblock +Open fifos or device files in nonblocking mode. Defaults to @code{nil}. +@end table +These options are ignored on operating systems which do not support them. +@end defun + @lspdef ext:set-buffering-mode @defun ext:set-buffering-mode stream mode Control the buffering mode of a stream @@ -303,6 +267,56 @@ that the error can be ignored or the octets can be replaced with a character. @end defun +@subsubsection Sequence Streams + +@lspdef ext:sequence-stream +@deftp {System Class} ext:sequence-stream + +@paragraph Class Precedence List +@coderef{ext:sequence-stream}, @code{stream}, @code{t} + +@paragraph Description +Sequence streams work similar to string streams for vectors. The +supplied vectors that the streams read from or write to must have a +byte sized element type, i.e. @code{(signed-byte 8)}, +@code{(unsigned-byte 8)} or @code{base-char}. + +The semantics depend on the vector element type and the external +format of the stream. If no external format is supplied and the +element type is an integer type, the stream is a binary stream and +accepts only integers of the same type as the element type of the +vector. Otherwise, the stream accepts both characters and integers and +converts them using the given external format. If the element type is +@code{base-char}, the elements of the vectors are treated as bytes. +This means that writing a character may use multiple elements of the +vector, whose @code{char-code}s will be equal to the values of the +bytes comprising the character in the given external format. +@end deftp + +@lspdef ext:make-sequence-input-stream +@defun ext:make-sequence-input-stream vector &key (start 0) (end nil) (external-format nil) +Create a sequence input stream with the subsequence bounded by +@var{start} and @var{end} of the given vector. +@end defun +@lspdef ext:make-sequence-output-stream +@defun ext:make-sequence-output-stream vector &key (external-format nil) +Create a sequence output stream. +@end defun + +@exindex Using sequence streams +Example: + +Using sequence streams to convert to a UTF8 encoded base string +@lisp +CL-USER> (defvar *output* (make-array 20 :element-type 'base-char :adjustable t :fill-pointer 0)) +*OUTPUT* +CL-USER> (defvar *stream* (ext:make-sequence-output-stream *output* :external-format :utf-8)) +*STREAM* +CL-USER> (write-string "Spätzle mit Soß'" *stream*) +"Spätzle mit Soß'" +CL-USER> *output* +"Spätzle mit SoÃ\237'" +@end lisp @node Streams - C Reference @subsection C Reference diff --git a/src/h/internal.h b/src/h/internal.h index 3579987d7..6a0a7abb2 100755 --- a/src/h/internal.h +++ b/src/h/internal.h @@ -234,6 +234,9 @@ extern enum ecl_ffi_tag ecl_foreign_type_code(cl_object type); #define OPEN_RA "a+b" /* Windows does not have this flag (POSIX thing) */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif #ifndef O_NONBLOCK #define O_NONBLOCK 0 #endif diff --git a/src/h/object.h b/src/h/object.h index 69023bc9a..4b2ebd3e1 100644 --- a/src/h/object.h +++ b/src/h/object.h @@ -634,7 +634,9 @@ enum { ECL_STREAM_LITTLE_ENDIAN = 128, ECL_STREAM_C_STREAM = 256, ECL_STREAM_MIGHT_SEEK = 512, - ECL_STREAM_CLOSE_COMPONENTS = 1024 + ECL_STREAM_CLOSE_COMPONENTS = 1024, + ECL_STREAM_CLOSE_ON_EXEC = 2048, + ECL_STREAM_NONBLOCK = 4096 }; /* buffer points to an array of bytes ending at buffer_end. Decode one