/* First figure out how much space is available in the buffer. */ count = f->_IO_write_end - f->_IO_write_ptr; /* 判断输出缓冲区还有多少空间 */ if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) { count = f->_IO_buf_end - f->_IO_write_ptr; /* 判断输出缓冲区还有多少空间 */ if (count >= n) /* 输出缓冲区够用 */ { registerconstchar *p; for (p = s + n; p > s; ) { if (*--p == '\n') { count = p - s + 1; /* 重新调整输出缓冲区的可用size */ must_flush = 1; break; } } } } /* Then fill the buffer. */ if (count > 0) /* 如果输出缓冲区有空间,则先把数据拷贝至输出缓冲区 */ { if (count > to_do) count = to_do; if (count > 20) { #ifdef _LIBC f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count); #else memcpy (f->_IO_write_ptr, s, count); /* 将目标输出数据拷贝至输出缓冲区 */ f->_IO_write_ptr += count; #endif s += count; /* 计算是否还有目标输出数据剩余 */ } else { registerchar *p = f->_IO_write_ptr; registerint i = (int) count; while (--i >= 0) *p++ = *s++; f->_IO_write_ptr = p; } to_do -= count; /* 计算是否还有目标输出数据剩余 */ } if (to_do + must_flush > 0) /* 如果还有目标数据剩余,此时则表明输出缓冲区未建立或输出缓冲区已经满了 */ { _IO_size_t block_size, do_write; /* Next flush the (full) buffer. */ if (_IO_OVERFLOW (f, EOF) == EOF) return n - to_do;
/* Try to maintain alignment: write a whole number of blocks. dont_write is what gets left over. */ block_size = f->_IO_buf_end - f->_IO_buf_base; /* 检查输出数据是否是大块 */ do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
if (do_write) { count = new_do_write (f, s, do_write); to_do -= count; if (count < do_write) return n - to_do; }
/* Now write out the remainder. Normally, this will fit in the buffer, but it's somewhat messier for line-buffered files, so we let _IO_default_xsputn handle the general case. */ if (to_do) to_do -= _IO_default_xsputn (f, s+do_write, to_do); } return n - to_do; }
int _IO_new_file_overflow (f, ch) _IO_FILE *f; int ch; { if (f->_flags & _IO_NO_WRITES) /* 检测IO_FILE的_flags是否包含_IO_NO_WRITES标志位 */ { f->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); return EOF; }
if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == 0) { if (f->_IO_write_base == 0) /* 表明输出缓冲区尚未建立 */ { _IO_doallocbuf (f); /* 调用_IO_doallocbuf函数去分配输出缓冲区 */ _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); } /* Otherwise must be currently reading. If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end, logically slide the buffer forwards one block (by setting the read pointers to all point at the beginning of the block). This makes room for subsequent output. Otherwise, set the read pointers to _IO_read_end (leaving that alone, so it can continue to correspond to the external position). */ if (f->_IO_read_ptr == f->_IO_buf_end) /* 初始化其他指针 */ f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; f->_IO_write_ptr = f->_IO_read_ptr; f->_IO_write_base = f->_IO_write_ptr; f->_IO_write_end = f->_IO_buf_end; f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
f->_flags |= _IO_CURRENTLY_PUTTING; if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) f->_IO_write_end = f->_IO_write_ptr; } if (ch == EOF) return _IO_new_do_write(f, f->_IO_write_base, f->_IO_write_ptr - f->_IO_write_base); /* 执行_IO_new_do_write,利用系统调用write输出输出缓冲区 */ if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */ if (_IO_do_flush (f) == EOF) return EOF; *f->_IO_write_ptr++ = ch; if ((f->_flags & _IO_UNBUFFERED) || ((f->_flags & _IO_LINE_BUF) && ch == '\n')) if (_IO_new_do_write(f, f->_IO_write_base, f->_IO_write_ptr - f->_IO_write_base) == EOF) return EOF; return (unsignedchar) ch; }
/* Now write out the remainder. Normally, this will fit in the buffer, but it's somewhat messier for line-buffered files, so we let _IO_default_xsputn handle the general case. */ if (to_do) to_do -= _IO_default_xsputn (f, s+do_write, to_do); }