Difference between revisions of "Null stream"
(Initial revision) |
m |
||
Line 8: | Line 8: | ||
An instance of the null stream is created using the following function: | An instance of the null stream is created using the following function: | ||
− | < | + | <syntaxhighlight lang="C"> |
int mu_nullstream_create (mu_stream_t *pstr, int mode) | int mu_nullstream_create (mu_stream_t *pstr, int mode) | ||
− | </ | + | </syntaxhighlight> |
It creates an instance of the null stream and returns it in the memory | It creates an instance of the null stream and returns it in the memory | ||
Line 64: | Line 64: | ||
''struct mu_nullstream_pattern'', defined as: | ''struct mu_nullstream_pattern'', defined as: | ||
− | < | + | <syntaxhighlight lang="C"> |
struct mu_nullstream_pattern | struct mu_nullstream_pattern | ||
{ | { | ||
Line 70: | Line 70: | ||
size_t size; /* Number of bytes in pattern */ | size_t size; /* Number of bytes in pattern */ | ||
}; | }; | ||
− | </ | + | </syntaxhighlight> |
The ''pattern'' member points to ''size'' bytes of data which | The ''pattern'' member points to ''size'' bytes of data which | ||
Line 76: | Line 76: | ||
''str'' is a null stream instance, and consider the following code: | ''str'' is a null stream instance, and consider the following code: | ||
− | < | + | <syntaxhighlight lang="C"> |
struct mu_nullstream_pattern pat; | struct mu_nullstream_pattern pat; | ||
char buf[16]; | char buf[16]; | ||
Line 83: | Line 83: | ||
pat.pattern = "01234567"; | pat.pattern = "01234567"; | ||
pat.size = 8; | pat.size = 8; | ||
− | mu_stream_ioctl (str, | + | mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, &pat); |
− | |||
− | |||
− | |||
mu_stream_read (str, buf, sizeof (buf), &n); | mu_stream_read (str, buf, sizeof (buf), &n); | ||
− | </ | + | </syntaxhighlight> |
Then, after the call to <tt>mu_stream_read</tt> with the <tt>size</tt> | Then, after the call to <tt>mu_stream_read</tt> with the <tt>size</tt> | ||
Line 96: | Line 93: | ||
Similarly, the following code: | Similarly, the following code: | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_stream_seek (str, 3, MU_SEEK_SET, NULL); | mu_stream_seek (str, 3, MU_SEEK_SET, NULL); | ||
mu_stream_read (str, buf, sizeof (buf), &n); | mu_stream_read (str, buf, sizeof (buf), &n); | ||
− | </ | + | </syntaxhighlight> |
will yield ''"3456701234567012"''. | will yield ''"3456701234567012"''. | ||
Line 105: | Line 102: | ||
The default behavior corresponds to the following initialization: | The default behavior corresponds to the following initialization: | ||
− | < | + | <syntaxhighlight lang="C"> |
pat.pattern = ""; | pat.pattern = ""; | ||
pat.size = 1; | pat.size = 1; | ||
− | mu_stream_ioctl (str, | + | mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, &pat); |
− | + | </syntaxhighlight> | |
− | |||
− | |||
− | </ | ||
Calling the <tt>MU_IOCTL_NULLSTREAM_SET_PATTERN</tt> with a <tt>NULL</tt> | Calling the <tt>MU_IOCTL_NULLSTREAM_SET_PATTERN</tt> with a <tt>NULL</tt> | ||
Line 118: | Line 112: | ||
<tt>EOF</tt>, e.g. the following code: | <tt>EOF</tt>, e.g. the following code: | ||
− | + | <syntaxhighlight lang="C"> | |
− | < | + | mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, NULL); |
− | mu_stream_ioctl (str, | ||
− | |||
− | |||
− | |||
rc = mu_stream_read (str, buf, sizeof (buf), &n); | rc = mu_stream_read (str, buf, sizeof (buf), &n); | ||
− | </ | + | </syntaxhighlight> |
will return <tt>rc = 0</tt> and <tt>n = 0</tt>. | will return <tt>rc = 0</tt> and <tt>n = 0</tt>. | ||
Line 136: | Line 126: | ||
the following code: | the following code: | ||
− | < | + | <syntaxhighlight lang="C"> |
int class = MU_CTYPE_DIGIT|MU_CTYPE_XLETR; | int class = MU_CTYPE_DIGIT|MU_CTYPE_XLETR; | ||
− | mu_stream_ioctl (str, | + | mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATCLASS, &class); |
− | + | </syntaxhighlight> | |
− | + | ||
− | |||
− | </ | ||
initializes the read pattern to the following string: | initializes the read pattern to the following string: | ||
<tt>0123456789ABCDEFabcdef</tt> | <tt>0123456789ABCDEFabcdef</tt> | ||
Line 155: | Line 143: | ||
limits the stream size to 32 bytes: | limits the stream size to 32 bytes: | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_off_t limit = 32; | mu_off_t limit = 32; | ||
− | mu_stream_ioctl (str, | + | mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SETSIZE, &limit); |
− | + | </syntaxhighlight> | |
− | |||
− | |||
− | </ | ||
Another way to set the null stream size is via the | Another way to set the null stream size is via the | ||
Line 203: | Line 188: | ||
ader. | ader. | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_off_t | mu_off_t | ||
decoded_size (mu_stream_t mime_str, const char *encoding) | decoded_size (mu_stream_t mime_str, const char *encoding) | ||
Line 211: | Line 196: | ||
mu_stream_stat_buffer stat; /* Statistics buffer */ | mu_stream_stat_buffer stat; /* Statistics buffer */ | ||
mu_stream_t null; /* Null stream */ | mu_stream_t null; /* Null stream */ | ||
− | </ | + | </syntaxhighlight> |
First, create the filter stream for decoding the message part: | First, create the filter stream for decoding the message part: | ||
− | < | + | <syntaxhighlight lang="C"> |
− | rc = mu_filter_create (&fstr, mime_str, encoding, | + | rc = mu_filter_create (&fstr, mime_str, encoding, MU_FILTER_DECODE, MU_STREAM_READ); |
− | |||
if (rc) | if (rc) | ||
abort (); | abort (); | ||
− | </ | + | </syntaxhighlight> |
Then, create an instance of the null stream which will act | Then, create an instance of the null stream which will act | ||
as a receiver: | as a receiver: | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_nullstream_create (&null, MU_STREAM_WRITE); | mu_nullstream_create (&null, MU_STREAM_WRITE); | ||
− | </ | + | </syntaxhighlight> |
The data will be read from <tt>fstr</tt> and written to <tt>null</tt>. | The data will be read from <tt>fstr</tt> and written to <tt>null</tt>. | ||
Line 234: | Line 218: | ||
stream: | stream: | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_stream_set_stat (null, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), | mu_stream_set_stat (null, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), | ||
stat); | stat); | ||
− | </ | + | </syntaxhighlight> |
The second argument instructs the stream to keep track of the | The second argument instructs the stream to keep track of the | ||
Line 244: | Line 228: | ||
Now, copy the entire contents of <tt>fstr</tt> to <tt>null</tt>: | Now, copy the entire contents of <tt>fstr</tt> to <tt>null</tt>: | ||
− | < | + | <syntaxhighlight lang="C"> |
rc = mu_stream_copy (null, fstr, 0, NULL); | rc = mu_stream_copy (null, fstr, 0, NULL); | ||
if (rc) | if (rc) | ||
abort (); | abort (); | ||
− | </ | + | </syntaxhighlight> |
When done, destroy both streams (they are not needed any more), and | When done, destroy both streams (they are not needed any more), and | ||
Line 254: | Line 238: | ||
<tt>stat</tt>: | <tt>stat</tt>: | ||
− | < | + | <syntaxhighlight lang="C"> |
mu_stream_destroy (&null); | mu_stream_destroy (&null); | ||
mu_stream_destroy (&fstr); | mu_stream_destroy (&fstr); | ||
return stat[MU_STREAM_STAT_OUT]; | return stat[MU_STREAM_STAT_OUT]; | ||
− | </ | + | </syntaxhighlight> |
Revision as of 23:00, 14 December 2010
Null stream
A null stream is similar to the system /dev/null device. It is not connected to any particular physical storage. Any data written to such stream are irrevocably lost. Reading from such a stream returns fixed data, depending on the mode of the stream.
An instance of the null stream is created using the following function:
int mu_nullstream_create (mu_stream_t *pstr, int mode)
It creates an instance of the null stream and returns it in the memory location pointed to by pstr. The mode argument specifies the access mode for this stream. It can be a binary or of the following values:
- MU_STREAM_READ
- Stream is opened for reading.
- MU_STREAM_WRITE
- Stream is opened for writing.
The returned stream is always seekable, so the MU_STREAM_SEEK mode is implied.
Any other bits set in the mode argument are silently ignored.
Writing to an instance of null stream and seeking in such streams always succeeds. If the stream was created with the MU_STREAM_READ on, the reads from it normally behave as if it were connected to an endless source of zero bytes, i.e. each call to:
mu_stream_read (str, buf, size, &n);
results in filling buf with size zeroes. This is similar to reading from the system /dev/zero device.
nothing to do with /dev/null, or /dev/zero. We
refer to these devices only to illustrate the behavior of 'null streams.This is the default behavior when reading. It can be altered using the MU_IOCTL_NULLSTREAM ioctl.
The MU_IOCTL_NULLSTREAM ioctl
This ioctl controls various parameters of a null stream. Synopsis:
mu_stream_ioctl (stream, MU_IOCTL_NULLSTREAM, opcode, arg);
where opcode is the operation code specific to null streams and arg is the operation argument. Supported operation codes and their arguments are discussed below in this document.
MU_IOCTL_NULLSTREAM_SET_PATTERN
This ioctl sets a read pattern. The argument is a pointer to struct mu_nullstream_pattern, defined as:
struct mu_nullstream_pattern
{
char *pattern; /* Return pattern */
size_t size; /* Number of bytes in pattern */
};
The pattern member points to size bytes of data which are returned cyclically at each read. For example, suppose that str is a null stream instance, and consider the following code:
struct mu_nullstream_pattern pat;
char buf[16];
size_t n;
pat.pattern = "01234567";
pat.size = 8;
mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, &pat);
mu_stream_read (str, buf, sizeof (buf), &n);
Then, after the call to mu_stream_read with the size argument of 16, we will receive "0123456701234567".
Similarly, the following code:
mu_stream_seek (str, 3, MU_SEEK_SET, NULL);
mu_stream_read (str, buf, sizeof (buf), &n);
will yield "3456701234567012".
The default behavior corresponds to the following initialization:
pat.pattern = "";
pat.size = 1;
mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, &pat);
Calling the MU_IOCTL_NULLSTREAM_SET_PATTERN with a NULL argument causes all subsequent reads from that stream to return EOF, e.g. the following code:
mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, NULL);
rc = mu_stream_read (str, buf, sizeof (buf), &n);
will return rc = 0 and n = 0.
MU_IOCTL_NULLSTREAM_SET_PATCLASS
Set read pattern in terms of C character classes The argument is a pointer to an integer containing a bitwise OR of the desired character classes from mailutils/cctype.h. For example, the following code:
int class = MU_CTYPE_DIGIT|MU_CTYPE_XLETR;
mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATCLASS, &class);
initializes the read pattern to the following string: 0123456789ABCDEFabcdef
Two ioctls are provided to control the size of a null stream available to seek and read operations.
MU_IOCTL_NULLSTREAM_SETSIZE
Limit the addressable size of a null stream. Argument is a pointer to mu_off_t object specifying the new size. The example below limits the stream size to 32 bytes:
mu_off_t limit = 32;
mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SETSIZE, &limit);
Another way to set the null stream size is via the mu_stream_truncate function:
mu_stream_truncate (str, 32);
Setting the stream size to 0 causes all subsequent reads from that stream to return EOF. The similar effect has the MU_IOCTL_NULLSTREAM_SET_PATTERN ioctl with the NULL argument.
MU_IOCTL_NULLSTREAM_CLRSIZE
Cancel the size limitation imposed by a previous MU_IOCTL_NULLSTREAM_SETSIZE ioctl or a call to mu_stream_truncate. Argument must be NULL.
Null stream usage
Due to their nature, null streams are not among the most used stream flavors. They are mainly useful for testing or measuring purposes.
The mhn utility from GNU Mailutils MH suite gives a nice example of using a null stream instance to compute the actual (decoded) size of a part of a MIME message. In the example below we present a simplified version of this code. It defines the function decoded_size:
mu_off_t decoded_size (mu_stream_t mime_str, const char *encoding)
This function return the size of the decoded input strem. Arguments are:
- mime_str
- A stream obtained from the MIME part.
- encoding
- Encoding type, as obtained from the Content-Transfer-Encoding MIME he
ader.
mu_off_t
decoded_size (mu_stream_t mime_str, const char *encoding)
{
int rc; /* Result code */
mu_stream_t fstr /* Filter stream */
mu_stream_stat_buffer stat; /* Statistics buffer */
mu_stream_t null; /* Null stream */
First, create the filter stream for decoding the message part:
rc = mu_filter_create (&fstr, mime_str, encoding, MU_FILTER_DECODE, MU_STREAM_READ);
if (rc)
abort ();
Then, create an instance of the null stream which will act as a receiver:
mu_nullstream_create (&null, MU_STREAM_WRITE);
The data will be read from fstr and written to null. Number of bytes written will give the decoded size of the message. To get this number, attach the statistics buffer to the null stream:
mu_stream_set_stat (null, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
stat);
The second argument instructs the stream to keep track of the bytes output (i.e. written) to the stream.
Now, copy the entire contents of fstr to null:
rc = mu_stream_copy (null, fstr, 0, NULL);
if (rc)
abort ();
When done, destroy both streams (they are not needed any more), and return the value of the MU_STREAM_STAT_OUTth element from stat:
mu_stream_destroy (&null);
mu_stream_destroy (&fstr);
return stat[MU_STREAM_STAT_OUT];