internals.c
来自「一个C源代码分析器」· C语言 代码 · 共 660 行 · 第 1/2 页
C
660 行
/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.This file is part of the GNU C Library.The GNU C Library is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General Public License aspublished by the Free Software Foundation; either version 2 of theLicense, or (at your option) any later version.The GNU C Library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULibrary General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with the GNU C Library; see the file COPYING.LIB. Ifnot, write to the Free Software Foundation, Inc., 675 Mass Ave,Cambridge, MA 02139, USA. */#include <ansidecl.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>/* Make sure that FP has its functions set. */voidDEFUN(__stdio_check_funcs, (fp), register FILE *fp){ if (!fp->__seen) { /* Initialize the stream's info, including buffering info. This may give a buffer, change I/O functions, etc. If no buffer is set (and the stream is not made explicitly unbuffered), we allocate a buffer below, using the bufsize set by this function. */ extern void EXFUN(__stdio_init_stream, (FILE *)); fp->__room_funcs = __default_room_functions; fp->__io_funcs = __default_io_functions; __stdio_init_stream (fp); fp->__seen = 1; }}/* Minimum size of a buffer we will allocate by default. If this much memory is not available, the stream in question will be made unbuffered instead. */#define MIN_BUFSIZE 128/* Figure out what kind of buffering (none, line, or full) and what buffer size to give FP. */static voidDEFUN(init_stream, (fp), register FILE *fp){ __stdio_check_funcs (fp); if (fp->__buffer == NULL && !fp->__userbuf) { int save; if (fp->__bufsize == 0) fp->__bufsize = BUFSIZ; /* Try to get however many bytes of buffering __stdio_pickbuf specified, but if that much memory isn't available, try half as much each time until it succeeds or the buffer size becomes too small to be useful. */ save = errno; while (fp->__bufsize >= MIN_BUFSIZE) { fp->__buffer = (char *) malloc(fp->__bufsize); if (fp->__buffer == NULL) fp->__bufsize /= 2; else break; } errno = save; if (fp->__buffer == NULL) { /* We can't get space for the buffer, so make it unbuffered. */ fp->__userbuf = 1; fp->__bufsize = 0; } } if (fp->__bufp == NULL) { /* Set the buffer pointer to the beginning of the buffer. */ fp->__bufp = fp->__buffer; fp->__put_limit = fp->__get_limit = fp->__buffer; }}/* Determine the current file position of STREAM if it is unknown. */intDEFUN(__stdio_check_offset, (stream), FILE *stream){ init_stream (stream); if (stream->__offset == (fpos_t) -1) { /* This stream's offset is unknown or unknowable. */ if (stream->__io_funcs.__seek == NULL) { /* Unknowable. */ errno = ESPIPE; return EOF; } else { /* Unknown. Find it out. */ fpos_t pos = (fpos_t) 0; if ((*stream->__io_funcs.__seek)(stream->__cookie, &pos, SEEK_CUR) < 0) { if (errno == ESPIPE) /* Object is incapable of seeking. */ stream->__io_funcs.__seek = NULL; return EOF; } stream->__offset = pos; } } if (stream->__target == (fpos_t) -1) /* This stream was opened on an existing object with an unknown file position. The position is now known. Make this the target position. */ stream->__target = stream->__offset; return 0;}/* Move FP's file position to its target file position, seeking as necessary and updating its `offset' field. Sets ferror(FP) (and possibly errno) for errors. */static voidDEFUN(seek_to_target, (fp), FILE *fp){ int save = errno; if (__stdio_check_offset (fp) == EOF) { if (errno == ESPIPE) errno = save; else fp->__error = 1; } else if (fp->__target != fp->__offset) { /* We are not at the target file position. Seek to that position. */ if (fp->__io_funcs.__seek == NULL) { /* We can't seek! */ errno = ESPIPE; fp->__error = 1; } else { fpos_t pos = fp->__target; if ((*fp->__io_funcs.__seek)(fp->__cookie, &pos, SEEK_SET) < 0) /* Seek failed! */ fp->__error = 1; else { fp->__offset = pos; if (pos != fp->__target) /* Seek didn't go to the right place! */ fp->__error = 1; } } }}/* Flush the buffer for FP. If C is not EOF, it is also to be written. If the stream is line buffered and C is a newline, it is written to the output, otherwise it is put in the buffer after it has been flushed to avoid a system call for a single character. This is the default `output room' function. */static voidDEFUN(flushbuf, (fp, c), register FILE *fp AND int c){ int flush_only = c == EOF; size_t buffer_written; size_t to_write; /* Set if target and get_limit have already been twiddled appropriately. */ int twiddled = 0; if (fp->__put_limit == fp->__buffer) { /* The stream needs to be primed for writing. */ size_t buffer_offset = 0; /* If the user has read some of the buffer, the target position is incremented for each character he has read. */ fp->__target += fp->__bufp - fp->__buffer; if (fp->__mode.__read && fp->__room_funcs.__input != NULL && !fp->__mode.__append) { int save = errno; CONST int aligned = (fp->__buffer == NULL || __stdio_check_offset(fp) == EOF || fp->__target % fp->__bufsize == 0); errno = save; if (!aligned) { /* Move to a block (buffer size) boundary and read in a block. Then the output will be written as a whole block, too. */ CONST size_t o = fp->__target % fp->__bufsize; fp->__target -= o; if ((*fp->__room_funcs.__input)(fp) == EOF && ferror(fp)) return; else __clearerr(fp); if (fp->__get_limit - fp->__buffer < o) /* Oops. We didn't read enough (probably because we got EOF). Forget we even mentioned it. */ fp->__target += o; else /* Start bufp as far into the buffer as we were into this block before we read it. */ buffer_offset = o; } /* The target position is now set to where the beginning of the buffer maps to; and the get_limit was set by the input-room function. */ twiddled = 1; } if (fp->__buffer != NULL) { /* Set up to write output into the buffer. */ fp->__put_limit = fp->__buffer + fp->__bufsize; fp->__bufp = fp->__buffer + buffer_offset; if (!flush_only) { /* Put C in the buffer to be written out. We only need to actually write it out now if it is a newline on a line-buffered stream. */ *fp->__bufp++ = (unsigned char) c; if (!fp->__linebuf || (unsigned char) c != '\n') { /* There is no need to flush C from the buffer right now. Record that nothing was written from the buffer, and go do clean-up at end. */ buffer_written = 0; goto end; } else /* We put C in the buffer, so don't write it again later. */ flush_only = 1; } } } /* If there is read data in the buffer past what was written, write all of that as well. Otherwise, just write what has been written into the buffer. */ buffer_written = fp->__bufp - fp->__buffer; to_write = (buffer_written == 0 ? 0 : fp->__get_limit > fp->__bufp ? fp->__get_limit - fp->__buffer : buffer_written); if (fp->__io_funcs.__write == NULL || (to_write == 0 && flush_only)) { /* There is no writing function or we're coming from an fflush call with nothing in the buffer, so just say the buffer's been flushed, increment the file offset, and return. */ fp->__bufp = fp->__buffer; fp->__offset += to_write; goto end; } if (to_write > 0) { int wrote; /* Go to the target file position. Don't bother if appending; the write will just ignore the file position anyway. */ if (!fp->__mode.__append) seek_to_target (fp); if (!ferror(fp)) { /* Write out the buffered data. */ wrote = (*fp->__io_funcs.__write)(fp->__cookie, fp->__buffer, to_write); if (wrote > 0) { if (fp->__mode.__append) /* The write has written the data to the end of the file and updated the file position to after the data. Don't bother to find the current position; we can get it later if we need it. */ fp->__offset = fp->__target = -1; else /* Record that we've moved forward in the file. */ fp->__offset += wrote; } if (wrote < (int) to_write) /* The writing function should always write the whole buffer unless there is an error. */ fp->__error = 1; } } /* Reset the buffer pointer to the beginning of the buffer. */ fp->__bufp = fp->__buffer; /* If we're not just flushing, write the last character, C. */ if (!flush_only && !ferror(fp)) { if (fp->__buffer == NULL || (fp->__linebuf && (unsigned char) c == '\n')) { /* Either we're unbuffered, or we're line-buffered and C is a newline, so really write it out immediately. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?