Null stream

From Mailutils

Revision as of 23:00, 14 December 2010 by Gray (Talk | contribs)
Jump to: navigation, search


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:

Stream is opened for reading.
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.


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.


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

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:

  rc = mu_stream_read (str, buf, sizeof (buf), &n);

will return rc = 0 and n = 0.


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:


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.


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.


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:

A stream obtained from the MIME part.
Encoding type, as obtained from the Content-Transfer-Encoding MIME he


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),

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