More missing _unlocked <stdio.h> functions.
Also simplify trivial one-liners like perror/puts/fputs, and clean up fread/fwrite slightly. Fix perror to match POSIX. Add basic perror and *_unlocked tests. Bug: N/A Test: ran tests Change-Id: I63f83c8e0c15c3c4096509d17421ac331b6fc23d
This commit is contained in:
parent
e379a20250
commit
37ad959783
22 changed files with 382 additions and 665 deletions
|
@ -10,6 +10,7 @@ New libc functions in P:
|
|||
* `__freading`/`__fwriting` (completing <stdio_ext.h>)
|
||||
* `endhostent`/endnetent`/`endprotoent`/`getnetent`/`getprotoent`/`sethostent`/`setnetent`/`setprotoent` (completing <netdb.h>)
|
||||
* `fexecve`
|
||||
* `fflush_unlocked`/`fgetc_unlocked`/`fgets_unlocked`/`fputc_unlocked`/`fputs_unlocked`/`fread_unlocked`/`fwrite_unlocked`
|
||||
* `getentropy`/`getrandom` (adding <sys/random.h>)
|
||||
* `getlogin_r`
|
||||
* `glob`/`globfree` (adding <glob.h>)
|
||||
|
|
|
@ -14,7 +14,6 @@ libc_common_src_files = [
|
|||
"bionic/siginterrupt.c",
|
||||
"bionic/sigsetmask.c",
|
||||
"stdio/fmemopen.cpp",
|
||||
"stdio/fread.cpp",
|
||||
"stdio/parsefloat.c",
|
||||
"stdio/refill.c",
|
||||
"stdio/stdio.cpp",
|
||||
|
@ -439,28 +438,22 @@ cc_library_static {
|
|||
"upstream-openbsd/lib/libc/net/ntohl.c",
|
||||
"upstream-openbsd/lib/libc/net/ntohs.c",
|
||||
"upstream-openbsd/lib/libc/net/res_random.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fflush.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fgetln.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fgets.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fgetwc.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fgetws.c",
|
||||
"upstream-openbsd/lib/libc/stdio/flags.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fpurge.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fputs.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fputwc.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fputws.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fvwrite.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fwalk.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fwide.c",
|
||||
"upstream-openbsd/lib/libc/stdio/fwrite.c",
|
||||
"upstream-openbsd/lib/libc/stdio/getdelim.c",
|
||||
"upstream-openbsd/lib/libc/stdio/gets.c",
|
||||
"upstream-openbsd/lib/libc/stdio/makebuf.c",
|
||||
"upstream-openbsd/lib/libc/stdio/mktemp.c",
|
||||
"upstream-openbsd/lib/libc/stdio/open_memstream.c",
|
||||
"upstream-openbsd/lib/libc/stdio/open_wmemstream.c",
|
||||
"upstream-openbsd/lib/libc/stdio/perror.c",
|
||||
"upstream-openbsd/lib/libc/stdio/puts.c",
|
||||
"upstream-openbsd/lib/libc/stdio/rget.c",
|
||||
"upstream-openbsd/lib/libc/stdio/setvbuf.c",
|
||||
"upstream-openbsd/lib/libc/stdio/tempnam.c",
|
||||
|
|
|
@ -256,7 +256,20 @@ int ferror_unlocked(FILE* __fp) __INTRODUCED_IN(23);
|
|||
int fileno_unlocked(FILE* __fp) __INTRODUCED_IN(24);
|
||||
#define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0)
|
||||
#define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0)
|
||||
#endif /* __USE_BSD */
|
||||
#endif
|
||||
|
||||
#if defined(__USE_BSD)
|
||||
int fflush_unlocked(FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
int fgetc_unlocked(FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
int fputc_unlocked(int __ch, FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
size_t fread_unlocked(void* __buf, size_t __size, size_t __count, FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
size_t fwrite_unlocked(const void* __buf, size_t __size, size_t __count, FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
#endif
|
||||
|
||||
#if defined(__USE_GNU)
|
||||
int fputs_unlocked(const char* __s, FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
char* fgets_unlocked(char* __buf, int __size, FILE* __fp) __INTRODUCED_IN_FUTURE;
|
||||
#endif
|
||||
|
||||
#if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
|
||||
#include <bits/fortify/stdio.h>
|
||||
|
|
|
@ -1326,6 +1326,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1246,6 +1246,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1351,6 +1351,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1310,6 +1310,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1246,6 +1246,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1308,6 +1308,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1246,6 +1246,13 @@ LIBC_P { # introduced=P
|
|||
endnetent;
|
||||
endprotoent;
|
||||
fexecve;
|
||||
fflush_unlocked;
|
||||
fgetc_unlocked;
|
||||
fgets_unlocked;
|
||||
fputc_unlocked;
|
||||
fputs_unlocked;
|
||||
fread_unlocked;
|
||||
fwrite_unlocked;
|
||||
getentropy;
|
||||
getnetent;
|
||||
getprotoent;
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
/* $OpenBSD: fread.c,v 1.12 2014/05/01 16:40:36 deraadt Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include "local.h"
|
||||
|
||||
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
|
||||
|
||||
size_t
|
||||
fread(void *buf, size_t size, size_t count, FILE *fp) __overloadable
|
||||
{
|
||||
CHECK_FP(fp);
|
||||
|
||||
/*
|
||||
* Extension: Catch integer overflow.
|
||||
*/
|
||||
if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) &&
|
||||
size > 0 && SIZE_MAX / size < count) {
|
||||
errno = EOVERFLOW;
|
||||
fp->_flags |= __SERR;
|
||||
return (0);
|
||||
}
|
||||
|
||||
const size_t desired_total = count * size;
|
||||
size_t total = desired_total;
|
||||
|
||||
/*
|
||||
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
|
||||
*/
|
||||
if (total == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
FLOCKFILE(fp);
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
|
||||
// TODO: how can this ever happen?!
|
||||
if (fp->_r < 0)
|
||||
fp->_r = 0;
|
||||
|
||||
/*
|
||||
* Ensure _bf._size is valid.
|
||||
*/
|
||||
if (fp->_bf._base == NULL) {
|
||||
__smakebuf(fp);
|
||||
}
|
||||
|
||||
char* dst = static_cast<char*>(buf);
|
||||
|
||||
while (total > 0) {
|
||||
/*
|
||||
* Copy data out of the buffer.
|
||||
*/
|
||||
size_t buffered_bytes = MIN((size_t) fp->_r, total);
|
||||
memcpy(dst, fp->_p, buffered_bytes);
|
||||
fp->_p += buffered_bytes;
|
||||
fp->_r -= buffered_bytes;
|
||||
dst += buffered_bytes;
|
||||
total -= buffered_bytes;
|
||||
|
||||
/*
|
||||
* Are we done?
|
||||
*/
|
||||
if (total == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do we have so much more to read that we should
|
||||
* avoid copying it through the buffer?
|
||||
*/
|
||||
if (total > (size_t) fp->_bf._size) {
|
||||
/*
|
||||
* Make sure that fseek doesn't think it can
|
||||
* reuse the buffer since we are going to read
|
||||
* directly from the file descriptor.
|
||||
*/
|
||||
fp->_flags |= __SMOD;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Less than a buffer to go, so refill the buffer and
|
||||
* go around the loop again.
|
||||
*/
|
||||
if (__srefill(fp)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read directly into the caller's buffer.
|
||||
*/
|
||||
while (total > 0) {
|
||||
ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total);
|
||||
if (bytes_read <= 0) {
|
||||
fp->_flags |= (bytes_read == 0) ? __SEOF : __SERR;
|
||||
break;
|
||||
}
|
||||
dst += bytes_read;
|
||||
total -= bytes_read;
|
||||
}
|
||||
|
||||
out:
|
||||
FUNLOCKFILE(fp);
|
||||
return ((desired_total - total) / size);
|
||||
}
|
|
@ -145,11 +145,12 @@ struct __sfileext {
|
|||
// #define __SOPT 0x0400 --- historical (do fseek() optimization).
|
||||
// #define __SNPT 0x0800 --- historical (do not do fseek() optimization).
|
||||
// #define __SOFF 0x1000 --- historical (set iff _offset is in fact correct).
|
||||
#define __SMOD 0x2000 // true => fgetln modified _p text.
|
||||
// #define __SMOD 0x2000 --- historical (set iff fgetln modified _p text).
|
||||
#define __SALC 0x4000 // Allocate string space dynamically.
|
||||
#define __SIGN 0x8000 // Ignore this file in _fwalk.
|
||||
|
||||
// TODO: remove remaining references to these obsolete flags (see above).
|
||||
#define __SMOD 0
|
||||
#define __SNPT 0
|
||||
#define __SOPT 0
|
||||
|
||||
|
@ -243,10 +244,18 @@ int __vfwscanf(FILE *, const wchar_t *, va_list);
|
|||
#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
|
||||
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
|
||||
|
||||
/* OpenBSD declares these in fvwrite.h but we want to ensure they're hidden. */
|
||||
struct __suio;
|
||||
extern int __sfvwrite(FILE *, struct __suio *);
|
||||
wint_t __fputwc_unlock(wchar_t wc, FILE *fp);
|
||||
/* OpenBSD declares these in fvwrite.h, but we share them with C++ parts of the implementation. */
|
||||
struct __siov {
|
||||
void* iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
struct __suio {
|
||||
struct __siov* uio_iov;
|
||||
int uio_iovcnt;
|
||||
size_t uio_resid;
|
||||
};
|
||||
int __sfvwrite(FILE*, struct __suio*);
|
||||
wint_t __fputwc_unlock(wchar_t wc, FILE* fp);
|
||||
|
||||
/* Remove the if (!__sdidinit) __sinit() idiom from untouched upstream stdio code. */
|
||||
extern void __sinit(void); // Not actually implemented.
|
||||
|
|
|
@ -111,7 +111,6 @@ __srefill(FILE *fp)
|
|||
}
|
||||
fp->_p = fp->_bf._base;
|
||||
fp->_r = (*fp->_read)(fp->_cookie, (char *)fp->_p, fp->_bf._size);
|
||||
fp->_flags &= ~__SMOD; /* buffer contents are again pristine */
|
||||
if (fp->_r <= 0) {
|
||||
if (fp->_r == 0)
|
||||
fp->_flags |= __SEOF;
|
||||
|
|
|
@ -91,7 +91,7 @@ FILE* stdin = &__sF[0];
|
|||
FILE* stdout = &__sF[1];
|
||||
FILE* stderr = &__sF[2];
|
||||
|
||||
struct glue __sglue = { NULL, 3, __sF };
|
||||
struct glue __sglue = { nullptr, 3, __sF };
|
||||
static struct glue* lastglue = &__sglue;
|
||||
|
||||
class ScopedFileLock {
|
||||
|
@ -116,7 +116,7 @@ static glue* moreglue(int n) {
|
|||
glue* g = reinterpret_cast<glue*>(data);
|
||||
FILE* p = reinterpret_cast<FILE*>(ALIGN(data + sizeof(*g)));
|
||||
__sfileext* pext = reinterpret_cast<__sfileext*>(ALIGN(data + sizeof(*g)) + n * sizeof(FILE));
|
||||
g->next = NULL;
|
||||
g->next = nullptr;
|
||||
g->niobs = n;
|
||||
g->iobs = p;
|
||||
while (--n >= 0) {
|
||||
|
@ -144,7 +144,7 @@ FILE* __sfp(void) {
|
|||
struct glue *g;
|
||||
|
||||
_THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
|
||||
for (g = &__sglue; g != NULL; g = g->next) {
|
||||
for (g = &__sglue; g != nullptr; g = g->next) {
|
||||
for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
|
||||
if (fp->_flags == 0)
|
||||
goto found;
|
||||
|
@ -152,8 +152,7 @@ FILE* __sfp(void) {
|
|||
|
||||
/* release lock while mallocing */
|
||||
_THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
|
||||
if ((g = moreglue(NDYNAMIC)) == NULL)
|
||||
return (NULL);
|
||||
if ((g = moreglue(NDYNAMIC)) == nullptr) return nullptr;
|
||||
_THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex);
|
||||
lastglue->next = g;
|
||||
lastglue = g;
|
||||
|
@ -161,15 +160,15 @@ FILE* __sfp(void) {
|
|||
found:
|
||||
fp->_flags = 1; /* reserve this slot; caller sets real flags */
|
||||
_THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex);
|
||||
fp->_p = NULL; /* no current pointer */
|
||||
fp->_p = nullptr; /* no current pointer */
|
||||
fp->_w = 0; /* nothing to read or write */
|
||||
fp->_r = 0;
|
||||
fp->_bf._base = NULL; /* no buffer */
|
||||
fp->_bf._base = nullptr; /* no buffer */
|
||||
fp->_bf._size = 0;
|
||||
fp->_lbfsize = 0; /* not line buffered */
|
||||
fp->_file = -1; /* no file */
|
||||
|
||||
fp->_lb._base = NULL; /* no line buffer */
|
||||
fp->_lb._base = nullptr; /* no line buffer */
|
||||
fp->_lb._size = 0;
|
||||
_FILEEXT_INIT(fp);
|
||||
|
||||
|
@ -288,8 +287,8 @@ FILE* freopen(const char* file, const char* mode, FILE* fp) {
|
|||
// Flush the stream; ANSI doesn't require this.
|
||||
if (fp->_flags & __SWR) __sflush(fp);
|
||||
|
||||
// If close is NULL, closing is a no-op, hence pointless.
|
||||
isopen = fp->_close != NULL;
|
||||
// If close is null, closing is a no-op, hence pointless.
|
||||
isopen = (fp->_close != nullptr);
|
||||
if ((wantfd = fp->_file) < 0 && isopen) {
|
||||
(*fp->_close)(fp->_cookie);
|
||||
isopen = 0;
|
||||
|
@ -316,8 +315,8 @@ FILE* freopen(const char* file, const char* mode, FILE* fp) {
|
|||
if (fp->_flags & __SMBF) free(fp->_bf._base);
|
||||
fp->_w = 0;
|
||||
fp->_r = 0;
|
||||
fp->_p = NULL;
|
||||
fp->_bf._base = NULL;
|
||||
fp->_p = nullptr;
|
||||
fp->_bf._base = nullptr;
|
||||
fp->_bf._size = 0;
|
||||
fp->_lbfsize = 0;
|
||||
if (HASUB(fp)) FREEUB(fp);
|
||||
|
@ -374,7 +373,7 @@ int fclose(FILE* fp) {
|
|||
ScopedFileLock sfl(fp);
|
||||
WCIO_FREE(fp);
|
||||
int r = fp->_flags & __SWR ? __sflush(fp) : 0;
|
||||
if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
|
||||
if (fp->_close != nullptr && (*fp->_close)(fp->_cookie) < 0) {
|
||||
r = EOF;
|
||||
}
|
||||
if (fp->_flags & __SMBF) free(fp->_bf._base);
|
||||
|
@ -438,6 +437,36 @@ int ferror(FILE* fp) {
|
|||
return ferror_unlocked(fp);
|
||||
}
|
||||
|
||||
int __sflush(FILE* fp) {
|
||||
// Flushing a read-only file is a no-op.
|
||||
if ((fp->_flags & __SWR) == 0) return 0;
|
||||
|
||||
// Flushing a file without a buffer is a no-op.
|
||||
unsigned char* p = fp->_bf._base;
|
||||
if (p == nullptr) return 0;
|
||||
|
||||
// Set these immediately to avoid problems with longjmp and to allow
|
||||
// exchange buffering (via setvbuf) in user write function.
|
||||
int n = fp->_p - p;
|
||||
fp->_p = p;
|
||||
fp->_w = (fp->_flags & (__SLBF|__SNBF)) ? 0 : fp->_bf._size;
|
||||
|
||||
while (n > 0) {
|
||||
int written = (*fp->_write)(fp->_cookie, reinterpret_cast<char*>(p), n);
|
||||
if (written <= 0) {
|
||||
fp->_flags |= __SERR;
|
||||
return EOF;
|
||||
}
|
||||
n -= written, p += written;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __sflush_locked(FILE* fp) {
|
||||
ScopedFileLock sfl(fp);
|
||||
return __sflush(fp);
|
||||
}
|
||||
|
||||
int __sread(void* cookie, char* buf, int n) {
|
||||
FILE* fp = reinterpret_cast<FILE*>(cookie);
|
||||
return TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
|
||||
|
@ -495,7 +524,7 @@ static off64_t __ftello64_unlocked(FILE* fp) {
|
|||
// smaller than that in the underlying object.
|
||||
result -= fp->_r;
|
||||
if (HASUB(fp)) result -= fp->_ur;
|
||||
} else if (fp->_flags & __SWR && fp->_p != NULL) {
|
||||
} else if (fp->_flags & __SWR && fp->_p != nullptr) {
|
||||
// Writing. Any buffered characters cause the
|
||||
// position to be greater than that in the
|
||||
// underlying object.
|
||||
|
@ -527,7 +556,7 @@ int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (fp->_bf._base == NULL) __smakebuf(fp);
|
||||
if (fp->_bf._base == nullptr) __smakebuf(fp);
|
||||
|
||||
// Flush unwritten data and attempt the seek.
|
||||
if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
|
||||
|
@ -670,11 +699,90 @@ int fgetc(FILE* fp) {
|
|||
return getc(fp);
|
||||
}
|
||||
|
||||
int fgetc_unlocked(FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
return getc_unlocked(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read at most n-1 characters from the given file.
|
||||
* Stop when a newline has been read, or the count runs out.
|
||||
* Return first argument, or NULL if no characters were read.
|
||||
* Do not return NULL if n == 1.
|
||||
*/
|
||||
char* fgets(char* buf, int n, FILE* fp) __overloadable {
|
||||
CHECK_FP(fp);
|
||||
ScopedFileLock sfl(fp);
|
||||
return fgets_unlocked(buf, n, fp);
|
||||
}
|
||||
|
||||
char* fgets_unlocked(char* buf, int n, FILE* fp) {
|
||||
if (n <= 0) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
|
||||
char* s = buf;
|
||||
n--; // Leave space for NUL.
|
||||
while (n != 0) {
|
||||
// If the buffer is empty, refill it.
|
||||
if (fp->_r <= 0) {
|
||||
if (__srefill(fp)) {
|
||||
// EOF/error: stop with partial or no line.
|
||||
if (s == buf) return nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t len = fp->_r;
|
||||
unsigned char* p = fp->_p;
|
||||
|
||||
// Scan through at most n bytes of the current buffer,
|
||||
// looking for '\n'. If found, copy up to and including
|
||||
// newline, and stop. Otherwise, copy entire chunk and loop.
|
||||
if (len > static_cast<size_t>(n)) len = n;
|
||||
unsigned char* t = static_cast<unsigned char*>(memchr(p, '\n', len));
|
||||
if (t != nullptr) {
|
||||
len = ++t - p;
|
||||
fp->_r -= len;
|
||||
fp->_p = t;
|
||||
memcpy(s, p, len);
|
||||
s[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
fp->_r -= len;
|
||||
fp->_p += len;
|
||||
memcpy(s, p, len);
|
||||
s += len;
|
||||
n -= len;
|
||||
}
|
||||
*s = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
int fputc(int c, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
return putc(c, fp);
|
||||
}
|
||||
|
||||
int fputc_unlocked(int c, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
return putc_unlocked(c, fp);
|
||||
}
|
||||
|
||||
int fputs(const char* s, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
ScopedFileLock sfl(fp);
|
||||
return fputs_unlocked(s, fp);
|
||||
}
|
||||
|
||||
int fputs_unlocked(const char* s, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
size_t length = strlen(s);
|
||||
return (fwrite_unlocked(s, 1, length, fp) == length) ? 0 : EOF;
|
||||
}
|
||||
|
||||
int fscanf(FILE* fp, const char* fmt, ...) {
|
||||
CHECK_FP(fp);
|
||||
PRINTF_IMPL(vfscanf(fp, fmt, ap));
|
||||
|
@ -723,6 +831,11 @@ wint_t getwchar() {
|
|||
return fgetwc(stdin);
|
||||
}
|
||||
|
||||
void perror(const char* msg) {
|
||||
if (msg == nullptr) msg = "";
|
||||
fprintf(stderr, "%s%s%s\n", msg, (*msg == '\0') ? "" : ": ", strerror(errno));
|
||||
}
|
||||
|
||||
int printf(const char* fmt, ...) {
|
||||
PRINTF_IMPL(vfprintf(stdout, fmt, ap));
|
||||
}
|
||||
|
@ -754,6 +867,13 @@ int putchar_unlocked(int c) {
|
|||
return putc_unlocked(c, stdout);
|
||||
}
|
||||
|
||||
int puts(const char* s) {
|
||||
size_t length = strlen(s);
|
||||
ScopedFileLock sfl(stdout);
|
||||
return (fwrite_unlocked(s, 1, length, stdout) == length &&
|
||||
putc_unlocked('\n', stdout) != EOF) ? 0 : EOF;
|
||||
}
|
||||
|
||||
wint_t putwc(wchar_t wc, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
return fputwc(wc, fp);
|
||||
|
@ -869,6 +989,116 @@ int wscanf(const wchar_t* fmt, ...) {
|
|||
PRINTF_IMPL(vfwscanf(stdin, fmt, ap));
|
||||
}
|
||||
|
||||
static int fflush_all() {
|
||||
return _fwalk(__sflush_locked);
|
||||
}
|
||||
|
||||
int fflush(FILE* fp) {
|
||||
if (fp == nullptr) return fflush_all();
|
||||
ScopedFileLock sfl(fp);
|
||||
return fflush_unlocked(fp);
|
||||
}
|
||||
|
||||
int fflush_unlocked(FILE* fp) {
|
||||
if (fp == nullptr) return fflush_all();
|
||||
if ((fp->_flags & (__SWR | __SRW)) == 0) {
|
||||
errno = EBADF;
|
||||
return EOF;
|
||||
}
|
||||
return __sflush(fp);
|
||||
}
|
||||
|
||||
size_t fread(void* buf, size_t size, size_t count, FILE* fp) __overloadable {
|
||||
CHECK_FP(fp);
|
||||
ScopedFileLock sfl(fp);
|
||||
return fread_unlocked(buf, size, count, fp);
|
||||
}
|
||||
|
||||
size_t fread_unlocked(void* buf, size_t size, size_t count, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
|
||||
size_t desired_total;
|
||||
if (__builtin_mul_overflow(size, count, &desired_total)) {
|
||||
errno = EOVERFLOW;
|
||||
fp->_flags |= __SERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t total = desired_total;
|
||||
if (total == 0) return 0;
|
||||
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
|
||||
// TODO: how can this ever happen?!
|
||||
if (fp->_r < 0) fp->_r = 0;
|
||||
|
||||
// Ensure _bf._size is valid.
|
||||
if (fp->_bf._base == nullptr) __smakebuf(fp);
|
||||
|
||||
char* dst = static_cast<char*>(buf);
|
||||
|
||||
while (total > 0) {
|
||||
// Copy data out of the buffer.
|
||||
size_t buffered_bytes = MIN(static_cast<size_t>(fp->_r), total);
|
||||
memcpy(dst, fp->_p, buffered_bytes);
|
||||
fp->_p += buffered_bytes;
|
||||
fp->_r -= buffered_bytes;
|
||||
dst += buffered_bytes;
|
||||
total -= buffered_bytes;
|
||||
|
||||
// Are we done?
|
||||
if (total == 0) goto out;
|
||||
|
||||
// Do we have so much more to read that we should avoid copying it through the buffer?
|
||||
if (total > static_cast<size_t>(fp->_bf._size)) break;
|
||||
|
||||
// Less than a buffer to go, so refill the buffer and go around the loop again.
|
||||
if (__srefill(fp)) goto out;
|
||||
}
|
||||
|
||||
// Read directly into the caller's buffer.
|
||||
while (total > 0) {
|
||||
ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total);
|
||||
if (bytes_read <= 0) {
|
||||
fp->_flags |= (bytes_read == 0) ? __SEOF : __SERR;
|
||||
break;
|
||||
}
|
||||
dst += bytes_read;
|
||||
total -= bytes_read;
|
||||
}
|
||||
|
||||
out:
|
||||
return ((desired_total - total) / size);
|
||||
}
|
||||
|
||||
size_t fwrite(const void* buf, size_t size, size_t count, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
ScopedFileLock sfl(fp);
|
||||
return fwrite_unlocked(buf, size, count, fp);
|
||||
}
|
||||
|
||||
size_t fwrite_unlocked(const void* buf, size_t size, size_t count, FILE* fp) {
|
||||
CHECK_FP(fp);
|
||||
|
||||
size_t n;
|
||||
if (__builtin_mul_overflow(size, count, &n)) {
|
||||
errno = EOVERFLOW;
|
||||
fp->_flags |= __SERR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n == 0) return 0;
|
||||
|
||||
__siov iov = { .iov_base = const_cast<void*>(buf), .iov_len = n };
|
||||
__suio uio = { .uio_iov = &iov, .uio_iovcnt = 1, .uio_resid = n };
|
||||
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
|
||||
// The usual case is success (__sfvwrite returns 0); skip the divide if this happens,
|
||||
// since divides are generally slow.
|
||||
return (__sfvwrite(fp, &uio) == 0) ? count : ((n - uio.uio_resid) / size);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
namespace phony {
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/* $OpenBSD: fflush.c,v 1.9 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "local.h"
|
||||
|
||||
/* Flush a single file, or (if fp is NULL) all files. */
|
||||
int
|
||||
fflush(FILE *fp)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (fp == NULL)
|
||||
return (_fwalk(__sflush_locked));
|
||||
FLOCKFILE(fp);
|
||||
if ((fp->_flags & (__SWR | __SRW)) == 0) {
|
||||
errno = EBADF;
|
||||
r = EOF;
|
||||
} else
|
||||
r = __sflush(fp);
|
||||
FUNLOCKFILE(fp);
|
||||
return (r);
|
||||
}
|
||||
DEF_STRONG(fflush);
|
||||
|
||||
int
|
||||
__sflush(FILE *fp)
|
||||
{
|
||||
unsigned char *p;
|
||||
int n, t;
|
||||
|
||||
t = fp->_flags;
|
||||
if ((t & __SWR) == 0)
|
||||
return (0);
|
||||
|
||||
if ((p = fp->_bf._base) == NULL)
|
||||
return (0);
|
||||
|
||||
n = fp->_p - p; /* write this much */
|
||||
|
||||
/*
|
||||
* Set these immediately to avoid problems with longjmp and to allow
|
||||
* exchange buffering (via setvbuf) in user write function.
|
||||
*/
|
||||
fp->_p = p;
|
||||
fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
|
||||
|
||||
for (; n > 0; n -= t, p += t) {
|
||||
t = (*fp->_write)(fp->_cookie, (char *)p, n);
|
||||
if (t <= 0) {
|
||||
fp->_flags |= __SERR;
|
||||
return (EOF);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
__sflush_locked(FILE *fp)
|
||||
{
|
||||
int r;
|
||||
|
||||
FLOCKFILE(fp);
|
||||
r = __sflush(fp);
|
||||
FUNLOCKFILE(fp);
|
||||
return (r);
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/* $OpenBSD: fgets.c,v 1.16 2016/09/21 04:38:56 guenther Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "local.h"
|
||||
|
||||
/*
|
||||
* Read at most n-1 characters from the given file.
|
||||
* Stop when a newline has been read, or the count runs out.
|
||||
* Return first argument, or NULL if no characters were read.
|
||||
* Do not return NULL if n == 1.
|
||||
*/
|
||||
char *
|
||||
fgets(char *buf, int n, FILE *fp) __overloadable
|
||||
{
|
||||
size_t len;
|
||||
char *s;
|
||||
unsigned char *p, *t;
|
||||
|
||||
if (n <= 0) { /* sanity check */
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
FLOCKFILE(fp);
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
s = buf;
|
||||
n--; /* leave space for NUL */
|
||||
while (n != 0) {
|
||||
/*
|
||||
* If the buffer is empty, refill it.
|
||||
*/
|
||||
if (fp->_r <= 0) {
|
||||
if (__srefill(fp)) {
|
||||
/* EOF/error: stop with partial or no line */
|
||||
if (s == buf) {
|
||||
FUNLOCKFILE(fp);
|
||||
return (NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = fp->_r;
|
||||
p = fp->_p;
|
||||
|
||||
/*
|
||||
* Scan through at most n bytes of the current buffer,
|
||||
* looking for '\n'. If found, copy up to and including
|
||||
* newline, and stop. Otherwise, copy entire chunk
|
||||
* and loop.
|
||||
*/
|
||||
if (len > n)
|
||||
len = n;
|
||||
t = memchr(p, '\n', len);
|
||||
if (t != NULL) {
|
||||
len = ++t - p;
|
||||
fp->_r -= len;
|
||||
fp->_p = t;
|
||||
(void)memcpy(s, p, len);
|
||||
s[len] = '\0';
|
||||
FUNLOCKFILE(fp);
|
||||
return (buf);
|
||||
}
|
||||
fp->_r -= len;
|
||||
fp->_p += len;
|
||||
(void)memcpy(s, p, len);
|
||||
s += len;
|
||||
n -= len;
|
||||
}
|
||||
*s = '\0';
|
||||
FUNLOCKFILE(fp);
|
||||
return (buf);
|
||||
}
|
||||
DEF_STRONG(fgets);
|
|
@ -1,59 +0,0 @@
|
|||
/* $OpenBSD: fputs.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "local.h"
|
||||
#include "fvwrite.h"
|
||||
|
||||
/*
|
||||
* Write the given string to the given file.
|
||||
*/
|
||||
int
|
||||
fputs(const char *s, FILE *fp)
|
||||
{
|
||||
struct __suio uio;
|
||||
struct __siov iov;
|
||||
int ret;
|
||||
|
||||
iov.iov_base = (void *)s;
|
||||
iov.iov_len = uio.uio_resid = strlen(s);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
FLOCKFILE(fp);
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
ret = __sfvwrite(fp, &uio);
|
||||
FUNLOCKFILE(fp);
|
||||
return (ret);
|
||||
}
|
||||
DEF_STRONG(fputs);
|
|
@ -32,20 +32,4 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* I/O descriptors for __sfvwrite().
|
||||
*/
|
||||
struct __siov {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
struct __suio {
|
||||
struct __siov *uio_iov;
|
||||
int uio_iovcnt;
|
||||
int uio_resid;
|
||||
};
|
||||
|
||||
__BEGIN_HIDDEN_DECLS
|
||||
extern int __sfvwrite(FILE *, struct __suio *);
|
||||
wint_t __fputwc_unlock(wchar_t wc, FILE *fp);
|
||||
__END_HIDDEN_DECLS
|
||||
/* Moved to "local.h". */
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/* $OpenBSD: fwrite.c,v 1.12 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "local.h"
|
||||
#include "fvwrite.h"
|
||||
|
||||
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
|
||||
|
||||
/*
|
||||
* Write `count' objects (each size `size') from memory to the given file.
|
||||
* Return the number of whole objects written.
|
||||
*/
|
||||
size_t
|
||||
fwrite(const void *buf, size_t size, size_t count, FILE *fp) __overloadable
|
||||
{
|
||||
size_t n;
|
||||
struct __suio uio;
|
||||
struct __siov iov;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Extension: Catch integer overflow
|
||||
*/
|
||||
if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) &&
|
||||
size > 0 && SIZE_MAX / size < count) {
|
||||
errno = EOVERFLOW;
|
||||
fp->_flags |= __SERR;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
|
||||
*/
|
||||
if ((n = count * size) == 0)
|
||||
return (0);
|
||||
|
||||
iov.iov_base = (void *)buf;
|
||||
uio.uio_resid = iov.iov_len = n;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
|
||||
/*
|
||||
* The usual case is success (__sfvwrite returns 0);
|
||||
* skip the divide if this happens, since divides are
|
||||
* generally slow and since this occurs whenever size==0.
|
||||
*/
|
||||
FLOCKFILE(fp);
|
||||
_SET_ORIENTATION(fp, -1);
|
||||
ret = __sfvwrite(fp, &uio);
|
||||
FUNLOCKFILE(fp);
|
||||
if (ret == 0)
|
||||
return (count);
|
||||
return ((n - uio.uio_resid) / size);
|
||||
}
|
||||
DEF_STRONG(fwrite);
|
|
@ -1,63 +0,0 @@
|
|||
/* $OpenBSD: perror.c,v 1.9 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
void
|
||||
perror(const char *s)
|
||||
{
|
||||
struct iovec *v;
|
||||
struct iovec iov[4];
|
||||
char buf[NL_TEXTMAX];
|
||||
|
||||
v = iov;
|
||||
if (s && *s) {
|
||||
v->iov_base = (char *)s;
|
||||
v->iov_len = strlen(s);
|
||||
v++;
|
||||
v->iov_base = ": ";
|
||||
v->iov_len = 2;
|
||||
v++;
|
||||
}
|
||||
(void)strerror_r(errno, buf, sizeof(buf));
|
||||
v->iov_base = buf;
|
||||
v->iov_len = strlen(v->iov_base);
|
||||
v++;
|
||||
v->iov_base = "\n";
|
||||
v->iov_len = 1;
|
||||
(void)writev(STDERR_FILENO, iov, (v - iov) + 1);
|
||||
}
|
||||
DEF_STRONG(perror);
|
|
@ -1,63 +0,0 @@
|
|||
/* $OpenBSD: puts.c,v 1.12 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "local.h"
|
||||
#include "fvwrite.h"
|
||||
|
||||
/*
|
||||
* Write the given string to stdout, appending a newline.
|
||||
*/
|
||||
int
|
||||
puts(const char *s)
|
||||
{
|
||||
size_t c = strlen(s);
|
||||
struct __suio uio;
|
||||
struct __siov iov[2];
|
||||
int ret;
|
||||
|
||||
iov[0].iov_base = (void *)s;
|
||||
iov[0].iov_len = c;
|
||||
iov[1].iov_base = "\n";
|
||||
iov[1].iov_len = 1;
|
||||
uio.uio_resid = c + 1;
|
||||
uio.uio_iov = &iov[0];
|
||||
uio.uio_iovcnt = 2;
|
||||
FLOCKFILE(stdout);
|
||||
_SET_ORIENTATION(stdout, -1);
|
||||
ret = __sfvwrite(stdout, &uio);
|
||||
FUNLOCKFILE(stdout);
|
||||
return (ret ? EOF : '\n');
|
||||
}
|
||||
DEF_STRONG(puts);
|
|
@ -1962,3 +1962,61 @@ TEST(STDIO_TEST, constants) {
|
|||
ASSERT_LE(FILENAME_MAX, PATH_MAX);
|
||||
ASSERT_EQ(L_tmpnam, PATH_MAX);
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, perror) {
|
||||
ExecTestHelper eth;
|
||||
eth.Run([&]() { errno = EINVAL; perror("a b c"); exit(0); }, 0, "a b c: Invalid argument\n");
|
||||
eth.Run([&]() { errno = EINVAL; perror(nullptr); exit(0); }, 0, "Invalid argument\n");
|
||||
eth.Run([&]() { errno = EINVAL; perror(""); exit(0); }, 0, "Invalid argument\n");
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, puts) {
|
||||
ExecTestHelper eth;
|
||||
eth.Run([&]() { exit(puts("a b c")); }, 0, "a b c\n");
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, unlocked) {
|
||||
TemporaryFile tf;
|
||||
|
||||
FILE* fp = fopen(tf.filename, "w+");
|
||||
ASSERT_TRUE(fp != nullptr);
|
||||
|
||||
clearerr_unlocked(fp);
|
||||
ASSERT_FALSE(feof_unlocked(fp));
|
||||
ASSERT_FALSE(ferror_unlocked(fp));
|
||||
|
||||
ASSERT_EQ(fileno(fp), fileno_unlocked(fp));
|
||||
|
||||
ASSERT_NE(EOF, putc_unlocked('a', fp));
|
||||
ASSERT_NE(EOF, putc('b', fp));
|
||||
ASSERT_NE(EOF, fputc_unlocked('c', fp));
|
||||
ASSERT_NE(EOF, fputc('d', fp));
|
||||
|
||||
rewind(fp);
|
||||
ASSERT_EQ('a', getc_unlocked(fp));
|
||||
ASSERT_EQ('b', getc(fp));
|
||||
ASSERT_EQ('c', fgetc_unlocked(fp));
|
||||
ASSERT_EQ('d', fgetc(fp));
|
||||
|
||||
rewind(fp);
|
||||
ASSERT_EQ(2U, fwrite_unlocked("AB", 1, 2, fp));
|
||||
ASSERT_EQ(2U, fwrite("CD", 1, 2, fp));
|
||||
ASSERT_EQ(0, fflush_unlocked(fp));
|
||||
|
||||
rewind(fp);
|
||||
char buf[BUFSIZ] = {};
|
||||
ASSERT_EQ(2U, fread_unlocked(&buf[0], 1, 2, fp));
|
||||
ASSERT_EQ(2U, fread(&buf[2], 1, 2, fp));
|
||||
ASSERT_STREQ("ABCD", buf);
|
||||
|
||||
rewind(fp);
|
||||
ASSERT_NE(EOF, fputs("hello ", fp));
|
||||
ASSERT_NE(EOF, fputs_unlocked("world", fp));
|
||||
ASSERT_NE(EOF, fputc('\n', fp));
|
||||
|
||||
rewind(fp);
|
||||
ASSERT_TRUE(fgets_unlocked(buf, sizeof(buf), fp) != nullptr);
|
||||
ASSERT_STREQ("hello world\n", buf);
|
||||
|
||||
ASSERT_EQ(0, fclose(fp));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue