glibc/stdio/internals.c
Ulrich Drepper 9a0a462ceb Update.
1997-09-11 04:36  Ulrich Drepper  <drepper@cygnus.com>

	* db2/db_int.h: Define __set_errno if not yet available.
	* db2/btree/bt_rec.c: Use __set_errno to set errno value.
	* db2/clib/getlong.c: Likewise.
	* db2/db185/db185.c: Likewise.
	* db2/db185/db185_int.h: Likewise.
	* db2/dbm/dbm.c: Likewise.
	* db2/lock/lock_deadlock.c: Likewise.
	* db2/log/log_archive.c: Likewise.

	* elf/dl-profile.c: Implement mcount function.

	* gmon/gmon.c: Use __profil not profil because of namespace pollution.
	* gmon/mcount.c: Remove BSD kernel code.
	Use compare&swap instruction if possible to change state variable.
	Optimize frompc folding.
	* gmon/sys/gmon.h (struct gmonparam): Change state field to long int.
	* sysdeps/i386/i486/atomicity.h: New file.
	* sysdeps/stub/atomicity.h: New file.
	* sysdeps/mach/hurd/profil.c: Define function as __profil and make
	profil weak alias.
	* sysdeps/posix/profil.c: Likewise.

	* string/bits/string2.h: New file.
	* include/bits/string2.h: New file.
	* string/Makefile (routines): Add mempcpy.
	(tests): Add inl-tester.
	Remove _D__NO_STRING_INLINES from CFLAGS-* variables.
	* sysdeps/generic/mempcpy.c: New file.
	* sysdeps/generic/memccpy.c: Undef function name to enable definition
	as macro.
	* sysdeps/generic/memchr.c: Likewise.
	* sysdeps/generic/memcmp.c: Likewise.
	* sysdeps/generic/memmem.c: Likewise.
	* sysdeps/generic/memmove.c: Likewise.
	* sysdeps/generic/strcat.c: Likewise.
	* sysdeps/generic/strchr.c: Likewise.
	* sysdeps/generic/strcmp.c: Likewise.
	* sysdeps/generic/strcpy.c: Likewise.
	* sysdeps/generic/strcspn.c: Likewise.
	* sysdeps/generic/strlen.c: Likewise.
	* sysdeps/generic/strncat.c: Likewise.
	* sysdeps/generic/strncmp.c: Likewise.
	* sysdeps/generic/strncpy.c: Likewise.
	* sysdeps/generic/strpbrk.c: Likewise.
	* sysdeps/generic/strrchr.c: Likewise.
	* sysdeps/generic/strsep.c: Likewise.
	* sysdeps/generic/strspn.c: Likewise.
	* sysdeps/generic/strstr.c: Likewise.
	* sysdeps/generic/strtok.c: Likewise.
	* sysdeps/generic/strtok_r.c: Likewise.
	* sysdeps/i386/memset.c: Likewise.
	* sysdeps/i386/bits/string.h: Correct a few types and constraints.
	* sysdeps/i386/i486/bits/string.h: Heavy rewrites and optimizations.
	* string/stratcliff.c: Undefine __USE_STRING_INLINES.
	* string/tst-strlen.c: Likewise.
	* string/string.h: Add prototype for mempcpy.  Include bits/string2.h
	header always if optimizing.
	* intl/dcgettext.c: Don't unconditionally define stpcpy, only if not
	yet defined.
	* intl/l10nflist.c: Likewise.

	* string/tester.c: Add copyright and make little cleanups.

	* inet/test_ifindex.c: Change type of ni variable to unsigned int.

	* locale/programs/ld-ctype.c (struct locale_ctype_t): Change type
	of fields map_collection_max and map_collection_act to size_t.

	* nss/libnss_files.map: Group entries.

	* posix/unistd.h: Add prototype for __setpgid and __profil.

	* sysdeps/generic/crypt.h: Declare __crypt_r.

	* sysdeps/i386/bits/select.h: Fix fatal bugs, use correct casts now.

	* sysdeps/i386/fpu/bits/mathinline.h (isgreater, isgreaterequal,
	isless, islessequal, islessgreater, isunordered): Optimize a bit.

	* sysdeps/stub/ftruncate.c: Include missing header for prototype.
	* sysdeps/stub/getdents.c: Likewise.
	* sysdeps/stub/reboot.c: Likewise.
	* sysdeps/stub/swapon.c: Likewise.
	* sysdeps/stub/syscall.c: Likewise.
	* sysdeps/stub/ualarm.c: Likewise.
	* sysdeps/stub/usleep.c: Likewise.

	* sysdeps/unix/sysv/linux/if_index.c: Don't compile or use opensock
	if SIOGIFINDEX and SIOGIFNAME are not defined.

	* sysdeps/unix/sysv/linux/net/if.h: Add IFF_PORTSEL and IFF_AUTOMEDIA
	according to recent kernel changes.

1997-09-10 21:32  Klaus Espenlaub  <kespenla@student.informatik.uni-ulm.de>

	* Makeconfig: Use $(have-initfini) instead of $(elf) to figure out
	the installed name of the startup code.
	(common-generated): Add version.mk.
	* Makefile (distclean-1): Add glibcbug.
	* Makerules: Replace -lgcc by $(gnulib).
	* catgets/Makefile (generated): Add xmalloc.o.
	* csu/Makefile (generated): Replace align.h and end.h by defs.h to
	match the generated file.
	* manual/Makefile (mostlyclean): Add stub-manual and stamp.o.
	(realclean): Changed to remove chapters-incl[12].
	* po/Makefile (realclean): New rule to remove the generated .mo files.
	* time/Makefile: Only include zonefile dependencies if $(no_deps) is
	not true to avoid make clean failure when directory time doesn't exist
	yet.
	(generated): Add tzselect.

	* stdio/fgets.c (fgets): Add casts to reduce gcc warning noise.
	* stdio/internals.c (flushbuf): Likewise.
	* stdio/linewrap.c (lwupdate): Likewise.
	* stdio/memstream.c (enlarge_buffer): Likewise.
	* stdio-common/vfscanf.c (_IO_vfscanf): Likewise.
	* time/tzset.c (compute_change): Likewise.
	* misc/init-misc.c (__init_misc): Only declare static if HAVE_GNU_LD
	is defined.
	* sysdeps/posix/pipestream.c (FUNC): Change to generate ANSI C style
	functions.
	* sysdeps/stub/init-posix.c: Likewise.
	* sysdeps/stub/profil.c: Likewise.
	* munch-tmpl.c (__libc_init): Convert to ANSI C style declaration to
	reduce gcc warning noise.
	* stdio/glue.c (_filbuf, _flsbuf): Likewise.
	* stdio/obstream.c (grow, seek, input, init_obstream): Likewise.
	* stdio/vasprintf.c (enlarge_buffer): Likewise.
	* sysdeps/generic/sysd-stdio.c (__stdio_read, __stdio_write,
	__stdio_seek, __stdio_close, __stdio_fileno, __stdio_open,
	__stdio_reopen): Likewise.
	* sysdeps/posix/defs.c (_cleanup): Likewise.
	* time/offtime.c (__offtime): Add cast.

	* posix/getopt.c: Don't use text_set_element if not defined.

	* configure.in: Provide a check for underscores before user labels
	that works even when the compiler used for building doesn't work
	(like when there is no C library).  Use the old way if the compiler
	works.

1997-09-10 05:08  David S. Miller  <davem@caip.rutgers.edu>

	* sysdeps/unix/sysv/linux/sparc/bits/ioctls.h: The TC* ioctls use
	'T' not 't' on SparcLinux.
	* sysdeps/unix/sysv/linux/sparc/bits/termios.h: tcflag_t is 32 bits.

	* sysdeps/unix/sysv/linux/sparc/sparc64/longjmp.S: Add aliases for
	_longjmp and siglongjmp.

1997-09-09  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* libio/stdio.h: Add format attributes to the extra printf and
	scanf like functions.
	* stdio/stdio.h: Likewise.

1997-09-09  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* nis/nss_nisplus/nisplus-network.c (_nss_nisplus_getnetbyaddr_r):
	Print tablename_val, not tablename_len.

	* nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_getntohost_r):
	Use sprintf instead of sprintf, the string always fits.
	* nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_gethostbyaddr_r):
	Likewise.
	* nis/nss_nisplus/nisplus-network.c (_nss_nisplus_getnetbyaddr_r):
	Likewise.
	* nis/nss_nisplus/nisplus-proto.c
	(_nss_nisplus_getprotobynumber_r): Likewise.
	* nis/nss_nisplus/nisplus-rpc.c (_nss_nisplus_getrpcbynumber_r):
	Likewise.
	* nis/nss_nisplus/nisplus-service.c
	(_nss_nisplus_getservbynumber_r): Likewise.

	* nis/nss_nisplus/nisplus-alias.c (_nss_create_tablename): Use
	__stpcpy, __stpncpy and __strdup instead of public names.
	* nis/nss_nisplus/nisplus-ethers.c (_nss_create_tablename):
	Likewise.
	* nis/nss_nisplus/nisplus-grp.c (_nss_create_tablename): Likewise.
	* nis/nss_nisplus/nisplus-hosts.c (_nss_create_tablename):
	Likewise.
	* nis/nss_nisplus/nisplus-netgrp.c (_nss_nisplus_parse_netgroup):
	Likewise.
	* nis/nss_nisplus/nisplus-network.c (_nss_nisplus_parse_netent):
	Likewise.
	(_nss_create_tablename): Likewise.
	* nis/nss_nisplus/nisplus-proto.c (_nss_nisplus_parse_protoent):
	Likewise.
	(_nss_create_tablename): Likewise.
	* nis/nss_nisplus/nisplus-pwd.c (_nss_create_tablename):
	Likewise.
	* nis/nss_nisplus/nisplus-rpc.c (_nss_nisplus_parse_rpcent):
	Likewise.
	(_nss_create_tablename): Likewise.
	* nis/nss_nisplus/nisplus-service.c (_nss_nisplus_parse_servent):
	Likewise.
	(_nss_create_tablename): Likewise.
	* nis/nss_nisplus/nisplus-spwd.c (_nss_create_tablename):
	Likewise.

	* libc.map: Export __stpcpy and __strdup.

1997-09-09  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* math/Makefile (CFLAGS-test-float.c, CFLAGS-test-double.c,
	CFLAGS-test-ldouble.c): Pass -ffloat-store to avoid excessive
	precision.

1997-09-09  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* include/rpc/auth_des.h: New file.

1997-09-09  Paul Eggert  <eggert@twinsun.com>

	* time/mktime.c (__mktime_internal): Declare sec_requested even if
	!LEAP_SECONDS_POSSIBLE, since it's needed at the end when checking
	for time_t overflow.

1997-09-09 22:11  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/posix/getcwd.c: Correct test for too small buffer.
	Reported by Erik Troan <ewt@redhat.com>.

	* elf/dl-close.c: Include <bits/libc-lock.h>, not <libc-lock.h>.
	* elf/dl-open.c: Likewise.

1997-09-07 17:09  Richard Henderson  <rth@cygnus.com>

	* sysdeps/alpha/Makefile: Kill setjmp_aux.
	* sysdeps/alpha/bits/setjmp.h: Rewrite in terms of an array.
	* sysdeps/alpha/__longjmp.c: Remove.
	* sysdeps/alpha/setjmp_aux.c: Remove.
	* sysdeps/alpha/__longjmp.S: New file.
	* sysdeps/alpha/bsd-_setjmp.S: Stub out.
	* sysdeps/alpha/bsd-setjmp.S: Likewise.
	* sysdeps/alpha/setjmp.S: Do the work; don't call __setjmp_aux.
	Move _setjmp and setjmp from bsd-*.S.

1997-09-06  20:20  Ulrich Drepper  <drepper@cygnus.com>

	* include/rpc/auth.h: New file.
	* include/rpc/auth_unix.h: New file.

1997-09-06  Paul Eggert  <eggert@twinsun.com>

	Fix gmtime so that it reports leap seconds when TZ
	indicates that leap seconds are desired.

	* time/gmtime.c (<stddef.h>): Remove unnecessary include.
	(gmtime): Put after gmtime_r, to help the compiler inline.
	(__tz_convert): New decl.
	(gmtime_r): Use __tz_convert instead of __offtime,
	so that leap seconds are handled correctly.

	* time/localtime.c (<errno.h>, <libc-lock.h>): Remove includes that
	are now unnecessary.
	(__tzset_internal, __tz_compute, __tzfile_compute, __use_tzfile,
	__tzset_lock): Remove extern decls that are now unnecessary.
	(localtime_internal): Moved to __tz_convert in tzset.c.
	so that localtime and gmtime can both use it easily.
	(localtime): Put after localtime_r, to help the compiler inline.
	(localtime_r): Use __tz_convert instead of localtime_internal.

	* time/strftime.c (__tz_compute): Remove unused (and now incorrect)
	decl.

	* time/tzfile.c (__tzfile_compute): New arg USE_LOCALTIME.

	* time/tzset.c (<errno.h>): Include.
	(_tmbuf): New decl.
	(__tzfile_compute): New function.
	(tz_compute): Renamed from __tz_compute.  No longer extern.
	Remove redundant call to tzset_internal.
	(tzset_internal): Renamed from __tzset_internal.  No longer extern.
	(tzset_lock): Renamed from __tzset_lock.  No longer extern.
	(__tz_convert): New function, containing functionality of old
	localtime_internal function, plus locking and optional UTC.

1997-09-06  Paul Eggert  <eggert@twinsun.com>

	* time/tzfile.c (__tzfile_read): Don't read a file if TZ is the empty
	string, just use UTC without leap seconds.  This is for compatibility
	with the Olson code.

1997-09-06  Paul Eggert  <eggert@twinsun.com>

	* time/tzset.c (__tzname_max): Lock tz data structures before
	invoking tzset_internal.

	* time/tzfile.c: Define compute_tzname_max statically.

1997-09-07 10:57  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* nis/nis_call.c: Remove not longer necessary HAVE_SECURE_RPC ifdefs.
	* nis/nis_intern.h: Likewise.
	* nis/nss_nis/nis-publickey.c: Likewise.
	* nis/nss_nisplus/nisplus-publickey.c: Likewise.
	* nis/ypclnt.c: Likewise.

	* sunrpc/auth_des.c: Don't dereference NULL pointer,
	initialize ad->ad_timediff.

	* sunrpc/auth_none.c: Don't define our own prototypes, use the one
	from the header files.
	* sunrpc/auth_unix.c: Likewise.
	* sunrpc/clnt_raw.c: Likewise.
	* sunrpc/clnt_tcp.c: Likewise.
	* sunrpc/rpc_cmsg.c: Likewise.

	* sunrpc/key_call.c: Fix signal handling.

	* sunrpc/openchild.c: Don't use /bin/sh to start /usr/etc/keyenvoy,
	or we will get a deadlock with NIS+.

	* sunrpc/rpc/auth.h: Add prototype for xdr_opaque_auth, don't define
	HAVE_SECURE_RPC.

1997-09-07 15:51  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/i386/bits/select.h [__GNUC__] (__FD_ZERO, __FD_SET, __FD_CLR,
	__FD_ISSET): Use correct casts to address array correctly.
	Reported by urbanw@cs.umu.se.

1997-09-07 05:07  Ulrich Drepper  <drepper@cygnus.com>

	* elf/dl-close.c: Include <bits/libc-lock.h>, not <libc-lock.h>.
	* elf/dl-open.c: Likewise.
	* sysdeps/i386/memset.c: Undefine memset in case the header with the
	optimized functions is included.
	Patches by NIIBE Yutaka <gniibe@mri.co.jp>.

	* sysdeps/i386/bits/string.h [__PIC__] (strcspn, strspn, strpbrk,
	strsep): Use register for second parameter.
	* sysdeps/i386/i486/bits/string.h: Likewise.
	Reported by NIIBE Yutaka <gniibe@mri.co.jp>.

1997-09-03 09:48  Geoff Keating  <geoffk@ozemail.com.au>

	* math/libm-test.c: Change various tolerances to match what the
	tested routines can actually provide.

	* math/Makefile: Add new tests.
	* math/atest-sincos.c: New file.
	* math/atest-exp.c: New file.

	* csu/Makefile: Give initfini.s and initfiniS.s their own
	CFLAGS-* macros so they can be overridden.
	* sysdeps/powerpc/Makefile [subdir=csu]: Override flags for
	initfiniS.s to use -fpic instead of -fPIC, because the sed script
	breaks otherwise.

	* sysdeps/powerpc/Makefile [build-shared]: Use -fpic not -fPIC for
	efficiency.

	* sysdeps/powerpc/dl-machine.h (ELF_MACHINE_RUNTIME_TRAMPOLINE):
	Don't use register 0, to let _mcount be in a shared object.

	* sysdeps/powerpc/dl-machine.h: Use full sentences in comments.
	Generally clean up.  Suppress some code we don't need when relocating
	ld.so.
	* sysdeps/powerpc/test-arith.c: Change loop indices to size_t when
	appropriate to suppress gcc warning.
	* resolv/res_send.c: Suppress warning.
	* sunrpc/xdr_sizeof.c: Suppress warning.

	* FAQ: Add ppc-linux.
	* manual/maint.texi: Add ppc-linux.  Explain that gcc can't build it
	yet.

	* sysdeps/unix/sysv/linux/powerpc/profil-counter.h: Correct for
	current kernels.

1997-08-15 07:45  Geoff Keating  <geoffk@ozemail.com.au>

	* stdlib/fmtmsg.c: Use two parameters for __libc_once_define.
	* sysdeps/i386/machine-gmon.h: Correct typo.

	* sysdeps/unix/sysv/linux/powerpc/bits/mman.h: Change to match
	kernel.

	* sysdeps/generic/dl-sysdep.c: Add hook for bizzare PPC argument hack.
	* sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c: Rewrite to use
	sysdeps/linux/dl-sysdep.c.

	* sysdeps/powerpc/Makefile [subdir=gmon]: Compile ppc-mcount.
	* sysdeps/powerpc/machine-gmon.h: Use ppc-mcount.
	* sysdeps/powerpc/ppc-mcount: New file.

	The following are mostly changes to allow profiling:
	* sysdeps/powerpc/add_n.S: Added.
	* sysdeps/powerpc/add_n.s: Removed.
	* sysdeps/powerpc/addmul_1.S: Added.
	* sysdeps/powerpc/addmul_1.s: Removed.
	* sysdeps/powerpc/bsd-_setjmp.S: Use JUMPTARGET macro.
	* sysdeps/powerpc/bsd-setjmp.S: Use JUMPTARGET macro.
	* sysdeps/powerpc/lshift.S: Added.
	* sysdeps/powerpc/lshift.s: Removed.
	* sysdeps/powerpc/memset.S: Added.
	* sysdeps/powerpc/memset.s: Removed.
	* sysdeps/powerpc/mul_1.S: Added.
	* sysdeps/powerpc/mul_1.s: Removed.
	* sysdeps/powerpc/rshift.S: Added.
	* sysdeps/powerpc/rshift.s: Removed.
	* sysdeps/powerpc/s_copysign.S: Use ENTRY, END, weak_alias macros.
	* sysdeps/powerpc/s_fabs.S: Use ENTRY, END, weak_alias macros.
	* sysdeps/powerpc/setjmp.S: Use JUMPTARGET macro.
	* sysdeps/powerpc/strchr.S: Added.
	* sysdeps/powerpc/strchr.s: Removed.
	* sysdeps/powerpc/strcmp.S: Added.
	* sysdeps/powerpc/strcmp.s: Removed.
	* sysdeps/powerpc/strlen.S: Added.
	* sysdeps/powerpc/strlen.s: Removed.
	* sysdeps/powerpc/sub_n.S: Added.
	* sysdeps/powerpc/sub_n.s: Removed.
	* sysdeps/powerpc/submul_1.S: Added.
	* sysdeps/powerpc/submul_1.s: Removed.
	* sysdeps/unix/sysv/linux/powerpc/_exit.S: Removed.
	* sysdeps/unix/sysv/linux/powerpc/brk.S: Added.
	* sysdeps/unix/sysv/linux/powerpc/brk.c: Removed.
	* sysdeps/unix/sysv/linux/powerpc/clone.S: Use new macros. Fix
	various bugs. Document that it isn't tested.
	* sysdeps/unix/sysv/linux/powerpc/sigreturn.S: Make look like
	sysdeps/unix/_exit.S.
	* sysdeps/unix/sysv/linux/powerpc/socket.S: Use new macros.
	* sysdeps/unix/sysv/linux/powerpc/syscall.S: Use new macros.
	* sysdeps/unix/sysv/linux/powerpc/sysdep.h: Define some new macros
	to make assembler (possibly) more portable, allow profiling, etc.
1997-09-11 12:09:10 +00:00

689 lines
19 KiB
C

/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Make sure that FP has its functions set. */
void
__stdio_check_funcs (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 __stdio_init_stream __P ((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 void
init_stream (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;
}
__set_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. */
int
__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. */
__set_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 void
seek_to_target (FILE *fp)
{
int save = errno;
if (__stdio_check_offset (fp) == EOF)
{
if (errno == ESPIPE)
__set_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! */
__set_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!
This should never happen. */
#ifdef EGRATUITOUS
/* It happens in the Hurd when the io server doesn't
obey the protocol for io_seek. */
__set_errno (EGRATUITOUS);
#else
/* I don't think this can happen in Unix. */
__set_errno (ESPIPE); /* ??? */
#endif
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 void
flushbuf (register FILE *fp, 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 (fp->__target == -1)
/* For an unseekable object, data recently read bears no relation
to data we will write later. Discard the buffer. */
fp->__get_limit = fp->__buffer;
else
/* 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);
__set_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 ((size_t) (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 ((size_t) (fp->__bufp - fp->__buffer) <= buffer_offset && flush_only)
{
/* There is nothing new in the buffer, only data that
was read back aligned from the file. */
buffer_written = 0;
goto end;
}
}
/* 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;
if (fp->__offset != -1)
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 if (fp->__offset != -1)
/* 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. */
char cc = (unsigned char) c;
if ((*fp->__io_funcs.__write)(fp->__cookie, &cc, 1) < 1)
fp->__error = 1;
else if (fp->__offset != -1)
{
/* Record that we've moved forward in the file. */
++fp->__offset;
++fp->__target;
}
}
else
/* Just put C in the buffer. */
*fp->__bufp++ = (unsigned char) c;
}
end:
if (!twiddled)
{
if (fp->__target != -1)
/* The new target position moves up as
much as the user wrote into the buffer. */
fp->__target += buffer_written;
/* Set the reading limit to the beginning of the buffer,
so the next `getc' will call __fillbf. */
fp->__get_limit = fp->__buffer;
}
if (feof (fp) || ferror (fp))
fp->__bufp = fp->__put_limit;
}
/* Fill the buffer for FP and return the first character read (or EOF).
This is the default `input_room' function. */
static int
fillbuf (register FILE *fp)
{
/* How far into the buffer we read we want to start bufp. */
size_t buffer_offset = 0;
register char *buffer;
register size_t to_read, nread = 0;
/* This must be unsigned to avoid sign extension in return. */
unsigned char c;
if (fp->__io_funcs.__read == NULL)
{
/* There is no read function, so always return EOF. */
fp->__eof = 1;
goto end;
}
if (fp->__buffer == NULL)
{
/* We're unbuffered, so we want to read only one character. */
buffer = (char *) &c;
to_read = 1;
}
else
{
/* We're buffered, so try to fill the buffer. */
buffer = fp->__buffer;
to_read = fp->__bufsize;
}
/* We're reading, so we're not at the end-of-file. */
fp->__eof = 0;
/* Go to the target file position. */
{
int save = errno;
if (__stdio_check_offset (fp) == 0 && fp->__target != fp->__offset)
{
/* Move to a block (buffer size) boundary. */
if (fp->__bufsize != 0)
{
buffer_offset = fp->__target % fp->__bufsize;
fp->__target -= buffer_offset;
}
seek_to_target (fp);
}
__set_errno (save);
}
while (!ferror (fp) && !feof (fp) && nread <= buffer_offset)
{
/* Try to fill the buffer. */
int count = (*fp->__io_funcs.__read) (fp->__cookie, buffer, to_read);
if (count == 0)
fp->__eof = 1;
else if (count < 0)
fp->__error = 1;
else
{
buffer += count;
nread += count;
to_read -= count;
if (fp->__offset != -1)
/* Record that we've moved forward in the file. */
fp->__offset += count;
}
}
if (fp->__buffer == NULL)
/* There is no buffer, so return the character we read
without all the buffer pointer diddling. */
return (feof (fp) || ferror (fp)) ? EOF : c;
/* Reset the buffer pointer to the beginning of the buffer
(plus whatever offset we may have set above). */
fp->__bufp = fp->__buffer + buffer_offset;
end:;
if (feof (fp) || ferror (fp))
{
/* Set both end pointers to the beginning of the buffer so
the next i/o call will force a call to __fillbf/__flshfp. */
fp->__put_limit = fp->__get_limit = fp->__buffer;
return EOF;
}
/* Set the end pointer to one past the last character we read. */
fp->__get_limit = fp->__buffer + nread;
/* Make it so the next `putc' will call __flshfp. */
fp->__put_limit = fp->__buffer;
/* Return the first character in the buffer. */
return *((unsigned char *) (fp->__bufp++));
}
/* Default I/O and room functions. */
extern __io_read_fn __stdio_read;
extern __io_write_fn __stdio_write;
extern __io_seek_fn __stdio_seek;
extern __io_close_fn __stdio_close;
extern __io_fileno_fn __stdio_fileno;
const __io_functions __default_io_functions =
{
__stdio_read, __stdio_write, __stdio_seek, __stdio_close, __stdio_fileno
};
const __room_functions __default_room_functions =
{
fillbuf, flushbuf
};
/* Flush the buffer for FP and also write C if FLUSH_ONLY is nonzero.
This is the function used by putc and fflush. */
int
__flshfp (fp, c)
register FILE *fp;
int c;
{
int flush_only = c == EOF;
if (!__validfp (fp) || !fp->__mode.__write)
{
__set_errno (EINVAL);
return EOF;
}
if (ferror (fp))
return EOF;
if (fp->__pushed_back)
{
/* Discard the char pushed back by ungetc. */
fp->__bufp = fp->__pushback_bufp;
fp->__pushed_back = 0;
}
/* Make sure the stream is initialized (has functions and buffering). */
init_stream (fp);
/* Do this early, so a `putc' on such a stream will never return success. */
if (fp->__room_funcs.__output == NULL)
{
/* A NULL `output room' function means
to always return an output error. */
fp->__error = 1;
return EOF;
}
if (!flush_only &&
/* Will C fit into the buffer?
See below about linebuf_active. */
fp->__bufp < (fp->__linebuf_active ? fp->__buffer + fp->__bufsize :
fp->__put_limit))
{
/* The character will fit in the buffer, so put it there. */
*fp->__bufp++ = (unsigned char) c;
if (fp->__linebuf && (unsigned char) c == '\n')
flush_only = 1;
else
return (unsigned char) c;
}
if (fp->__linebuf_active)
/* This is an active line-buffered stream, so its put-limit is set
to the beginning of the buffer in order to force a __flshfp call
on each putc (see below). We undo this hack here (by setting
the limit to the end of the buffer) to simplify the interface
with the output-room function. */
fp->__put_limit = fp->__buffer + fp->__bufsize;
/* Make room in the buffer. */
(*fp->__room_funcs.__output) (fp, flush_only ? EOF : (unsigned char) c);
if (fp->__linebuf)
{
/* This is a line-buffered stream, and it is now ready to do
some output. We call this an "active line-buffered stream".
We set the put_limit to the beginning of the buffer,
so the next `putc' call will force a call to this function.
Setting the linebuf_active flag tells the code above
(on the next call) to undo this hackery. */
fp->__put_limit = fp->__buffer;
fp->__linebuf_active = 1;
}
if (ferror (fp))
return EOF;
if (flush_only)
return 0;
return (unsigned char) c;
}
/* Fill the buffer for FP and return the first character read.
This is the function used by getc. */
int
__fillbf (fp)
register FILE *fp;
{
register int c;
fpos_t new_target;
if (!__validfp (fp) || !fp->__mode.__read)
{
__set_errno (EINVAL);
return EOF;
}
if (fp->__pushed_back)
{
/* Return the char pushed back by ungetc. */
fp->__bufp = fp->__pushback_bufp;
fp->__pushed_back = 0;
return fp->__pushback;
}
/* Make sure the stream is initialized (has functions and buffering). */
init_stream (fp);
/* If we're trying to read the first character of a new
line of input from an unbuffered or line buffered stream,
we must flush all line-buffered output streams. */
if (fp->__buffer == NULL || fp->__linebuf)
{
register FILE *f;
for (f = __stdio_head; f != NULL; f = f->__next)
if (__validfp (f) && f->__linebuf && f->__mode.__write)
(void) __flshfp (f, EOF);
}
/* Note we must do this after flushing all line-buffered
streams, or else __flshfp would undo it! */
if (fp->__linebuf_active)
{
/* This is an active line-buffered stream, meaning it is in the midst
of writing, but has a bogus put_limit. Restore it to normality. */
fp->__put_limit = fp->__buffer + fp->__bufsize;
fp->__linebuf_active = 0;
}
/* We want the beginning of the buffer to now
map to just past the last data we read. */
new_target = fp->__target + (fp->__get_limit - fp->__buffer);
if (fp->__put_limit > fp->__buffer)
{
/* There is written data in the buffer.
Flush it out. */
if (fp->__room_funcs.__output == NULL)
fp->__error = 1;
else
(*fp->__room_funcs.__output) (fp, EOF);
}
fp->__target = new_target;
if (ferror (fp))
c = EOF;
else if (fp->__room_funcs.__input != NULL)
{
c = (*fp->__room_funcs.__input) (fp);
if (fp->__buffer == NULL)
/* This is an unbuffered stream, so the target sync above
won't do anything the next time around. Instead, note that
we have read one character. The (nonexistent) buffer now
maps to the position just past that character. */
++fp->__target;
}
else
{
/* A NULL `input_room' function means always return EOF. */
fp->__eof = 1;
c = EOF;
}
return c;
}
/* Nuke a stream, but don't kill its link in the chain. */
void
__invalidate (stream)
register FILE *stream;
{
/* Save its link. */
register FILE *next = stream->__next;
/* Pulverize the deceased. */
memset((void *) stream, 0, sizeof(FILE));
/* Restore the deceased's link. */
stream->__next = next;
}