2 * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
3 * (c) Portions Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
10 #include <sys/types.h>
25 * SIO WRITE FUNCTIONS: Swrite, Sputc
29 * Stream write call: arguments same as those of write(2)
31 int Swrite( int fd, const char *addr, unsigned int nbytes )
33 __sio_descriptor_t *dp ;
35 unsigned int b_transferred ;
36 unsigned int b_avail ;
37 int total_b_transferred ;
41 if ( nbytes > INT_MAX )
43 if( sio_setup( fd, &dp, __SIO_OUTPUT_STREAM ) == SIO_ERR )
46 ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
48 b_avail = odp->buf_end - odp->nextb ;
49 b_transferred = MIN( nbytes, b_avail ) ;
50 sio_memcopy( addr, odp->nextb, b_transferred ) ;
51 odp->nextb += b_transferred ;
54 * check if we are done
56 if ( b_transferred == nbytes )
57 return( b_transferred ) ;
60 * at this point we know that the buffer is full
62 b_in_buffer = odp->buf_end - odp->start ;
63 b_written = __sio_writef( odp, fd ) ;
64 if ( b_written != b_in_buffer )
65 return( (b_written >= (int)nbytes) ? (int)nbytes : b_written ) ;
67 total_b_transferred = b_transferred ;
68 addr += b_transferred ;
69 nbytes -= b_transferred ;
73 b_transferred = MIN( nbytes, odp->buffer_size ) ;
74 sio_memcopy( addr, odp->nextb, b_transferred ) ;
75 odp->nextb += b_transferred ;
76 nbytes -= b_transferred ;
79 total_b_transferred += b_transferred ;
85 b_written = __sio_writef( odp, fd ) ;
86 if ( b_written != (int)odp->buffer_size )
88 if ( b_written != SIO_ERR )
90 total_b_transferred += b_written ;
91 odp->nextb += b_written ;
98 total_b_transferred += b_transferred ;
99 addr += b_transferred ;
101 return( total_b_transferred ) ;
106 * Add a character to a file
108 static int Sputc( int fd, char c )
110 __sio_descriptor_t *dp ;
113 if( sio_setup( fd, &dp, __SIO_OUTPUT_STREAM) == SIO_ERR )
116 ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
119 * The following is a weak check since we should really be
120 * checking that nextb == buf_end (it would be an error for
121 * nextb to exceed buf_end; btw, the assertion above, when
122 * enabled makes sure this does not occur).
124 * NOTE: __sio_writef NEVER uses data beyond the end of buffer.
126 if ( odp->nextb >= odp->buf_end )
128 int b_in_buffer = odp->buf_end - odp->start ;
131 * There is nothing we can do if __sio_writef does not manage
132 * to write the whole buffer
134 if ( __sio_writef( odp, fd ) != b_in_buffer )
138 if ( __SIO_MUST_FLUSH( *odp, c ) && __sio_writef( odp, fd ) == SIO_ERR )
151 * Read a line from a file
152 * Returns a pointer to the beginning of the line or NULL
154 char *Srdline( int fd )
156 __sio_descriptor_t *dp ;
163 if( sio_setup( fd, &dp, __SIO_INPUT_STREAM ) == SIO_ERR )
166 ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
169 if ( idp->memory_mapped && __sio_switch( idp, fd ) == FAILURE )
173 b_left = idp->end - idp->nextb ;
175 * Look for a '\n'. If the search fails, extend the buffer
176 * and search again (the extension is performed by copying the
177 * bytes that were searched to the auxiliary buffer and reading
178 * new input in the main buffer).
179 * If the new input still does not contain a '\n' and there is
180 * more space in the main buffer (this can happen with network
181 * connections), read more input until either the buffer is full
182 * or a '\n' is found.
183 * Finally, set cp to point to the '\n', and line_start to
184 * the beginning of the line
186 if ( b_left && ( cp = sio_memscan( idp->nextb, b_left, '\n' ) ) != NULL )
188 line_start = idp->nextb ;
189 idp->nextb = cp + 1 ;
193 extension = __sio_extend_buffer( idp, fd, b_left ) ;
196 ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
198 line_start = idp->start ;
199 cp = sio_memscan( idp->nextb, extension, '\n' ) ;
201 idp->nextb = cp + 1 ;
205 idp->nextb = idp->end ;
206 extension = __sio_more( idp, fd ) ;
209 cp = sio_memscan( idp->nextb, extension, '\n' ) ;
212 idp->nextb = cp + 1 ;
218 * If there is spare room in the buffer avoid trashing
221 if ( idp->end < &idp->buf[ idp->buffer_size ] )
224 cp = &idp->buf[ idp->buffer_size - 1 ] ;
229 else /* buffer could not be extended */
233 * Set errno to 0 if EOF has been reached
235 if ( extension == 0 )
241 line_start = idp->start ;
244 * By setting idp->nextb to be equal to idp->end,
245 * subsequent calls to Srdline will return NULL because
246 * __sio_extend_buffer will be invoked and it will return 0.
248 idp->nextb = idp->end ;
252 idp->line_length = cp - line_start ;
253 return( line_start ) ;
259 * SIO CONTROL FUNCTIONS
264 * Flush the buffer associated with the given file descriptor
265 * The special value, SIO_FLUSH_ALL flushes all buffers
268 * 0 : if fd is SIO_FLUSH_ALL or if the flush is successful
269 * SIO_ERR: if fd is not SIO_FLUSH_ALL and
270 * the flush is unsuccessful
271 * or the descriptor is not initialized or it is not
272 * an output descriptor
276 __sio_descriptor_t *dp ;
279 if ( fd == SIO_FLUSH_ALL )
281 for ( fd = 0, dp = __sio_descriptors ;
282 fd < __sio_n_descriptors ;
284 if ( DESCRIPTOR_INITIALIZED( dp ) &&
285 dp->stream_type == __SIO_OUTPUT_STREAM )
286 (void) __sio_writef( ODP( dp ), fd ) ;
291 if ( fd >= __sio_n_descriptors ) {
296 dp = &__sio_descriptors[ fd ] ;
298 if( (! DESCRIPTOR_INITIALIZED( dp )) ||
299 (dp->stream_type != __SIO_OUTPUT_STREAM) )
302 b_in_buffer = ODP( dp )->nextb - ODP( dp )->start ;
303 if ( __sio_writef( ODP( dp ), fd ) != b_in_buffer )
312 * Close the file descriptor. This call is provided because
313 * a file descriptor may be closed and then reopened. There is
314 * no easy way for SIO to identify such a situation, so Sclose
317 * Sclose invokes Sdone which finalizes the buffer.
318 * There is no SIO_CLOSE_ALL value for fd because such a thing
319 * would imply that the program will exit very soon, therefore
320 * the closing of all file descriptors will be done in the kernel
321 * (and the finalization will be done by the finalization function
322 * NOTE: not true if the OS does not support a finalization function)
324 * There is no need to invoke SETUP; Sdone will do it.
328 if ( __SIO_FD_INITIALIZED( fd ) ) {
329 if ( Sdone( fd ) == SIO_ERR ) {
334 return( close( fd ) ) ;
339 * Changes the type of buffering on the specified descriptor.
340 * As a side-effect, it initializes the descriptor as an output stream.
342 int Sbuftype( int fd, int type )
344 __sio_descriptor_t *dp ;
347 * Check for a valid type
349 if ( type != SIO_LINEBUF && type != SIO_FULLBUF && type != SIO_NOBUF )
355 if( sio_setup( fd, &dp, __SIO_OUTPUT_STREAM ) == SIO_ERR )
357 ODP( dp )->buftype = type ;
364 static char *sio_memscan( const char *from, int how_many, char ch )
367 char *last = from + how_many ;
369 for ( p = from ; p < last ; p++ )
375 #endif /* sio_memscan */
380 void __sio_memcopy( const char *from, char *to, int nbytes )
386 #endif /* NEED_MEMCOPY */
388 int sio_setup(int fd, __sio_descriptor_t **dp, unsigned int type)
390 if ( fd >= __sio_n_descriptors ) {
391 if( Smorefds(fd) != 0 ) {
397 *dp = &__sio_descriptors[ fd ];
399 if( DESCRIPTOR_INITIALIZED( *dp ) ) {
400 if( (*dp)->stream_type != type ) {
404 } else if( __sio_init(*dp, fd, type) == SIO_ERR )
411 * The Sputchar function depends on the fact that the fields
412 * nextb, buf_end, end
413 * are 0 if a stream descriptor is not being used or has not yet been
415 * This is true initially because of the static allocation of the
416 * descriptor array, and Sdone must make sure that it is true
417 * after I/O on a descriptor is over.
419 int Sputchar( int fd, char c )
423 if( __SIO_OD( fd ).nextb < __SIO_OD( fd ).buf_end ) {
424 if( __SIO_OD(fd).buftype == SIO_FULLBUF ) {
425 ret = *(__SIO_OD(fd).nextb)++ = (unsigned char) (c);
426 } else if ( __SIO_OD(fd).buftype == SIO_LINEBUF ) {
427 if( (*(__SIO_OD(fd).nextb) = (unsigned char)(c)) != '\n' ) {
428 ret = *(__SIO_OD(fd).nextb)++;
430 ret = Sputc( fd, *(__SIO_OD(fd).nextb) );
433 ret = Sputc( fd, c );
436 ret = Sputc( fd, c );