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