📄 sio.c
字号:
/* * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis * All rights reserved. The file named COPYRIGHT specifies the terms * and conditions for redistribution. */static char RCSid[] = "sio.c,v 1.2 1995/03/25 23:41:13 hardy Exp" ;static char sio_version[] = VERSION ;#include <sys/types.h>#include <sys/stat.h>#include "sio.h"#include "impl.h"#ifdef EVENTS#include "events.h"#endif/* * SIO WRITE FUNCTIONS: Swrite, Sputc */#ifndef sio_memscanPRIVATE char *sio_memscan();#endif/* * Stream write call: arguments same as those of write(2) */int Swrite( fd, addr, nbytes ) int fd ; register char *addr ; register int nbytes ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ; register int b_transferred ; register int b_avail ; int total_b_transferred ; int b_written ; int b_in_buffer ;#ifdef EVENTS EVENT( fd, EV_SWRITE ) ;#endif IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ; b_avail = odp->buf_end - odp->nextb ; b_transferred = MIN( nbytes, b_avail ) ; sio_memcopy( addr, odp->nextb, b_transferred ) ; odp->nextb += b_transferred ; /* * check if we are done */ if ( b_transferred == nbytes ) return( b_transferred ) ; /* * at this point we know that the buffer is full */ b_in_buffer = odp->buf_end - odp->start ; b_written = __sio_writef( odp, fd ) ; if ( b_written != b_in_buffer ) return( (b_written >= nbytes) ? nbytes : b_written ) ; total_b_transferred = b_transferred ; addr += b_transferred ; nbytes -= b_transferred ; for ( ;; ) { b_transferred = MIN( nbytes, odp->buffer_size ) ; sio_memcopy( addr, odp->nextb, b_transferred ) ; odp->nextb += b_transferred ; nbytes -= b_transferred ; if ( nbytes == 0 ) { total_b_transferred += b_transferred ; break ; } /* * the buffer is full */ b_written = __sio_writef( odp, fd ) ; if ( b_written != odp->buffer_size ) { if ( b_written != SIO_ERR ) { total_b_transferred += b_written ; odp->nextb += b_written ; } break ; } /* * everything is ok */ total_b_transferred += b_transferred ; addr += b_transferred ; } return( total_b_transferred ) ;}/* * Add a character to a file */int Sputc( fd, c ) int fd ; char c ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_od_t *odp = ODP( dp ) ;#ifdef EVENTS EVENT( fd, EV_SPUTC ) ;#endif IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ; /* * The following is a weak check since we should really be * checking that nextb == buf_end (it would be an error for * nextb to exceed buf_end; btw, the assertion above, when * enabled makes sure this does not occur). * * NOTE: __sio_writef NEVER uses data beyond the end of buffer. */ if ( odp->nextb >= odp->buf_end ) { int b_in_buffer = odp->buf_end - odp->start ; /* * There is nothing we can do if __sio_writef does not manage * to write the whole buffer */ if ( __sio_writef( odp, fd ) != b_in_buffer ) return( SIO_ERR ) ; } *odp->nextb++ = c ; if ( __SIO_MUST_FLUSH( *odp, c ) && __sio_writef( odp, fd ) == SIO_ERR ) return( SIO_ERR ) ; return ( c ) ;}/* * SIO READ FUNCTIONS *//* * Stream read call: arguments same as those of read(2) */int Sread( fd, addr, nbytes ) int fd ; char *addr ; int nbytes ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register int b_transferred ; int b_read ; int total_b_transferred ; int b_left ;#ifdef EVENTS EVENT( fd, EV_SREAD ) ;#endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; b_left = idp->end - idp->nextb ; b_transferred = MIN( b_left, nbytes ) ; sio_memcopy( idp->nextb, addr, b_transferred ) ; idp->nextb += b_transferred ; if ( b_transferred == nbytes ) return( b_transferred ) ; nbytes -= b_transferred ; total_b_transferred = b_transferred ; addr += b_transferred ; do { b_read = __sio_readf( idp, fd ) ; switch ( b_read ) { case SIO_ERR: if ( total_b_transferred == 0 ) return( SIO_ERR ) ; /* FALL THROUGH */ case 0: return( total_b_transferred ) ; } b_transferred = MIN( b_read, nbytes ) ; sio_memcopy( idp->nextb, addr, b_transferred ) ; addr += b_transferred ; idp->nextb += b_transferred ; total_b_transferred += b_transferred ; nbytes -= b_transferred ; } while ( nbytes && b_read == idp->buffer_size ) ; return( total_b_transferred ) ;}/* * Read a line from a file * Returns a pointer to the beginning of the line or NULL */char *Srdline( fd ) int fd ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register char *cp ; register char *line_start ; register int b_left ; register int extension ;#ifdef EVENTS EVENT( fd, EV_SRDLINE ) ;#endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;#ifdef HAS_MMAP if ( idp->memory_mapped && __sio_switch( idp, fd ) == FAILURE ) return( NULL ) ;#endif b_left = idp->end - idp->nextb ; /* * Look for a '\n'. If the search fails, extend the buffer * and search again (the extension is performed by copying the * bytes that were searched to the auxiliary buffer and reading * new input in the main buffer). * If the new input still does not contain a '\n' and there is * more space in the main buffer (this can happen with network * connections), read more input until either the buffer is full * or a '\n' is found. * Finally, set cp to point to the '\n', and line_start to * the beginning of the line */ if ( b_left && ( cp = sio_memscan( idp->nextb, b_left, '\n' ) ) != NULL ) { line_start = idp->nextb ; idp->nextb = cp + 1 ; } else { extension = __sio_extend_buffer( idp, fd, b_left ) ; if ( extension > 0 ) { ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; line_start = idp->start ; cp = sio_memscan( idp->nextb, extension, '\n' ) ; if ( cp != NULL ) idp->nextb = cp + 1 ; else for ( ;; ) { idp->nextb = idp->end ; extension = __sio_more( idp, fd ) ; if ( extension > 0 ) { cp = sio_memscan( idp->nextb, extension, '\n' ) ; if ( cp == NULL ) continue ; idp->nextb = cp + 1 ; break ; } else { /* * If there is spare room in the buffer avoid trashing * the last character */ if ( idp->end < &idp->buf[ idp->buffer_size ] ) cp = idp->end ; else cp = &idp->buf[ idp->buffer_size - 1 ] ; break ; } } } else /* buffer could not be extended */ if ( b_left == 0 ) { /* * Set errno to 0 if EOF has been reached */ if ( extension == 0 ) errno = 0 ; return( NULL ) ; } else { line_start = idp->start ; cp = idp->end ; /* * By setting idp->nextb to be equal to idp->end, * subsequent calls to Srdline will return NULL because * __sio_extend_buffer will be invoked and it will return 0. */ idp->nextb = idp->end ; } } *cp = NUL ; idp->line_length = cp - line_start ; return( line_start ) ;}/* * Get a character from a file */int Sgetc( fd ) int fd ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ;#ifdef EVENTS EVENT( fd, EV_SGETC ) ;#endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; if ( idp->nextb >= idp->end ) { register int b_read = __sio_readf( idp, fd ) ; if ( b_read == 0 ) return( SIO_EOF ) ; else if ( b_read == SIO_ERR ) return( SIO_ERR ) ; } return( (int) *idp->nextb++ ) ;}char *Sfetch( fd, lenp ) int fd ; long *lenp ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; register int b_read ; register char *p ;#ifdef EVENTS EVENT( fd, EV_SFETCH ) ;#endif IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; if ( idp->nextb >= idp->end ) { b_read = __sio_readf( idp, fd ) ; if ( b_read == SIO_ERR ) return( NULL ) ; if ( b_read == 0 ) { errno = 0 ; return( NULL ) ; } } *lenp = idp->end - idp->nextb ; p = idp->nextb ; idp->nextb = idp->end ; return( p ) ;}/* * SIO CONTROL FUNCTIONS *//* * Undo the last Srdline or Sgetc */int Sundo( fd, type ) int fd ; int type ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; register __sio_id_t *idp = IDP( dp ) ; int retval = 0 ;#ifdef EVENTS EVENT( fd, EV_SUNDO ) ;#endif CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ; /* * Undo works only for fd's used for input */ if ( dp->stream_type != __SIO_INPUT_STREAM ) return( SIO_ERR ) ; /* * Check if the operation makes sense; if so, do it, otherwise ignore it */ switch ( type ) { case SIO_UNDO_LINE: if ( idp->nextb - idp->line_length > idp->start ) { *--idp->nextb = '\n' ; idp->nextb -= idp->line_length ; } ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; break ; case SIO_UNDO_CHAR: if ( idp->nextb > idp->start ) idp->nextb-- ; ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ; break ; default: retval = SIO_ERR ; break ; } return( retval ) ;}/* * Flush the buffer associated with the given file descriptor * The special value, SIO_FLUSH_ALL flushes all buffers * * Return value: * 0 : if fd is SIO_FLUSH_ALL or if the flush is successful * SIO_ERR: if fd is not SIO_FLUSH_ALL and * the flush is unsuccessful * or the descriptor is not initialized or it is not * an output descriptor */int Sflush( fd ) int fd ;{ register __sio_descriptor_t *dp ; int b_in_buffer ;#ifdef EVENTS EVENT( fd, EV_SFLUSH ) ;#endif if ( fd == SIO_FLUSH_ALL ) { for ( fd = 0, dp = __sio_descriptors ; fd < N_SIO_DESCRIPTORS ; dp++, fd++ ) if ( DESCRIPTOR_INITIALIZED( dp ) && dp->stream_type == __SIO_OUTPUT_STREAM ) (void) __sio_writef( ODP( dp ), fd ) ; return( 0 ) ; } else { dp = &__sio_descriptors[ fd ] ; CONTROL_SETUP( dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; b_in_buffer = ODP( dp )->nextb - ODP( dp )->start ; if ( __sio_writef( ODP( dp ), fd ) != b_in_buffer ) return( SIO_ERR ) ; else return( 0 ) ; }}/* * Close the file descriptor. This call is provided because * a file descriptor may be closed and then reopened. There is * no easy way for SIO to identify such a situation, so Sclose * must be used. * * Sclose invokes Sdone which finalizes the buffer. * There is no SIO_CLOSE_ALL value for fd because such a thing * would imply that the program will exit very soon, therefore * the closing of all file descriptors will be done in the kernel * (and the finalization will be done by the finalization function * NOTE: not true if the OS does not support a finalization function) * * There is no need to invoke SETUP; Sdone will do it. */int Sclose( fd ) int fd ;{#ifdef EVENTS EVENT( fd, EV_SCLOSE ) ;#endif if ( __SIO_FD_INITIALIZED( fd ) ) if ( Sdone( fd ) == SIO_ERR ) return( SIO_ERR ) ; return( close( fd ) ) ;}/* * Tie the file descriptor in_fd to the file descriptor out_fd * This means that whenever a read(2) is done on in_fd, it is * preceded by a write(2) on out_fd. * Why this is nice to have: * 1) When used in filters it maximizes concurrency * 2) When the program prompts the user for something it forces * the prompt string to be displayed even if it does not * end with a '\n' (which would cause a flush). * In this implementation, out_fd cannot be a regular file. * This is done to avoid non-block-size write's. * The file descriptors are initialized if that has not been done * already. If any of them is initialized, it must be for the appropriate * stream type (input or output). * * NOTE: the code handles correctly the case when in_fd == out_fd */int Stie( in_fd, out_fd ) int in_fd, out_fd ;{ struct stat st ; register __sio_descriptor_t *dp ; int was_initialized ; boolean_e failed = NO ;#ifdef EVENTS EVENT( in_fd, EV_STIE ) ;#endif /* * Check if the out_fd is open */ if ( fstat( out_fd, &st ) == -1 ) return( SIO_ERR ) ; /* * If the out_fd refers to a regular file, the request is silently ignored */#ifdef S_IFMT if ( ( st.st_mode & S_IFMT ) == S_IFREG ) return( 0 ) ;#else if ( S_ISREG( st.st_mode ) ) return( 0 ) ;#endif dp = &__sio_descriptors[ in_fd ] ; was_initialized = dp->initialized ; /* remember if it was initialized */ IO_SETUP( in_fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ; /* * Perform manual initialization of out_fd to avoid leaving in_fd * initialized if the initialization of out_fd fails. * If out_fd is initialized, check if it is used for output. * If it is not initialized, initialize it for output. */ dp = &__sio_descriptors[ out_fd ] ; if ( DESCRIPTOR_INITIALIZED( dp ) ) { if ( dp->stream_type != __SIO_OUTPUT_STREAM ) { failed = YES ; errno = EBADF ; } } else if ( __sio_init( dp, out_fd, __SIO_OUTPUT_STREAM ) == SIO_ERR ) failed = YES ; if ( failed == NO ) { __SIO_ID( in_fd ).tied_fd = out_fd ; return( 0 ) ; } else { /* * We failed. If we did any initialization, undo it */ if ( ! was_initialized ) { int save_errno = errno ; (void) Sdone( in_fd ) ; errno = save_errno ; } return( SIO_ERR ) ; }}/* * Untie a file descriptor */int Suntie( fd ) int fd ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;#ifdef EVENTS EVENT( fd, EV_SUNTIE ) ;#endif CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ; if ( IDP( dp )->tied_fd != SIO_NO_TIED_FD ) { IDP( dp )->tied_fd = SIO_NO_TIED_FD ; return( 0 ) ; } else { errno = EBADF ; return( SIO_ERR ) ; }}/* * Changes the type of buffering on the specified descriptor. * As a side-effect, it initializes the descriptor as an output stream. */int Sbuftype( fd, type ) int fd, type ;{ register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;#ifdef EVENTS EVENT( fd, EV_SBUFTYPE ) ;#endif /* * Check for a valid type */ if ( type != SIO_LINEBUF && type != SIO_FULLBUF && type != SIO_NOBUF ) { errno = EINVAL ; return( SIO_ERR ) ; } IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ; ODP( dp )->buftype = type ; return( 0 ) ;}#ifndef sio_memscanPRIVATE char *sio_memscan( from, how_many, ch ) char *from ; int how_many ; register char ch ;{ register char *p ; register char *last = from + how_many ; for ( p = from ; p < last ; p++ ) if ( *p == ch ) return( p ) ; return( 0 ) ;}#endif /* sio_memscan */#ifdef NEED_MEMCOPYvoid __sio_memcopy( from, to, nbytes ) register char *from, *to ; register int nbytes ;{ while ( nbytes-- ) *to++ = *from++ ;}#endif /* NEED_MEMCOPY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -