Difference between revisions of "Null stream"

From Mailutils
Jump to navigationJump to search
(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:
  
<source lang="C">
+
<syntaxhighlight lang="C">
 
int mu_nullstream_create (mu_stream_t *pstr, int mode)
 
int mu_nullstream_create (mu_stream_t *pstr, int mode)
</source>
+
</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:
  
<source lang="C">
+
<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 */
 
};
 
};
</source>
+
</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:
  
<source lang="C">
+
<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_IOCTL_NULLSTREAM,
 
                  MU_IOCTL_NULLSTREAM_SET_PATTERN,
 
                  &pat);
 
  
 
   mu_stream_read (str, buf, sizeof (buf), &n);
 
   mu_stream_read (str, buf, sizeof (buf), &n);
</source>
+
</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:
  
<source lang="C">
+
<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);
</source>
+
</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:
  
<source lang="C">
+
<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);
                  MU_IOCTL_NULLSTREAM,
+
</syntaxhighlight>
                  MU_IOCTL_NULLSTREAM_SET_PATTERN,
 
                  &pat);
 
</source>
 
  
 
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">
<source lang="C">
+
   mu_stream_ioctl (str, MU_IOCTL_NULLSTREAM, MU_IOCTL_NULLSTREAM_SET_PATTERN, NULL);
   mu_stream_ioctl (str,
 
                  MU_IOCTL_NULLSTREAM,
 
                  MU_IOCTL_NULLSTREAM_SET_PATTERN,
 
                  NULL);
 
 
   rc = mu_stream_read (str, buf, sizeof (buf), &n);
 
   rc = mu_stream_read (str, buf, sizeof (buf), &n);
</source>
+
</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:
  
<source lang="C">
+
<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);
                  MU_IOCTL_NULLSTREAM,
+
</syntaxhighlight>
                  MU_IOCTL_NULLSTREAM_SET_PATCLASS,
+
 
                  &class);
 
</source>
 
 
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:
  
<source lang="C">
+
<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);
                  MU_IOCTL_NULLSTREAM,
+
</syntaxhighlight>
                  MU_IOCTL_NULLSTREAM_SETSIZE,
 
                  &limit);
 
</source>
 
  
 
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.
  
<source lang="C">
+
<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 */
</source>
+
</syntaxhighlight>
  
 
First, create the filter stream for decoding the message part:
 
First, create the filter stream for decoding the message part:
  
<source lang="C">
+
<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);
                        MU_FILTER_DECODE, MU_STREAM_READ);
 
 
   if (rc)
 
   if (rc)
 
     abort ();
 
     abort ();
</source>
+
</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:
  
<source lang="C">
+
<syntaxhighlight lang="C">
 
   mu_nullstream_create (&null, MU_STREAM_WRITE);
 
   mu_nullstream_create (&null, MU_STREAM_WRITE);
</source>
+
</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:
  
<source lang="C">
+
<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);
</source>
+
</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>:
  
<source lang="C">
+
<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 ();
</source>
+
</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>:
  
<source lang="C">
+
<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];
</source>
+
</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.

Note: Note that the internal implementation of null streams has

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];