----------------------------------------------------------------------------- -- -- Onions Network Streams Library -- -- O N I O N S . O U T S T R E A M S -- -- S p e c -- -- Copyright (C) 1997-1998 Regents of the University of California -- -- Onions is free software; you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published by the Free -- Software Foundation, with or without the single exception listed below; -- either version 2, or (at your option) any later version. Onions 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. See the GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- distributed with Onions; see the file COPYING. If not, write to the -- Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA -- 02111-1307, USA. -- -- As a special exception, if other files instantiate generics from this -- library, or you link this library with other files to produce an -- executable, this library does not by itself cause the resulting -- executable to be covered by the GNU General Public License. This -- exception does not however invalidate any other reasons why the -- executable file might be covered by the GNU General Public License. -- -- Created in 1997 by Roy T. Fielding ----------------------------------------------------------------------------- -- -- The Onions Output Streams class defines objects that move data from one -- interface to another while minimizing the copying of data in memory. -- Multiple stream objects can be cascaded to build an output pipe, where -- writing to the head of the pipe causes the head stream object -- to write to the next outbound stream object, and on down the line. -- One of the main features of streams is that they can filter the data -- as it passes, converting, adding to, and/or removing from the -- data before piping it to the output. Since multiple streams can be -- cascaded, the complete data conversion is the sum of the individual -- data conversions performed by the stream objects. -- -- This package defines an Output Stream with a null filter. -- The child packages File and Channel implement streams for writing to -- files and TCP/IP sockets, respectively. -- Additional child packages can implement a filter simply by -- overriding the Process procedure for the derived stream object -- and duplicating the dispatched routines that call Process. -- -- Each stream object supports dual interfaces: the Ada.Streams interface -- that uses a caller-provided Stream_Element_Array to pass data, and our -- own Bucket interface that passes the data as a list of dynamically -- allocated Iovec structures. The Ada.Streams interface requires that -- the data be copied every time it is filtered or placed in a buffer. -- The Bucket interface minimizes copying and corresponds nicely to the -- more efficient C_writev system call. -- with Ada.IO_Exceptions; with Ada.Streams; with Interfaces.C.Strings; with System.Storage_Elements; with Onions.Buckets; use Onions.Buckets; with Onions.Thin; package Onions.Outstreams is type Output_Stream is new Ada.Streams.Root_Stream_Type with private; type Output_Stream_Ptr is access Output_Stream; type Output_Pipe is access all Output_Stream'Class; ----------------------------------------------------- -- Output Pipe Classwide Manipulation Operations -- ----------------------------------------------------- -- Close and free a stream pipe after flushing its write buffers. -- procedure Close (Pipe : in out Output_Pipe); -- Abort_Stream should only be used if a stream is interrupted -- by the user, or an error occurs that makes the whole stream bad. -- It forces the stream closed without a flush. -- procedure Abort_Stream (Pipe : in out Output_Pipe); -- Reset is like Close, but resets the stream to the -- state it would be in if it was just created. -- procedure Reset (Pipe : in Output_Pipe); -- Flush a stream pipe's write buffers. -- procedure Flush (Pipe : in Output_Pipe); -- Push places the old Pipe outbound of Head and sets Pipe := Head -- Head is a pipe that might consist of multiple stream objects. -- procedure Push (Pipe : in out Output_Pipe; Head : in Output_Pipe); -- Pop flushes anything in the current Pipe head's buffers, -- moves that object to Head, sets Pipe to whatever is outbound of Head, -- and then disconnects Head from that outbound stream. -- procedure Pop (Pipe : in out Output_Pipe; Head : out Output_Pipe); ----------------------------------------------- -- Output Pipe Classwide Output Operations -- ----------------------------------------------- -- Write places a list of buckets onto Stream in order. -- This corresponds nicely with C_writev. -- procedure Write (Pipe : in Output_Pipe; ItemList : in Bucket_List); procedure Write (Pipe : in Output_Pipe; Item : in Bucket); procedure Write (Pipe : in Output_Pipe; Item : in String); ----------------------------------------------- -- Output Pipe Classwide Status Operations -- ----------------------------------------------- -- Set_Timeout places a limit on the amount of time in milliseconds -- any atomic stream operation is allowed to block. This limit applies -- to the entire stream pipe, but is only likely to be used by the most -- outbound stream object. A value of 0 means never timeout. The call -- is propagated to the Outbound stream object. Get_Timeout retrieves -- the current stream timeout value in milliseconds. -- procedure Set_Timeout (Pipe : in Output_Pipe; Millisec : in Natural); function Get_Timeout (Pipe : in Output_Pipe) return Natural; -- Get_Error can be called after an error exception has been raised -- to get the C errno or error string associated with the original error. -- The call is propagated to the Outbound stream object. -- function Get_Error (Pipe : in Output_Pipe) return C.int; function Get_Error (Pipe : in Output_Pipe) return String; -- Bytes returns a count of the stream pipe's outbound interface, -- usually for diagnostic purposes. -- function Bytes (Pipe : in Output_Pipe) return Natural; -- Get a stream pipe's write buffer size for max blocks. -- function Get_Max_Buffer_Blocksize (Pipe : in Output_Pipe) return Natural; -- Set a stream pipe's write buffer size for max blocks. -- A Num_Blocks of 0 will set it to unbuffered. -- procedure Set_Max_Buffer_Blocksize (Pipe : in Output_Pipe; Num_Blocks : in Natural); -- Name returns a string containing a meaningful name for this pipe, -- usually obtained from the most outbound stream object (because that's -- where things like file, directory, or host names are stored). -- function Name (Pipe : in Output_Pipe) return String; -------------------------------------------------------------------- -- Dispatching Stream Control Operations -- -- -- -- If a dispatching method has an implementation that invokes -- -- another primitive method, then derived classes MUST override -- -- the dispatching method or be totally screwed, since Ada95 -- -- only does dynamic invocation within classwide methods. -- -- Combine this with hidden implementation bodies and ... yes, -- -- you guessed it, all dispatching methods must be overridden -- -- by all derived types. Who needs multiple inheritance when -- -- you can have zero inheritance at double the price? *sigh* -- -------------------------------------------------------------------- -- Free the storage associated with a stream object. -- procedure Free (SP : in out Output_Stream_Ptr); -- Close a stream object (flushes the buffers) and -- propagate the close downstream. -- procedure Close (Stream : in out Output_Stream); -- Abort_Stream should only be used if a stream is interrupted -- by the user, or an error occurs that makes the whole stream bad. -- It forces the stream closed without a flush. -- procedure Abort_Stream (Stream : in out Output_Stream); -- Reset is like Close, but resets the stream to the state -- it would be in if it was just created. It flushes -- anything in its own buffers. -- procedure Reset (Stream : in out Output_Stream); -- The Flush method tells the stream to send any outbound buffered data -- downstream, but without taking down the stream. The stream decides -- whether or not it has buffered data to write. -- procedure Flush (Stream : in out Output_Stream); -- Get a stream's write buffer size for max blocks. -- function Get_Max_Buffer_Blocksize (Stream : in Output_Stream) return Natural; -- Set a stream's write buffer size for max blocks. -- A Num_Blocks of 0 will set it to unbuffered. -- procedure Set_Max_Buffer_Blocksize (Stream : in out Output_Stream; Num_Blocks : in Natural); -- Name returns a string containing a meaningful name for this stream, -- usually obtained from the most outbound stream object (because that's -- where things like file, directory, or host names are stored). -- function Name (Stream : in Output_Stream) return String; ------------------------------------------ -- Ada.Streams Dispatching Operations -- ------------------------------------------ -- Read is defined by Ada.Streams for abstract stream operations. -- Raises Mode_Error for an Output Stream. -- procedure Read (Stream : in out Output_Stream; Item : out Ada.Streams.Stream_Element_Array; Last : out Ada.Streams.Stream_Element_Offset); -- Write places each of the elements of Item into Stream in order. This -- interface is defined by Ada.Streams for abstract stream operations. -- We won't use it much because it forces a full data copy when filtering. -- procedure Write (Stream : in out Output_Stream; Item : in Ada.Streams.Stream_Element_Array); ---------------------------------- -- Data Processing Operations -- ---------------------------------- -- Process does the magic necessary to move the input data from -- the Unprocessed write queue to the downstream object. -- If Everything, then process the entire Unprocessed buffer -- as if it were the end-of-stream. -- procedure Process (Stream : in out Output_Stream; Everything : Boolean); ------------------------ -- Utility Routines -- ------------------------ -- Write_Vector will perform a system writev on an open descriptor, -- from the write Buffer_List of length Buffer_Num, containing a total -- Buffer_Bytes. If the descriptor is not ready for writing, -- it will wait up to Timeout milliseconds for it to become ready, -- or forever if Timeout = 0. -- -- Raises Timeout_Exceeded if we have to wait longer than Timeout; -- Device_Error if anything else goes fatally wrong. -- procedure Write_Vector (Filedes : in Onions.Thin.Descriptor; Timeout : in Natural; Buffer_List : in Bucket_List; Buffer_Num : in Natural; Buffer_Bytes : in System.Storage_Elements.Storage_Count); ------------------ -- Exceptions -- ------------------ -- Status_Error is raised if data is put down or read from a -- stream pipe in which the end-object doesn't have anything connected -- to its outbound interface (even though it expected another stream). -- Status_Error : exception renames Ada.IO_Exceptions.Status_Error; -- Mode_Error indicates an attempt to read from an Output_Stream. -- Mode_Error : exception renames Ada.IO_Exceptions.Mode_Error; -- End_Error indicates an attempt to write to a closed pipe (EOF). -- End_Error : exception renames Ada.IO_Exceptions.End_Error; -- Other standard Ada exceptions for (file) streams which might be -- raised if the stream end-object is doing device Stream_IO operations. -- Name_Error : exception renames Ada.IO_Exceptions.Name_Error; Use_Error : exception renames Ada.IO_Exceptions.Use_Error; Device_Error : exception renames Ada.IO_Exceptions.Device_Error; Data_Error : exception renames Ada.IO_Exceptions.Data_Error; -- Timeout_Exceeded indicates that a descriptor was not available -- for writing in the time allotted to Timeout. -- Timeout_Exceeded : exception; private type Output_Stream is new Ada.Streams.Root_Stream_Type with record Outbound : Output_Pipe; -- the stream object stack below (outbound of) this object Unprocessed : Bucket_Brigade; -- data given to our Write interface that is not yet filtered Byte_Count : System.Storage_Elements.Storage_Count := 0; -- amount of data written to the outbound stack Timeout : Natural := 0; -- time (in milliseconds) to limit blocking operations System_Error : C.int := 0; -- if a Unix system call results in an error, it will set errno -- to the global constant corresponding to that error. We save -- it here (from C_errno) so that it won't get trampled in later -- system calls by the exception handler. end record; end Onions.Outstreams;