summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/libsm/io.html
blob: 5bb7c32dbc1f8e718d679beb6b9a3c7d078fdb35 (plain)
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
<html>
<head>
<title>libsm sm_io general overview</title>
</head>
<body>
<a href="index.html">Back to libsm overview</a>
<center>
<h1>libsm sm_io general overview</h1>
<br> $Id: io.html,v 1.3 2001/03/17 03:22:50 gshapiro Exp $
</center>
<h2> Introduction </h2>
<p>
The <i>sm_io</i> portion of the <i>libsm</i> library is similar to
the <i>stdio</i> library. It is derived from the Chris Torek version
of the <i>stdio</i> library (BSD). There are some key differences
described below between <i>sm_io</i> and <i>stdio</i> but many
similarities will be noticed.
</p>
<p>
A key difference between <i>stdio</i> and <i>sm_io</i> is that the
functional code that does the open, close, read, write, etc. on a file
can be different for different files. For example, with <i>stdio</i>
the functional code (read, write) is either the default supplied in the
library or a "programmer specified" set of functions set via
<i>sm_io_open()</i>. Whichever set of functions are specified <b>all</b>
open's, read's, write's, etc use the same set of functions. In contrast, with
<i>sm_io</i> a different set of functions can be specified with each
active file for read's, write's, etc. These different function sets
are identified as <b>file types</b> (see <tt>sm_io_open()</tt>). Each function
set can handle the actions directly, pass the action request to
another function set or do some work before passing it on to another function
set. The setting of a function set for a file type can be done for
a file type at any time (even after the type is open).
</p>
<p>
A second difference is the use of <a href="rpool.html"><b>rpools</b></a>.
An <b>rpool</b> is specified with the opening of a file
(<tt>sm_io_open()</tt>).
This allows of a file to be associated with an rpool so that when the
rpool is released the open file will be closed; the <tt>sm_io_open()</tt>
registers that <tt>sm_io_close()</tt> should be called when the rpool is
released.
</p>
<p>
A third difference is that the I/O functions take a <i>timeout</i>
argument. This allows the setting of a maximum amount of time allowable
for the I/O to be completed. This means the calling program does not need
to setup it's own timeout mechanism. NOTE: SIGALRM's should not be
active in the calling program when an I/O function with a <i>timeout</i>
is used.
</p>
<p>
When converting source code from <i>stdio</i> to <i>sm_io</i> be
very careful to NOTE: the arguments to functions have been rationalized.
That is, unlike <i>stdio</i>, all <i>sm_io</i> functions that
take a file pointer (SM_FILE_T *) argument have the file pointer
as the first argument. Also not all functions with <i>stdio</i> have
an identical matching <i>sm_io</i> API: the API list has been thinned
since a number of <i>stdio</i> API's overlapped in functionality.
Remember many functions also have a <i>timeout</i> argument added.
</p>
<p>
When a file is going to be opened, the file type is included with
<tt>sm_io_open()</tt>.
A file type is either one automatically included with the <i>sm_io</i>
library or one created by the program at runtime.
File types can be either buffered or unbuffered. When buffered the buffering
is either the builtin <i>sm_io</i> buffering or as done by the file type.
File types can be disk files, strings, TCP/IP connections or whatever
your imagination can come up with that can be read and/or written to.
</p>
<p>
Information about a particular file type or pointer can be obtained or set with
the <i>sm_io</i> "info" functions.
The <tt>sm_io_setinfo()</tt> and <tt>sm_io_getinfo()</tt> functions work on
an active file pointer.
</p>
<h2>Include files</h2>
<p>
There is one main include file for use with sm_io: <i>io.h</i>. Since the
use of <b>rpools</b> is specified with <tt>sm_io_open()</tt> an
<b>rpool</b> may
be created and thus <i>rpool.h</i> may need to be included as well
(before io.h).
</p>
<pre>
#include &lt;rpool.h&gt;
#include &lt;io.h&gt;
</pre>

<h2>Functions/API's</h2>
<p>
Below is a list of the functions for <i>sm_io</i> listed in
alphabetical order. Currently these functions return error codes
and set errno when appropriate. These (may?/will?) change to
raising exceptions later.
</p>
<pre>
<a href="#sm_io_autoflush">SM_FILE_T *sm_io_autoflush(SM_FILE_T *fp, SM_FILE_T *)</a>

<a href="#sm_io_automode">void sm_io_automode(SM_FILE_T *fp, SM_FILE_T *)</a>

<a href="#defaultapi">void sm_io_clearerr(SM_FILE_T *fp)</a>

<a href="#sm_io_close">int sm_io_close(SM_FILE_T *fp, int timeout)</a>

<a href="#defaultapi">int sm_io_dup(SM_FILE_T *fp)</a>

<a href="#defaultapi">int sm_io_eof(SM_FILE_T *fp)</a>

<a href="#defaultapi">int sm_io_error(SM_FILE_T *fp)</a>

<a href="#defaultapi">char * sm_io_fgets(SM_FILE_T *fp, int timeout, char *buf, int n)</a>

<a href="#defaultapi">int sm_io_flush(SM_FILE_T *fp, int timeout)</a>

<a href="#sm_io_fopen">int sm_io_fopen(char *pathname, int flags [, MODE_T mode])</a>

<a href="#defaultapi">int sm_io_fprintf(SM_FILE_T *fp, int timeout, const char *fmt, ...)</a>

<a href="#defaultapi">int sm_io_fputs(s, int, SM_FILE_T *fp)</a>

<a href="#defaultapi">int sm_io_fscanf(SM_FILE_T *fp, int timeout, char const *fmt, ...) </a>

<a href="#defaultapi">int sm_io_getc(SM_FILE_T *fp, int timeout)</a>

<a href="#sm_io_getinfo">void sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)</a>

<a href="#sm_io_open">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>

<a href="#defaultapi">int sm_io_purge(SM_FILE_T *fp)</a>

<a href="#defaultapi">int sm_io_putc(SM_FILE_T *fp, int timeout, int c)</a>

<a href="#defaultapi">size_t sm_io_read(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>

<a href="#sm_io_reopen">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>

<a href="#defaultapi">void sm_io_rewind(SM_FILE_T *fp, int timeout)</a>

<a href="#defaultapi">int sm_io_seek(SM_FILE_T *fp, off_t offset, int timeout, int whence)</a>

<a href="#sm_io_setinfo">void sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)</a>

<a href="#defaultapi">int sm_io_setvbuf(SM_FILE_T *fp, int timeout, char *buf, int mode, size_t size)</a>

<a href="#defaultapi">int sm_io_sscanf(const char *str, char const *fmt, ...)</a>

<a href="#defaultapi">long sm_io_tell(SM_FILE_T *fp, int timeout)</a>

<a href="#defaultapi">int sm_io_ungetc(SM_FILE_T *fp, int timeout, int c)</a>

<a href="#defaultapi">size_t sm_io_write(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>

<a href="#defaultapi">int sm_snprintf(char *str, size_t n, char const *fmt, ...)</a>

</pre>
<a name="timeouts">
<h2>Timeouts</h2>
<p>
For many of the functions a <i>timeout</i> argument is given. This limits
the amount of time allowed for the function to complete. There are three
pre-defined values:
<menu>
<li>
SM_TIME_DEFAULT - timeout using the default setting for this file type
</li>
<li>
SM_TIME_FOREVER - timeout will take forever; blocks until task completed
</li>
<li>
SM_TIME_IMMEDIATE - timeout (virtually) now
</li>
</menu>
</p>
<p>
A function caller can also specify a positive integer value in milliseconds.
A function will return with <i>errno</i> set to EINVAL if a bad value
is given for <i>timeout</i>.
When a function times out the function returns in error with <i>errno</i>
set to <b>EAGAIN</b>. In the future this may change to an exception being
thrown.
</p>
<h2>Function Descriptions</h2>
<dl>
<!-- SM_IO_FOPEN -->
<p></p>
<dt><tt><a name="sm_io_fopen">
SM_FILE_T *
<br>
sm_io_fopen(char *pathname, int flags)
<br>
SM_FILE_T *
<br>
sm_io_fopen(char *pathname, int flags, MODE_T mode)
</a></tt></dt>
<dd>
Open the file named by <tt>pathname</tt>, and associate a stream with it.
The arguments are the same as for the <tt>open(2)</tt> system call.
<br>
If memory could not be allocated, an exception is raised.
If successful, an <tt>SM_FILE_T</tt> pointer is returned.
Otherwise, <tt>NULL</tt> is returned and <tt>errno</tt> is set.
<!-- SM_IO_OPEN -->
<p></p>
<dt><tt><a name="sm_io_open">
SM_FILE_T *
<br>
sm_io_open(const SM_FILE_T *type, int timeout, const void *info, int flags, void *rpool)
</a></tt></dt>
<dd>
Opens a file by <i>type</i> directed by <i>info</i>. <i>Type</i> is a filled-in
SM_FILE_T structure from the following builtin list
(<a href="#builtins"><b>descriptions below</b></a>)
or one specified by the program. 
<menu>
<li>
SmFtString
</li>
<li>
SmFtStdio
</li>
<li>
SmFtStdiofd
</li>
<li>
smioin <b>*</b>
</li>
<li>
smioout <b>*</b>
</li>
<li>
smioerr <b>*</b>
</li>
<li>
smiostdin <b>*</b>
</li>
<li>
smiostdout <b>*</b>
</li>
<li>
smiostderr <b>*</b>
</li>
<li>
SmFtSyslog
</li>
</menu>
<br>
The above list of file types are already appropriately filled in. Those marked
with a "<b>*</b>" are already open and may be used directly and immediately.
For program specified types, to set the <i>type</i> argument easily and with minimal error the macro
<b>SM_IO_SET_TYPE</b> should be used. The SM_FILE_T structure is fairly
large, but only a small portion of it need to be initialized for a new
type.
See also <a href="#writefunctions">"Writing Functions for a File Type"</a>.
<menu>
<pre>
SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
</pre>
</menu>
<br>
<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
section.
<br>
<i>Info</i> is information that describes for the file type what is
to be opened and any associated information.
For a disk file this would be a file path; with a TCP
connection this could be an a structure containing an IP address and port.
<br><i>Flags</i> is a
set of sm_io flags that describes how the file is to be interacted with:
<menu>
<li>
SM_IO_RDWR	- read and write
</li>
<li>
SM_IO_RDONLY	- read only
</li>
<li>
SM_IO_WRONLY	- write only
</li>
<li>
SM_IO_APPEND	- allow write to EOF only
</li>
<li>
SM_IO_APPENDRW	- allow read-write from EOF only
</li>
<li>
SM_IO_RDWRTR	- read and write with truncation of file first
</li>
</menu>
<i>Rpool</i> is the address of the rpool that this open is to be associated
with. When the rpool is released then the close function for this
file type will be automatically called to close the file for cleanup.
If NULL is specified for <i>rpool</i> then the close function is not
associated (attached) to an rpool.
<br>
On cannot allocate memory, an exception is raised.
If the <i>type</i> is invalid, <tt>sm_io_open</tt> will abort the process.
On success an SM_FILE_T * pointer is returned.
On failure the NULL pointer is returned and errno is set.
</dd>
<!-- SM_IO_SETINFO -->
<p></p>
<dt><tt><a name="sm_io_setinfo">
int
<br>
sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)
</a></tt></dt>
<dd>
For the open file <i>sfp</i> set the indicated information (<i>what</i>)
to the new value <i>(valp</i>).
This will make the change for this SM_FILE_T only. The file
type that <i>sfp</i> originally belonged to will still be
configured the same way (this is to prevent side-effect
to other open's of the same file type, particularly with threads).
The value of <i>what</i> will be file-type dependant since this function
is one of the per file type setable functions.
One value for <i>what</i> that is valid for all file types is
SM_WHAT_VECTORS. This sets the currently open file with a new function
vector set for open, close, etc. The new values are taken from <i>valp</i>
a SM_FILE_T filled in by the used via the macro SM_IO_SET_TYPE
(see and <a href="#writefunctions">
"Writing Functions for a File Type"</a> for more information).
<br>
On success 0 (zero) is returned. On failure -1 is returned and errno is set.
</dd>
<!-- SM_IO_GETINFO -->
<p></p>
<dt><tt><a name="sm_io_getinfo">
int
<br>
sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)
</a></tt></dt>
<dd>
For the open file <i>sfp</i> get the indicated information (<i>what</i>)
and place the result in <i>(valp</i>).
This will obtain information for SM_FILE_T only and may be different than
the information for the file type it was originally opened as.
The value of <i>what</i> will be file type dependant since this function
is one of the per file type setable functions.
One value for <i>what</i> that is valid for all file types is
SM_WHAT_VECTORS. This gets from the currently open file a copy of
the function vectors and stores them in <i>valp</i> a SM_FILE_T
(see <a href="#writefunctions">
"Writing Functions for a File Type"</a> for more information).
<br>
On success 0 (zero) is returned. On failure -1 is returned and errno is set.
</dd>
<!-- SM_IO_AUTOFLUSH -->
<p></p>
<dt><tt><a name="sm_io_autoflush">
void
<br>
sm_io_autoflush(SM_FILE_T *fp1, *SM_FILE_T fp2)
</a></tt></dt>
<dd>
Associate a read of <i>fp1</i> with a data flush for <i>fp2</i>. If a read
of <i>fp1</i> discovers that there is no data available to be read, then
<i>fp2</i> will have it's data buffer flushed for writable data. It is
assumed that <i>fp1</i> is open for reading and <i>fp2</i> is open
for writing.
<br>
On return the old file pointer associated with <i>fp1</i> for flushing
is returned. A return of NULL is no an error; this merely indicates no
previous association.
</dd>
<!-- SM_IO_AUTOMODE -->
<p></p>
<dt><tt><a name="sm_io_automode">
void
<br>
sm_io_automode(SM_FILE_T *fp1, *SM_FILE_T fp2)
<dt><tt><a name="sm_io_automode">
</a></tt></dt>
<dd>
Associate the two file pointers for blocking/non-blocking mode changes.
In the handling of timeouts <i>sm_io</i> may need to switch the mode of
a file between blocking and non-blocking. If the underlying file descriptor
has been duplicated with <tt>dup(2)</tt> and these descriptors are used
by <i>sm_io</i> (for example with an SmFtStdiofd file type), then this API
should be called to associate them. Otherwise odd behavior (i.e. errors)
may result that is not consistently reproducable nor easily identifiable.
</dd>
<!-- SM_IO_CLOSE -->
<p></p>
<dt><tt><a name="sm_io_close">
int
<br>
sm_io_close(SM_FILE_T *sfp, int timeout)
</a></tt></dt>
<dd>
Release all resources (file handles, memory, etc.) associated with
the open SM_FILE_T <i>sfp</i>. If buffering is active then the
buffer is flushed before any resources are released.
<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
section.
The first resources released after buffer flushing will be the
buffer itself. Then the <b>close</b> function specified in the
file type at open will be called. It is the responsibility
of the <b>close</b> function to release any file type
specific resources allocated and to call <tt>sm_io_close()</tt>
for the next file type layer(s) that the current file type uses (if any).
<br>
On success 0 (zero) is returned. On failure SM_IO_EOF is returned and
errno is set.
</dd>
</dl>
<h2>
<a name="builtins">Description of Builtin File Types</a>
</h2>
<p>
There are several builtin file types as mentioned in <tt>sm_io_open()</tt>.
More file types may be added later.
</p>
<dl>
<p></p>
<dt><tt>SmFtString</tt></dt>
<dd>
Operates on a character string. <i>SmFtString</i> is a file type only.
The string starts at the location 0 (zero)
and ends at the last character. A read will obtain the requested
number of characters if available; else as many as possible. A read
will not terminate the read characters with a NULL ('\0'). A write
will place the number of requested characters at the current location.
To append to a string either the pointer must currently be at the end
of the string or a seek done to position the pointer. The file type
handles the space needed for the string. Thus space needed for the
string will be grown automagically without the user worrying about
space management.
</dd>
<dt><tt>SmFtStdio</tt></dt>
<dd>
A predefined SM_FILE_T structure with function vectors pointing to
functions that result in the file-type behaving as the system stdio
normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
is the path of the file to be opened. Note that this file type
does not interact with the system's stdio. Thus a program mixing system
stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
and output.
</dd>
<dt><tt>SmFtStdiofd</tt></dt>
<dd>
A predefined SM_FILE_T structure with function vectors pointing to
functions that result in the file-type behaving as the system stdio
normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
is a file descriptor (the value returned by open(2)).  Note that this file type
does not interact with the system's stdio. Thus a program mixing system
stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
and output.
</dd>
<dt><tt>smioin</tt></dt>
<dt><tt>smioout</tt></dt>
<dt><tt>smioerr</tt></dt>
<dd>
The three types <i>smioin</i>, <i>smioout</i> and <i>smioerr</i> are grouped
together. These three types
perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
and <i>stderr</i>.  These types are both the names and the file pointers.
They are already open when a program starts (unless the parent explictly
closed file descriptors 0, 1 and 2).
Thus <tt>sm_io_open()</tt> should never be called for these types:
the named file pointers should be used directly.
<i>Smioin</i> and <i>smioout</i> are buffered
by default. <i>Smioerr</i> is not buffered by default. Calls to <b>stdio</b>
are safe to make when using these three<b>sm_io</b> file pointers.
There is no interaction between <b>sm_io</b> and <b>stdio</b>. Hence,
due to buffering, the sequence of input and output data from both <b>sm_io</b>
and <b>stdio</b> at the same time may appear unordered. For
coordination between <b>sm_io</b> and <b>stdio</b> use the three
file pointers below (<i>smiostdin, smiostdout, smiostderr</i>).
</dd>
<dt><tt>smiostdin</tt></dt>
<dt><tt>smiostdout</tt></dt>
<dt><tt>smiostderr</tt></dt>
<dd>
The three types <i>smiostdin</i>, <i>smioostdut</i> and <i>smiostderr</i>
are grouped together. These three types
perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
and <i>stderr</i>.  These types are both the names and file pointers.
They are already open when a program starts (unless the parent explictly
close file descriptors 0, 1 and 2).
Thus <tt>sm_io_open()</tt> should
never be called: the named file pointers should be used directly.
Calls to <b>stdio</b> are safe to make when using these three<b>sm_io</b>
file pointers though no code is shared between the two libaries.
However, the input and output between <i>sm_io</i> and <i>stdio</i> is
coordinated for these three file pointers: <i>smiostdin</i>,
<i>smiostdout</i> and <i>smiostderr</i> are layered on-top-of
the system's <i>stdio</i>.
<i>Smiostdin</i>, <i>smiostdout</i>
and <i>Smiostderr</i> are not buffered by default.
Hence, due to buffering in <i>stdio</i> only, the sequence of input and
output data from both <b>sm_io</b> and <b>stdio</b> at the same time will
appear ordered. If <i>sm_io</i> buffering is turned on then the
input and output can appear unordered or lost.
</dd>
<dt><tt>SmFtSyslog</tt></dt>
<dd>
This opens the channel to the system log. Reads are not allowed. Writes
cannot be undone once they have left the <i>sm_io</i> buffer.
The man pages for <tt>syslog(3)</tt> should be read for information
on syslog.
</dd>
</dl>
<p></p>
<hr>
<p></p>
<h2>
<a name="writefunctions">
Writing Functions for a File Type
</a>
</h2>
<p>
When writing functions to create a file type a function needs to
be created for each function vector in the SM_FILE_T structure
that will be passed to <tt>sm_io_open()</tt> or <tt>sm_io_setinfo()</tt>.
Otherwise the setting will be rejected and <i>errno</i> set to EINVAL.
Each function should accept and handle the number and types of arguments as
described in the portion of the SM_FILE_T structure shown below:
</p>
<pre>
        int      (*open) __P((SM_FILE_T *fp, const void *, int flags,
                              const void *rpool));
        int      (*close) __P((SM_FILE_T *fp));
        int      (*read)  __P((SM_FILE_T *fp, char *buf, size_t size));
        int      (*write) __P((SM_FILE_T *fp, const char *buf, size_t size));
        off_t    (*seek)  __P((SM_FILE_T *fp, off_t offset, int whence));
        int      (*getinfo) __P((SM_FILE_T *fp, int what, void *valp));
        int      (*setinfo) __P((SM_FILE_T *fp, int what, void *valp));
</pre>
<p>
The macro SM_IO_SET_TYPE should be used to initialized an SM_FILE_T as a file
type for an <tt>sm_io_open()</tt>:
<menu>
<pre>
SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
</pre>
<br>
where:
<menu>
<li>
type	- is the SM_FILE_T being filled-in
</li>
<li>
name	- a human readable character string for human identification purposes
</li>
<li>
open	- the vector to the open function
</li>
<li>
close	- the vector to the close function
</li>
<li>
read	- the vector to the read function
</li>
<li>
write	- the vector to the write function
</li>
<li>
seek	- the vector to the seek function
</li>
<li>
set	- the vector to the set function
</li>
<li>
get	- the vector to the get function
</li>
<li>
timeout	- the default to be used for a timeout when SM_TIME_DEFAULT specified
</li>
</menu>
</menu>
You should avoid trying to change or use the other structure members of the
SM_FILE_T. The file pointer content (internal structure members) of an active
file should only be set and observed with the "info" functions.
The two exceptions to the above statement are the structure members
<i>cookie</i> and <i>ival</i>. <i>Cookie</i> is of type <tt>void *</tt>
while <i>ival</i> is of type <tt>int</tt>. These two structure members exist
specificly for your created file type to use. The <i>sm_io</i> functions
will not change or set these two structure members; only specific file type
will change or set these variables.
</p>
<p>
For maintaining information privately about status for a file type the
information should be encapsulated in a <i>cookie</i>. A <i>cookie</i>
is an opaque type that contains information that is only known to
the file type layer itself. The <i>sm_io</i> package will know
nothing about the contents of the <i>cookie</i>; <i>sm_io</i> only
maintains the location of the <i>cookie</i> so that it may be passed
to the functions of a file type. It is up to the file type to
determine what to do with the <i>cookie</i>. It is the responsibility
of the file type's open to create the cookie and point the SM_FILE_T's
<i>cookie</i> at the address of the cookie.
It is the responsibility of close to clean up
any resources that the cookie and instance of the file type have used.
</p>
<p>
For the <i>cookie</i> to be passed to all members of a function type
cleanly the location of the cookie must assigned during
the call to open. The file type functions should not attempt to
maintain the <i>cookie</i> internally since the file type may have
serveral instances (file pointers).
</p>
<p>
The SM_FILE_T's member <i>ival</i> may be used in a manner similar to
<i>cookie</i>. It is not to be used for maintaining the file's offset
or access status (other members do that). It is intended as a "light"
reference.
</p>
<p>
The file type vector functions are called by the <tt>sm_io_*()</tt>
functions after <i>sm_io</i> processing has occurred. The <i>sm_io</i>
processing validates SM_FILE_T's and may then handle the call entirely
itself or pass the request to the file type vector functions.
</p>
<p>
All of the "int" functions should return -1 (minus one) on failure
and 0 (zero) or greater on success. <i>Errno</i> should be set to
provide diagnostic information to the caller if it has not already
been set by another function the file type function used.
</p>
<p>
Examples are a wonderful manner of clarifying details. Below is an example
of an open function.
</p>
<p>
This shows the setup.
<menu>
<pre>
SM_FILE_T *fp;
SM_FILE_T SM_IO_SET_TYPE(vector, "my_type", myopen, myclose, myread, mywrite,
				myseek, myget, myset, SM_TIME_FOREVER);

fp = sm_io_open(&vector, 1000, "data", SM_IO_RDONLY, NULL);

if (fp == NULL)
	return(-1);
</pre>
The above code open's a file of type "my_type". The <i>info</i> is set
to a string "data". "data" may be the name of a file or have some special
meaning to the file type. For sake of the example, we will have it be
the name of a file in the home directory of the user running the program.
Now the only file type function that is dependent on this information
will be the open function.
<br>
We have also specified read-only access (SM_IO_RDONLY) and that no <i>rpool</i>
will be used. The <i>timeout</i> has been set to 1000 milliseconds which
directs that the file and all associated setup should be done within
1000 milliseconds or return that the function erred (with errno==EAGAIN).
<pre>
int myopen(fp, info, flags, rpools)
	SM_FILE_T *fp;
        const void *info; 
        int flags;
        void *rpool;
{
	/*
	**  now we could do the open raw (i.e with read(2)), but we will
	**  use file layering instead. We will use the <i>stdio</i> file
	**  type (different than the system's stdio).
	*/
	struct passwd *pw;
	char path[PATH_MAX];

	pw = getpwuid(getuid());
	sm_io_snprintf(path, PATH_MAX, "%s/%s", pw->pw_dir, info);

	/*
	**  Okay. Now the path pass-in has been prefixed with the
	**  user's HOME directory. We'll call the regular stdio (SmFtStdio)
	**  now to handle the rest of the open.
	*/
	fp->cookie = sm_io_open(SmFtStdio, path, flags, rpools);
	if (fp->cookie == NULL)
		return(-1) /* errno set by sm_io_open call */
	else
		return(0);
}
</pre>
Later on when a write is performed the function <tt>mywrite</tt> will
be invoked. To match the above <tt>myopen</tt>, <tt>mywrite</tt> could
be written as:
<pre>
int mywrite(fp, buf, size)
	SM_FILE_T *fp;
        char *buf;
        size_t size;
{
	/*
	**  As an example, we can change, modify, refuse, filter, etc.
	**  the content being passed through before we ask the SmFtStdio
	**  to do the actual write.
	**  This example is very simple and contrived, but this keeps it
	**  clear.
	*/
	if (size == 0)
		return(0); /* why waste the cycles? */
	if (*buf == 'X')
		*buf = 'Y';

	/*
	**  Note that the file pointer passed to the next level is the
	**  one that was stored in the cookie during the open.
	*/
	return(sm_io_write(fp->cookie, buf, size));
}
</pre>
As a thought-exercise for the fair reader: how would you modify the
above two functions to make a "tee". That is the program will call
<tt>sm_io_open</tt> or <tt>sm_io_write</tt> and two or more files will
be opened and written to. (Hint: create a cookie to hold two or more
file pointers).
</menu>
</p>
<p></p>
<hr>
<br>
<hr>
<p></p>
<center>
<h1>
<a name="defaultapi">
libsm sm_io default API definition
</a>
</h1>
</center>
<h2> Introduction </h2>
<p>
A number of <i>sm_io</i> API's perform similar to their <i>stdio</i>
counterparts (same name as when the "sm_io_" is removed).
One difference between <i>sm_io</i> and <i>stdio</i> functions is that
if a "file pointer" (FILE/SM_FILE_T)
is one of the arguments for the function, then it is now the first
argument. <i>Sm_io</i> is standardized so that when a file pointer is
one of the arguments to function then it will always be the first
arguement. Many of the <i>sm_io</i> function take a <i>timeout</i>
argument (see <a href="#timeouts"><b>Timeouts</b></a>).
</p>
<p>
The API you have selected is one of these. Please consult the
appropriate <i>stdio</i> man page for now.
</p>

</body>
</html>
OpenPOWER on IntegriCloud