/*************************************************************** MPU-BUFFER.C This file contains source code of functions for buffered byte stream operations. PART OF : MPUIO - library . USAGE : Internal and external . NOTE : FREAD/FWRITE are binary byte operations. Copyright (C) 2000 - 2026 by Andrey V.Kosteltsev. All Rights Reserved. ***************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include int __mpu_IO_doallocbuf( mpu_FILE *stream ) { size_t size; if( stream->_buf_base != (unsigned char *)0 ) return( 0 ); size = (stream->_flags & __MPU_IO_UNBUFFERED) ? 1 : MPU_BUFSIZ; stream->_buf_base = (unsigned char *)malloc( size ); if( stream->_buf_base == (unsigned char *)0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( mpu_EOF ); } stream->_buf_end = stream->_buf_base + size; return( 0 ); } /* End of __mpu_IO_doallocbuf() */ /*************************************************************** Write as much of BUF as possible, retrying interrupted writes. Return the number of bytes actually transferred. COMPLETE is set to one only when all SIZE bytes were written. ***************************************************************/ static size_t __mpu_IO_write_bytes( mpu_FILE *stream, const unsigned char *buf, size_t size, int *complete ) { size_t done = 0; *complete = 0; while( done < size ) { ssize_t n; n = write( stream->_fileno, buf + done, size - done ); if( n < 0 ) { if( errno == EINTR ) continue; stream->_flags |= __MPU_IO_ERR_SEEN; return( done ); } if( n == 0 ) { errno = EIO; stream->_flags |= __MPU_IO_ERR_SEEN; return( done ); } done += (size_t)n; } *complete = 1; return( done ); } /* End of __mpu_IO_write_bytes() */ int __mpu_IO_file_sync_input_unlocked( mpu_FILE *stream ) { off_t unread; if( !(stream->_flags & __MPU_IO_READING) ) return( 0 ); unread = 0; if( stream->_read_ptr != (unsigned char *)0 && stream->_read_end != (unsigned char *)0 ) unread = (off_t)(stream->_read_end - stream->_read_ptr); if( unread != 0 ) { if( lseek( stream->_fileno, -unread, SEEK_CUR ) == (off_t)-1 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( mpu_EOF ); } } stream->_read_base = stream->_buf_base; stream->_read_ptr = stream->_buf_base; stream->_read_end = stream->_buf_base; return( 0 ); } /* End of __mpu_IO_file_sync_input_unlocked() */ int __mpu_IO_file_flush_unlocked( mpu_FILE *stream ) { size_t size; if( stream->_flags & __MPU_IO_WRITING ) { size = 0; if( stream->_write_base != (unsigned char *)0 && stream->_write_ptr != (unsigned char *)0 ) size = (size_t)(stream->_write_ptr - stream->_write_base); if( size != 0 ) { size_t done; int complete; done = __mpu_IO_write_bytes( stream, stream->_write_base, size, &complete ); if( !complete ) { /* A short write may have committed a prefix before the final error. Keep only the unwritten suffix buffered so that a later retry cannot duplicate that prefix. */ if( done != 0 && done < size ) memmove( stream->_write_base, stream->_write_base + done, size - done ); stream->_write_ptr = stream->_write_base + (size - done); stream->_write_end = stream->_buf_end; return( mpu_EOF ); } } stream->_write_base = stream->_buf_base; stream->_write_ptr = stream->_buf_base; stream->_write_end = stream->_buf_end; } else if( stream->_flags & __MPU_IO_READING ) { if( __mpu_IO_file_sync_input_unlocked( stream ) == mpu_EOF ) return( mpu_EOF ); } return( 0 ); } /* End of __mpu_IO_file_flush_unlocked() */ static int __mpu_IO_switch_to_read( mpu_FILE *stream ) { if( stream->_flags & __MPU_IO_NO_READS ) { errno = EBADF; stream->_flags |= __MPU_IO_ERR_SEEN; return( mpu_EOF ); } if( stream->_flags & __MPU_IO_WRITING ) { if( __mpu_IO_file_flush_unlocked( stream ) == mpu_EOF ) return( mpu_EOF ); stream->_flags &= ~__MPU_IO_WRITING; } if( __mpu_IO_doallocbuf( stream ) == mpu_EOF ) return( mpu_EOF ); if( !(stream->_flags & __MPU_IO_READING) ) { stream->_flags |= __MPU_IO_READING; stream->_read_base = stream->_buf_base; stream->_read_ptr = stream->_buf_base; stream->_read_end = stream->_buf_base; } return( 0 ); } /* End of __mpu_IO_switch_to_read() */ static int __mpu_IO_switch_to_write( mpu_FILE *stream ) { if( stream->_flags & __MPU_IO_NO_WRITES ) { errno = EBADF; stream->_flags |= __MPU_IO_ERR_SEEN; return( mpu_EOF ); } if( stream->_flags & __MPU_IO_READING ) { if( __mpu_IO_file_sync_input_unlocked( stream ) == mpu_EOF ) return( mpu_EOF ); stream->_flags &= ~__MPU_IO_READING; } if( __mpu_IO_doallocbuf( stream ) == mpu_EOF ) return( mpu_EOF ); if( !(stream->_flags & __MPU_IO_WRITING) ) { stream->_flags |= __MPU_IO_WRITING; stream->_write_base = stream->_buf_base; stream->_write_ptr = stream->_buf_base; stream->_write_end = stream->_buf_end; } return( 0 ); } /* End of __mpu_IO_switch_to_write() */ /*************************************************************** Refill a real-file input buffer and return the next byte without consuming it. ***************************************************************/ int __mpu_IO_file_underflow_unlocked( mpu_FILE *stream ) { ssize_t n; if( __mpu_IO_switch_to_read( stream ) == mpu_EOF ) return( mpu_EOF ); if( stream->_read_ptr < stream->_read_end ) return( (int)*stream->_read_ptr ); do { n = read( stream->_fileno, stream->_buf_base, (size_t)(stream->_buf_end - stream->_buf_base) ); } while( n < 0 && errno == EINTR ); if( n < 0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( mpu_EOF ); } if( n == 0 ) { stream->_flags |= __MPU_IO_EOF_SEEN; return( mpu_EOF ); } stream->_flags &= ~__MPU_IO_EOF_SEEN; stream->_read_base = stream->_buf_base; stream->_read_ptr = stream->_buf_base; stream->_read_end = stream->_buf_base + n; return( (int)*stream->_read_ptr ); } /* End of __mpu_IO_file_underflow_unlocked() */ /*************************************************************** Flush a real-file output buffer and optionally append one byte. Passing MPU_EOF requests only the flush operation. ***************************************************************/ int __mpu_IO_file_overflow_unlocked( mpu_FILE *stream, int c ) { unsigned char ch; if( __mpu_IO_switch_to_write( stream ) == mpu_EOF ) return( mpu_EOF ); if( stream->_write_ptr != stream->_write_base ) { if( __mpu_IO_file_flush_unlocked( stream ) == mpu_EOF ) return( mpu_EOF ); } if( c == mpu_EOF ) return( 0 ); ch = (unsigned char)c; if( stream->_flags & __MPU_IO_UNBUFFERED ) { int complete; return( __mpu_IO_write_bytes( stream, &ch, 1, &complete ) == 1 && complete ? c : mpu_EOF ); } *stream->_write_ptr++ = ch; if( (stream->_flags & __MPU_IO_LINE_BUF) && ch == '\n' ) { if( __mpu_IO_file_flush_unlocked( stream ) == mpu_EOF ) return( mpu_EOF ); } return( c ); } /* End of __mpu_IO_file_overflow_unlocked() */ /*************************************************************** Synchronize a real-file stream with its underlying descriptor. ***************************************************************/ int __mpu_IO_file_sync_unlocked( mpu_FILE *stream ) { return( __mpu_IO_file_flush_unlocked( stream ) ); } /* End of __mpu_IO_file_sync_unlocked() */ /*************************************************************** Get one raw byte from a real-file stream. ***************************************************************/ int __mpu_IO_file_get_byte_unlocked( mpu_FILE *stream ) { int c; if( __mpu_IO_switch_to_read( stream ) == mpu_EOF ) return( mpu_EOF ); if( stream->_read_ptr >= stream->_read_end ) { c = __mpu_IO_file_underflow_unlocked( stream ); if( c == mpu_EOF ) return( mpu_EOF ); } return( (int)*stream->_read_ptr++ ); } /* End of __mpu_IO_file_get_byte_unlocked() */ /*************************************************************** Put one raw byte to a real-file stream. ***************************************************************/ int __mpu_IO_file_put_byte_unlocked( unsigned char c, mpu_FILE *stream ) { if( __mpu_IO_switch_to_write( stream ) == mpu_EOF ) return( mpu_EOF ); if( stream->_flags & __MPU_IO_UNBUFFERED ) return( __mpu_IO_file_overflow_unlocked( stream, (int)c ) ); if( stream->_write_ptr == stream->_write_end ) { if( __mpu_IO_file_overflow_unlocked( stream, mpu_EOF ) == mpu_EOF ) return( mpu_EOF ); } *stream->_write_ptr++ = c; if( (stream->_flags & __MPU_IO_LINE_BUF) && c == '\n' ) { if( __mpu_IO_file_overflow_unlocked( stream, mpu_EOF ) == mpu_EOF ) return( mpu_EOF ); } return( (int)c ); } /* End of __mpu_IO_file_put_byte_unlocked() */ /*************************************************************** Read SIZE raw bytes from a real file stream using buffered copies and direct POSIX reads for large transfers. ***************************************************************/ size_t __mpu_IO_file_xsgetn_unlocked( mpu_FILE *stream, void *data, size_t size ) { unsigned char *p = (unsigned char *)data; size_t done = 0; if( __mpu_IO_switch_to_read( stream ) == mpu_EOF ) return( 0 ); while( done < size ) { size_t avail; size_t want; avail = (size_t)(stream->_read_end - stream->_read_ptr); if( avail != 0 ) { want = size - done; if( want > avail ) want = avail; memcpy( p + done, stream->_read_ptr, want ); stream->_read_ptr += want; done += want; continue; } want = size - done; if( want >= (size_t)(stream->_buf_end - stream->_buf_base) ) { ssize_t n; do { n = read( stream->_fileno, p + done, want ); } while( n < 0 && errno == EINTR ); if( n < 0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; break; } if( n == 0 ) { stream->_flags |= __MPU_IO_EOF_SEEN; break; } done += (size_t)n; continue; } { ssize_t n; do { n = read( stream->_fileno, stream->_buf_base, (size_t)(stream->_buf_end - stream->_buf_base) ); } while( n < 0 && errno == EINTR ); if( n < 0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; break; } if( n == 0 ) { stream->_flags |= __MPU_IO_EOF_SEEN; break; } stream->_read_base = stream->_buf_base; stream->_read_ptr = stream->_buf_base; stream->_read_end = stream->_buf_base + n; } } return( done ); } /* End of __mpu_IO_file_xsgetn_unlocked() */ /*************************************************************** Write SIZE raw bytes to a real file stream using buffered copies and direct POSIX writes for large transfers. ***************************************************************/ size_t __mpu_IO_file_xsputn_unlocked( mpu_FILE *stream, const void *data, size_t size ) { const unsigned char *p = (const unsigned char *)data; size_t done = 0; if( __mpu_IO_switch_to_write( stream ) == mpu_EOF ) return( 0 ); if( stream->_flags & (__MPU_IO_UNBUFFERED | __MPU_IO_LINE_BUF) ) { while( done < size ) { if( __mpu_IO_file_put_byte_unlocked( p[done], stream ) == mpu_EOF ) break; ++done; } return( done ); } while( done < size ) { size_t avail; size_t want; avail = (size_t)(stream->_write_end - stream->_write_ptr); if( avail != 0 ) { want = size - done; if( want > avail ) want = avail; memcpy( stream->_write_ptr, p + done, want ); stream->_write_ptr += want; done += want; if( done == size ) break; } if( stream->_write_ptr == stream->_write_end ) { if( __mpu_IO_file_flush_unlocked( stream ) == mpu_EOF ) break; } want = size - done; if( want >= (size_t)(stream->_buf_end - stream->_buf_base) ) { size_t n; int complete; n = __mpu_IO_write_bytes( stream, p + done, want, &complete ); done += n; if( !complete ) break; } } return( done ); } /* End of __mpu_IO_file_xsputn_unlocked() */ /*************************************************************** Read raw bytes from STREAM without acquiring its lock. ***************************************************************/ size_t mpu_fread_unlocked( void *ptr, size_t size, size_t nmemb, mpu_FILE *stream ) { unsigned char *p = (unsigned char *)ptr; size_t total; size_t done; if( !__mpu_IO_valid( stream ) ) return( 0 ); if( size == 0 || nmemb == 0 ) return( 0 ); if( nmemb > (size_t)-1 / size ) { errno = EOVERFLOW; stream->_flags |= __MPU_IO_ERR_SEEN; return( 0 ); } total = size * nmemb; if( total != 0 && ptr == (void *)0 ) { errno = EINVAL; stream->_flags |= __MPU_IO_ERR_SEEN; return( 0 ); } done = __mpu_IO_xsgetn_unlocked( stream, p, total ); return( size == 0 ? 0 : done / size ); } /* End of mpu_fread_unlocked() */ /*************************************************************** Write raw bytes to STREAM without acquiring its lock. ***************************************************************/ size_t mpu_fwrite_unlocked( const void *ptr, size_t size, size_t nmemb, mpu_FILE *stream ) { const unsigned char *p = (const unsigned char *)ptr; size_t total; size_t done; if( !__mpu_IO_valid( stream ) ) return( 0 ); if( size == 0 || nmemb == 0 ) return( 0 ); if( nmemb > (size_t)-1 / size ) { errno = EOVERFLOW; stream->_flags |= __MPU_IO_ERR_SEEN; return( 0 ); } total = size * nmemb; if( total != 0 && ptr == (const void *)0 ) { errno = EINVAL; stream->_flags |= __MPU_IO_ERR_SEEN; return( 0 ); } done = __mpu_IO_xsputn_unlocked( stream, p, total ); return( size == 0 ? 0 : done / size ); } /* End of mpu_fwrite_unlocked() */ size_t mpu_fread( void *ptr, size_t size, size_t nmemb, mpu_FILE *stream ) { size_t ret; if( !__mpu_IO_valid( stream ) ) return( 0 ); pthread_mutex_lock( &stream->_lock ); ret = mpu_fread_unlocked( ptr, size, nmemb, stream ); pthread_mutex_unlock( &stream->_lock ); return( ret ); } /* End of mpu_fread() */ size_t mpu_fwrite( const void *ptr, size_t size, size_t nmemb, mpu_FILE *stream ) { size_t ret; if( !__mpu_IO_valid( stream ) ) return( 0 ); pthread_mutex_lock( &stream->_lock ); ret = mpu_fwrite_unlocked( ptr, size, nmemb, stream ); pthread_mutex_unlock( &stream->_lock ); return( ret ); } /* End of mpu_fwrite() */ /*************************************************************** Finish real-file backend state before descriptor close. ***************************************************************/ int __mpu_IO_file_finish_unlocked( mpu_FILE *stream ) { return( __mpu_IO_file_sync_unlocked( stream ) ); } /* End of __mpu_IO_file_finish_unlocked() */ /*************************************************************** Configure buffering for a real-file stream. ***************************************************************/ int __mpu_IO_file_setbuf_unlocked( mpu_FILE *stream, unsigned char *buf, int mode, size_t size ) { unsigned char *newbuf = buf; unsigned char *oldbuf; int newbuf_owned = 0; if( mode != MPU_IOFBF && mode != MPU_IOLBF && mode != MPU_IONBF ) { errno = EINVAL; return( -1 ); } if( mode != MPU_IONBF && size == 0 ) { errno = EINVAL; return( -1 ); } /* Prepare replacement storage before synchronizing or changing the current buffering configuration. Allocation failure therefore leaves the existing buffer and its directional state intact. */ if( mode == MPU_IONBF ) { size = 1; newbuf = (unsigned char *)malloc( 1 ); if( newbuf == (unsigned char *)0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( -1 ); } newbuf_owned = 1; } else if( newbuf == (unsigned char *)0 ) { newbuf = (unsigned char *)malloc( size ); if( newbuf == (unsigned char *)0 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( -1 ); } newbuf_owned = 1; } if( __mpu_IO_file_sync_unlocked( stream ) == mpu_EOF ) { if( newbuf_owned ) free( newbuf ); return( -1 ); } oldbuf = stream->_buf_base; if( oldbuf != (unsigned char *)0 && !(stream->_flags & __MPU_IO_USER_BUF) ) free( oldbuf ); stream->_buf_base = newbuf; stream->_buf_end = newbuf + size; stream->_read_base = (unsigned char *)0; stream->_read_ptr = (unsigned char *)0; stream->_read_end = (unsigned char *)0; stream->_write_base = (unsigned char *)0; stream->_write_ptr = (unsigned char *)0; stream->_write_end = (unsigned char *)0; stream->_flags &= ~(__MPU_IO_USER_BUF | __MPU_IO_LINE_BUF | __MPU_IO_UNBUFFERED | __MPU_IO_READING | __MPU_IO_WRITING); if( mode == MPU_IONBF ) stream->_flags |= __MPU_IO_UNBUFFERED; else if( !newbuf_owned ) stream->_flags |= __MPU_IO_USER_BUF; if( mode == MPU_IOLBF ) stream->_flags |= __MPU_IO_LINE_BUF; return( 0 ); } /* End of __mpu_IO_file_setbuf_unlocked() */ /*************************************************************** Seek a real-file stream relative to WHENCE and return position. ***************************************************************/ off_t __mpu_IO_file_seekoff_unlocked( mpu_FILE *stream, off_t offset, int whence ) { off_t base; /* SEEK_CUR is relative to the logical stream position, not the descriptor position beyond unread buffered input/pushback. */ if( whence == MPU_SEEK_CUR ) { base = __mpu_IO_file_tell_unlocked( stream ); if( base == (off_t)-1 ) return( (off_t)-1 ); if( (offset > 0 && base > (off_t)(INT64_MAX - offset)) || (offset < 0 && base < (off_t)(INT64_MIN - offset)) ) { errno = EOVERFLOW; stream->_flags |= __MPU_IO_ERR_SEEN; return( (off_t)-1 ); } offset = base + offset; whence = MPU_SEEK_SET; } if( __mpu_IO_file_seek_unlocked( stream, offset, whence ) != 0 ) return( (off_t)-1 ); return( __mpu_IO_file_tell_unlocked( stream ) ); } /* End of __mpu_IO_file_seekoff_unlocked() */ /*************************************************************** Seek a real-file stream to an absolute position. ***************************************************************/ off_t __mpu_IO_file_seekpos_unlocked( mpu_FILE *stream, off_t position ) { return( __mpu_IO_file_seekoff_unlocked( stream, position, MPU_SEEK_SET ) ); } /* End of __mpu_IO_file_seekpos_unlocked() */ /*************************************************************** Reposition STREAM using an off_t file position. ***************************************************************/ int mpu_fseeko( mpu_FILE *stream, off_t offset, int whence ) { off_t pos; if( !__mpu_IO_valid( stream ) ) return( -1 ); if( whence != MPU_SEEK_SET && whence != MPU_SEEK_CUR && whence != MPU_SEEK_END ) { errno = EINVAL; return( -1 ); } pthread_mutex_lock( &stream->_lock ); pos = __mpu_IO_seekoff_unlocked( stream, offset, whence ); pthread_mutex_unlock( &stream->_lock ); return( pos == (off_t)-1 ? -1 : 0 ); } /* End of mpu_fseeko() */ /*************************************************************** Reposition STREAM; compatibility entry point for mpu_fseeko(). ***************************************************************/ int mpu_fseek( mpu_FILE *stream, off_t offset, int whence ) { return( mpu_fseeko( stream, offset, whence ) ); } /* End of mpu_fseek() */ /*************************************************************** Return the current STREAM position as off_t. ***************************************************************/ off_t mpu_ftello( mpu_FILE *stream ) { off_t pos; if( !__mpu_IO_valid( stream ) ) return( (off_t)-1 ); if( __MPU_IO_JUMPS( stream ) == (const struct __mpu_IO_jump_t *)0 || __MPU_IO_JUMPS( stream )->tell == (off_t (*)(mpu_FILE *))0 ) { errno = ESPIPE; stream->_flags |= __MPU_IO_ERR_SEEN; return( (off_t)-1 ); } pthread_mutex_lock( &stream->_lock ); pos = (*__MPU_IO_JUMPS( stream )->tell)( stream ); pthread_mutex_unlock( &stream->_lock ); return( pos ); } /* End of mpu_ftello() */ /*************************************************************** Return the current STREAM position; compatibility wrapper. ***************************************************************/ off_t mpu_ftell( mpu_FILE *stream ) { return( mpu_ftello( stream ) ); } /* End of mpu_ftell() */ /*************************************************************** Save STREAM position and conversion state in POS. ***************************************************************/ int mpu_fgetpos( mpu_FILE *stream, mpu_fpos_t *pos ) { off_t current; if( pos == (mpu_fpos_t *)0 ) { errno = EINVAL; return( -1 ); } current = mpu_ftello( stream ); if( current == (off_t)-1 ) return( -1 ); pos->__pos = current; pos->__state = 0; return( 0 ); } /* End of mpu_fgetpos() */ /*************************************************************** Restore STREAM position and conversion state from POS. ***************************************************************/ int mpu_fsetpos( mpu_FILE *stream, const mpu_fpos_t *pos ) { if( pos == (const mpu_fpos_t *)0 ) { errno = EINVAL; return( -1 ); } /* UTF-8 is decoded as complete UCS-2 characters, so no shift state needs restoration in the current backend. Keep __state reserved in mpu_fpos_t for ABI-compatible future conversion state. */ return( mpu_fseeko( stream, pos->__pos, MPU_SEEK_SET ) ); } /* End of mpu_fsetpos() */ void mpu_rewind( mpu_FILE *stream ) { off_t pos; if( !__mpu_IO_valid( stream ) ) return; pthread_mutex_lock( &stream->_lock ); pos = __mpu_IO_seekoff_unlocked( stream, (off_t)0, MPU_SEEK_SET ); if( pos != (off_t)-1 ) mpu_clearerr_unlocked( stream ); pthread_mutex_unlock( &stream->_lock ); return; } /* End of mpu_rewind() */ int mpu_setvbuf( mpu_FILE *stream, unsigned char *buf, int mode, size_t size ) { int ret; if( !__mpu_IO_valid( stream ) ) return( -1 ); pthread_mutex_lock( &stream->_lock ); ret = __mpu_IO_setbuf_unlocked( stream, buf, mode, size ); pthread_mutex_unlock( &stream->_lock ); return( ret ); } /* End of mpu_setvbuf() */ void mpu_setbuf( mpu_FILE *stream, unsigned char *buf ) { if( buf == (unsigned char *)0 ) (void)mpu_setvbuf( stream, (unsigned char *)0, MPU_IONBF, 1 ); else (void)mpu_setvbuf( stream, buf, MPU_IOFBF, MPU_BUFSIZ ); return; } /* End of mpu_setbuf() */ int __mpu_IO_file_seek_unlocked( mpu_FILE *stream, off_t offset, int whence ) { off_t pos; if( __mpu_IO_file_flush_unlocked( stream ) == mpu_EOF ) return( -1 ); pos = lseek( stream->_fileno, offset, whence ); if( pos == (off_t)-1 ) { stream->_flags |= __MPU_IO_ERR_SEEN; return( -1 ); } stream->_unget_count = 0; stream->_flags &= ~(__MPU_IO_READING | __MPU_IO_WRITING | __MPU_IO_EOF_SEEN); stream->_read_base = stream->_buf_base; stream->_read_ptr = stream->_buf_base; stream->_read_end = stream->_buf_base; stream->_write_base = stream->_buf_base; stream->_write_ptr = stream->_buf_base; stream->_write_end = stream->_buf_end; return( 0 ); } /* End of __mpu_IO_file_seek_unlocked() */ off_t __mpu_IO_file_tell_unlocked( mpu_FILE *stream ) { off_t pos; pos = lseek( stream->_fileno, (off_t)0, SEEK_CUR ); if( pos != (off_t)-1 ) { if( stream->_flags & __MPU_IO_READING ) { unsigned int i; if( stream->_read_ptr != (unsigned char *)0 && stream->_read_end != (unsigned char *)0 ) pos -= (off_t)(stream->_read_end - stream->_read_ptr); /* Public/scanner pushback is UCS-2 while real-file positions are UTF-8 byte offsets. Account for the encoded width of every pending pushed-back character in the logical position. */ for( i = 0; i < stream->_unget_count; ++i ) { __mpu_uint32_t u = (__mpu_uint32_t)stream->_unget_chars[i]; pos -= (off_t)(u < 0x80U ? 1 : (u < 0x800U ? 2 : 3)); } } else if( stream->_flags & __MPU_IO_WRITING ) { if( stream->_write_base != (unsigned char *)0 && stream->_write_ptr != (unsigned char *)0 ) pos += (off_t)(stream->_write_ptr - stream->_write_base); } } else stream->_flags |= __MPU_IO_ERR_SEEN; return( pos ); } /* End of __mpu_IO_file_tell_unlocked() */ /*************************************************************** Select line buffering for STREAM using an internally allocated buffer. This is the LIBMPUIO counterpart of glibc setlinebuf(). ***************************************************************/ void mpu_setlinebuf( mpu_FILE *stream ) { (void)mpu_setvbuf( stream, (unsigned char *)0, MPU_IOLBF, MPU_BUFSIZ ); return; } /* End of mpu_setlinebuf() */ /*************************************************************** Hide internal symbols: ***************************************************************/ __mpu_hidden_decl(__mpu_IO_doallocbuf); __mpu_hidden_decl(__mpu_IO_file_finish_unlocked); __mpu_hidden_decl(__mpu_IO_file_flush_unlocked); __mpu_hidden_decl(__mpu_IO_file_get_byte_unlocked); __mpu_hidden_decl(__mpu_IO_file_overflow_unlocked); __mpu_hidden_decl(__mpu_IO_file_put_byte_unlocked); __mpu_hidden_decl(__mpu_IO_file_seek_unlocked); __mpu_hidden_decl(__mpu_IO_file_seekoff_unlocked); __mpu_hidden_decl(__mpu_IO_file_seekpos_unlocked); __mpu_hidden_decl(__mpu_IO_file_setbuf_unlocked); __mpu_hidden_decl(__mpu_IO_file_sync_input_unlocked); __mpu_hidden_decl(__mpu_IO_file_sync_unlocked); __mpu_hidden_decl(__mpu_IO_file_tell_unlocked); __mpu_hidden_decl(__mpu_IO_file_underflow_unlocked); __mpu_hidden_decl(__mpu_IO_file_xsgetn_unlocked); __mpu_hidden_decl(__mpu_IO_file_xsputn_unlocked); /* End of hide internal symbols. ***************************************************************/ /* End of mpu-buffer.c */