]> pd.if.org Git - pdclib.old/blob - functions/stdio/fwrite.c
pthread c11 threading backend: add support for thread specific data
[pdclib.old] / functions / stdio / fwrite.c
1 /* $Id$ */
2
3 /* fwrite( const void *, size_t, size_t, FILE * )
4
5    This file is part of the Public Domain C Library (PDCLib).
6    Permission is granted to use, modify, and / or redistribute at will.
7 */
8
9 #include <stdio.h>
10
11 #ifndef REGTEST
12 #include <_PDCLIB_io.h>
13 #include <_PDCLIB_glue.h>
14
15 #include <stdbool.h>
16 #include <string.h>
17
18 //TODO OS(2012-08-01): Ascertain purpose of lineend & potentially remove
19
20 size_t fwrite_unlocked( const void * _PDCLIB_restrict ptr, 
21                size_t size, size_t nmemb, 
22                FILE * _PDCLIB_restrict stream )
23 {
24     if ( _PDCLIB_prepwrite( stream ) == EOF )
25     {
26         return 0;
27     }
28     _PDCLIB_size_t offset = 0;
29     //bool lineend = false;
30     size_t nmemb_i;
31     for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
32     {
33         for ( size_t size_i = 0; size_i < size; ++size_i )
34         {
35             if ( ( stream->buffer[ stream->bufidx++ ] = ((char*)ptr)[ nmemb_i * size + size_i ] ) == '\n' )
36             {
37                 /* Remember last newline, in case we have to do a partial line-buffered flush */
38                 offset = stream->bufidx;
39                 //lineend = true;
40             }
41             if ( stream->bufidx == stream->bufsize )
42             {
43                 if ( _PDCLIB_flushbuffer( stream ) == EOF )
44                 {
45                     /* Returning number of objects completely buffered */
46                     return nmemb_i;
47                 }
48                 //lineend = false;
49                 /*
50                  * The entire buffer has been flushed; this means we have to
51                  * reset our newline position as we have already written
52                  * that part of the stream.
53                  */
54                 offset = 0;
55             }
56         }
57     }
58     /* Fully-buffered streams are OK. Non-buffered streams must be flushed,
59        line-buffered streams only if there's a newline in the buffer.
60     */
61     switch ( stream->status & ( _IONBF | _IOLBF ) )
62     {
63         case _IONBF:
64             if ( _PDCLIB_flushbuffer( stream ) == EOF )
65             {
66                 /* We are in a pinch here. We have an error, which requires a
67                    return value < nmemb. On the other hand, all objects have
68                    been written to buffer, which means all the caller had to
69                    do was removing the error cause, and re-flush the stream...
70                    Catch 22. We'll return a value one short, to indicate the
71                    error, and can't really do anything about the inconsistency.
72                 */
73                 return nmemb_i - 1;
74             }
75             break;
76         case _IOLBF:
77             {
78             size_t bufidx = stream->bufidx;
79             stream->bufidx = offset;
80             if ( _PDCLIB_flushbuffer( stream ) == EOF )
81             {
82                 /* See comment above. */
83                 stream->bufidx = bufidx;
84                 return nmemb_i - 1;
85             }
86             stream->bufidx = bufidx - offset;
87             memmove( stream->buffer, stream->buffer + offset, stream->bufidx );
88             }
89     }
90     return nmemb_i;
91 }
92
93 size_t fwrite( const void * _PDCLIB_restrict ptr, 
94                size_t size, size_t nmemb, 
95                FILE * _PDCLIB_restrict stream )
96 {
97     flockfile( stream );
98     size_t r = fwrite_unlocked( ptr, size, nmemb, stream );
99     funlockfile( stream );
100     return r;
101 }
102
103 #endif
104
105 #ifdef TEST
106 #include <_PDCLIB_test.h>
107
108 int main( void )
109 {
110     /* Testing covered by fread(). */
111     return TEST_RESULTS;
112 }
113
114 #endif
115