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 + -
显示快捷键?