nullstream.texi
8.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
@c This is part of the GNU Mailutils manual.
@c Copyright (C) 2010-2012 Free Software Foundation, Inc.
@c See file mailutils.texi for copying conditions.
@c *******************************************************************
@section Null stream
@cindex null stream
@cindex stream, null
A @dfn{null stream} is similar to the system @file{/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:
@deffn {stream function} int mu_nullstream_create (mu_stream_t *pstr, int mode)
Create an instance of the null stream and return it in the memory
location pointed to by @var{pstr}. The @var{mode} argument specifies
the access mode for this stream. It can be a binary @samp{or} of the
following values:
@table @code
@item MU_STREAM_READ
Stream is opened for reading.
@item MU_STREAM_WRITE
Stream is opened for writing.
@end table
The returned stream is always seekable, so the @code{MU_STREAM_SEEK}
mode is implied.
Any other bits set in the @var{mode} argument are silently ignored.
@end deffn
Writing to an instance of null stream and seeking in such streams
always succeeds. If the stream was created with the
@code{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:
@smallexample
mu_stream_read (str, buf, size, &n);
@end smallexample
@noindent
results in filling @var{buf} with @var{size} zeroes. This is similar
to reading from the system @file{/dev/zero} device@footnote{Note that
the internal implementation of @dfn{null streams} has nothing to do
with @file{/dev/null}, or @file{/dev/zero}. We refer to these devices
only to illustrate the behavior of @dfn{null streams}.}.
This is the default behavior when reading. It can be altered using
the @samp{MU_IOCTL_NULLSTREAM} ioctl.
@defvr {ioctl} MU_IOCTL_NULLSTREAM
This ioctl controls various parameters of a null stream. Synopsis:
@example
mu_stream_ioctl (@var{stream}, MU_IOCTL_NULLSTREAM, @var{opcode}, @var{arg});
@end example
@noindent
where @var{opcode} is the operation code specific to null streams and
@var{arg} is the operation argument. Supported operation codes and
their arguments are discussed below in this document.
@end defvr
@defvr {ioctl opcode} MU_IOCTL_NULLSTREAM_SET_PATTERN
Set the @dfn{pattern} for reads. The argument is a pointer to
@dfn{struct mu_nullstream_pattern}, defined as:
@smallexample
@group
struct mu_nullstream_pattern
@{
char *pattern; /* Return pattern */
size_t size; /* Number of bytes in pattern */
@};
@end group
@end smallexample
The @samp{pattern} member points to @samp{size} bytes of data which
are returned cyclically at each read. For example, suppose that
@var{str} is a null stream instance, and consider the following code:
@smallexample
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);
@end smallexample
Then, after the call to @code{mu_stream_read}, we will have:
@smallexample
@group
n @result{} 16
buf @result{} "0123456701234567"
@end group
@end smallexample
Similarly, the following code:
@smallexample
mu_stream_seek (str, 3, MU_SEEK_SET, NULL);
mu_stream_read (str, buf, sizeof (buf), &n);
@end smallexample
@noindent
will yield:
@smallexample
@group
n @result{} 16
buf @result{} "3456701234567012"
@end group
@end smallexample
The default behavior corresponds to the following initialization:
@smallexample
@group
pat.pattern = "";
pat.size = 1;
mu_stream_ioctl (str,
MU_IOCTL_NULLSTREAM,
MU_IOCTL_NULLSTREAM_SET_PATTERN,
&pat);
@end group
@end smallexample
Calling the @samp{MU_IOCTL_NULLSTREAM_SET_PATTERN} with a @samp{NULL}
argument causes all subsequent reads from that stream to return @samp{EOF}:
@smallexample
@group
mu_stream_ioctl (str,
MU_IOCTL_NULLSTREAM,
MU_IOCTL_NULLSTREAM_SET_PATTERN,
NULL);
@dots{}
rc = mu_stream_read (str, buf, sizeof (buf), &n);
rc @result{} 0
n @result{} 0
@end group
@end smallexample
@end defvr
@defvr {ioctl opcode} MU_IOCTL_NULLSTREAM_SET_PATCLASS
Set read pattern in terms of @dfn{C character classes}
(@FIXME-pxref{C character classes}). Argument is a pointer
to an integer containing a bitwise @samp{OR} of the desired
character classes from @file{mailutils/cctype.h}. For example,
the following code:
@smallexample
int class = MU_CTYPE_DIGIT|MU_CTYPE_XLETR;
mu_stream_ioctl (str,
MU_IOCTL_NULLSTREAM,
MU_IOCTL_NULLSTREAM_SET_PATCLASS,
&class);
@end smallexample
@noindent
initializes the read pattern to the following string:
@smallexample
0123456789ABCDEFabcdef
@end smallexample
@end defvr
Two ioctls are provided to control the @dfn{size} of a null stream
available to seek and read operations.
@defvr {ioctl opcode} MU_IOCTL_NULLSTREAM_SETSIZE
Limit the addressable size of a null stream. Argument is a pointer
to @samp{mu_off_t} object specifying the new size. The example below
limits the stream size to 32 bytes:
@smallexample
@group
mu_off_t limit = 32;
mu_stream_ioctl (str,
MU_IOCTL_NULLSTREAM,
MU_IOCTL_NULLSTREAM_SETSIZE,
&limit);
@end group
@end smallexample
@end defvr
Another way to set the null stream size is via the
@samp{mu_stream_truncate} function:
@smallexample
mu_stream_truncate (str, 32);
@end smallexample
Setting the stream size to @samp{0} causes all subsequent reads from
that stream to return @samp{EOF}. The similar effect has the
@samp{MU_IOCTL_NULLSTREAM_SET_PATTERN} ioctl with the @samp{NULL} argument.
@defvr {ioctl opcode} MU_IOCTL_NULLSTREAM_CLRSIZE
Cancel the size limitation imposed by a previous
@samp{MU_IOCTL_NULLSTREAM_SETSIZE} ioctl or a call to
@samp{mu_stream_truncate}. Argument must be @samp{NULL}.
@end defvr
@menu
* null stream usage::
@end menu
@node null stream usage
@subsection 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 @command{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 @samp{decoded_size}:
@deffn {example function} mu_off_t decoded_size (mu_stream_t mime_str, @
const char *encoding)
Return the size of the decoded input strem. Arguments are:
@table @var
@item mime_str
A stream obtained from the MIME part.
@item encoding
Encoding type, as obtained from the @samp{Content-Transfer-Encoding}
MIME header.
@end table
@example
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 */
@end example
First, create the filter stream for decoding the message part:
@example
rc = mu_filter_create (&fstr, mime_str, encoding,
MU_FILTER_DECODE, MU_STREAM_READ);
if (rc)
abort ();
@end example
Then, create an instance of the null stream which will act
as a receiver:
@example
mu_nullstream_create (&null, MU_STREAM_WRITE);
@end example
The data will be read from @var{fstr} and written to @var{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:
@example
mu_stream_set_stat (null, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT),
stat);
@end example
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 @var{fstr} to @var{null}:
@example
rc = mu_stream_copy (null, fstr, 0, NULL);
if (rc)
abort ();
@end example
When done, destroy both streams (they are not needed any more), and
return the value of @samp{MU_STREAM_STAT_OUT} element from @var{stat}:
@example
mu_stream_destroy (&null);
mu_stream_destroy (&fstr);
return stat[MU_STREAM_STAT_OUT];
@}
@end example