if (fp->_IO_buf_base == NULL) { /* Maybe we already have a push back pointer. */ if (fp->_IO_save_base != NULL) { free(fp->_IO_save_base); fp->_flags &= ~_IO_IN_BACKUP; } _IO_doallocbuf(fp); }
while (want > 0) { have = fp->_IO_read_end - fp->_IO_read_ptr; if (want <= have) { memcpy(s, fp->_IO_read_ptr, want); fp->_IO_read_ptr += want; want = 0; } else { if (have > 0) { #ifdef _LIBC s = __mempcpy(s, fp->_IO_read_ptr, have); #else memcpy(s, fp->_IO_read_ptr, have); s += have; #endif want -= have; fp->_IO_read_ptr += have; }
/* Check for backup and repeat */ if (_IO_in_backup(fp)) { _IO_switch_to_main_get_area(fp); continue; }
/* If we now want less than a buffer, underflow and repeat the copy. Otherwise, _IO_SYSREAD directly to the user buffer. */ if (fp->_IO_buf_base && want < (size_t)(fp->_IO_buf_end - fp->_IO_buf_base)) { if (__underflow(fp) == EOF) break;
continue; }
/* These must be set before the sysread as we might longjmp out waiting for input. */ _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
/* Try to maintain alignment: read a whole number of blocks. */ count = want; if (fp->_IO_buf_base) { _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base; if (block_size >= 128) count -= want % block_size; }
int _IO_file_doallocate(_IO_FILE* fp) { _IO_size_t size; char* p; structstat64st;
#ifndef _LIBC /* If _IO_cleanup_registration_needed is non-zero, we should call the function it points to. This is to make sure _IO_cleanup gets called on exit. We call it from _IO_file_doallocate, since that is likely to get called by any program that does buffered I/O. */ if (__glibc_unlikely(_IO_cleanup_registration_needed != NULL)) (*_IO_cleanup_registration_needed) (); #endif
size = _IO_BUFSIZ; if (fp->_fileno >= 0 && __builtin_expect(_IO_SYSSTAT(fp, &st), 0) >= 0) { if (S_ISCHR(st.st_mode)) { /* Possibly a tty. */ if ( #ifdef DEV_TTY_P DEV_TTY_P(&st) || #endif local_isatty(fp->_fileno)) fp->_flags |= _IO_LINE_BUF; } #if _IO_HAVE_ST_BLKSIZE if (st.st_blksize > 0) size = st.st_blksize; #endif } p = malloc(size); if (__glibc_unlikely(p == NULL)) return EOF; _IO_setb(fp, p, p + size, 1); return1; } libc_hidden_def(_IO_file_doallocate)
_IO_new_file_underflow (_IO_FILE *fp) { _IO_ssize_t count; #if 0 /* SysV does not make this test; take it out for compatibility */ if (fp->_flags & _IO_EOF_SEEN) return (EOF); #endif
if (fp->_flags & _IO_NO_READS)//会先检测是否存在_IO_NO_READS标志, { fp->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); return EOF; } if (fp->_IO_read_ptr < fp->_IO_read_end)//检测输入缓冲区里存在数据
return *(unsignedchar *) fp->_IO_read_ptr;
if (fp->_IO_buf_base == NULL) { /* Maybe we already have a push back pointer. */ if (fp->_IO_save_base != NULL) { free (fp->_IO_save_base); fp->_flags &= ~_IO_IN_BACKUP; } _IO_doallocbuf (fp);//如果没有输入缓冲区,则再次调用_IO_doallocbuf分配输入缓冲区 }
/* Flush all line buffered files before reading. */ /* FIXME This can/should be moved to genops ?? */ if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) { #if 0 _IO_flush_all_linebuffered (); #else /* We used to flush all line-buffered stream. This really isn't required by any standard. My recollection is that traditional Unix systems did this for stdout. stderr better not be line buffered. So we do just that here explicitly. --drepper */ _IO_acquire_lock (_IO_stdout);
_IO_switch_to_get_mode (fp); /* This is very tricky. We have to adjust those pointers before we call _IO_SYSREAD () since we may longjump () out while waiting for input. Those pointers may be screwed up. H.J. */ fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; fp->_IO_read_end = fp->_IO_buf_base; fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_buf_base;
count = _IO_SYSREAD (fp, fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base); if (count <= 0) { if (count == 0) fp->_flags |= _IO_EOF_SEEN; else fp->_flags |= _IO_ERR_SEEN, count = 0; } fp->_IO_read_end += count; if (count == 0) { /* If a stream is read to EOF, the calling application may switch active handles. As a result, our offset cache would no longer be valid, so unset it. */ fp->_offset = _IO_pos_BAD; return EOF; } if (fp->_offset != _IO_pos_BAD) _IO_pos_adjust (fp->_offset, count); return *(unsignedchar *) fp->_IO_read_ptr; }