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
diff --git a/libc/Android.bp b/libc/Android.bp
index 89d33b0..5d0a020 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -14,7 +14,6 @@
"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 @@
"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",
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 559e52a..2d45fc5 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -256,7 +256,20 @@
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>
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 981cea6..abab364 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1326,6 +1326,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 67fac4e..d464a0c 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1246,6 +1246,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 443d18c..97965ac 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1351,6 +1351,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 0f5efff..930a1ca 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1310,6 +1310,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 67fac4e..d464a0c 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1246,6 +1246,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index a802aa1..27b9743 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1308,6 +1308,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 67fac4e..d464a0c 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1246,6 +1246,13 @@
endnetent;
endprotoent;
fexecve;
+ fflush_unlocked;
+ fgetc_unlocked;
+ fgets_unlocked;
+ fputc_unlocked;
+ fputs_unlocked;
+ fread_unlocked;
+ fwrite_unlocked;
getentropy;
getnetent;
getprotoent;
diff --git a/libc/stdio/fread.cpp b/libc/stdio/fread.cpp
deleted file mode 100644
index 073f71a..0000000
--- a/libc/stdio/fread.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index c728eec..a86e924 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -145,11 +145,12 @@
// #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 @@
#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.
diff --git a/libc/stdio/refill.c b/libc/stdio/refill.c
index a7c4bff..1df4191 100644
--- a/libc/stdio/refill.c
+++ b/libc/stdio/refill.c
@@ -111,7 +111,6 @@
}
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;
diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp
index cf97a3f..c10bc00 100644
--- a/libc/stdio/stdio.cpp
+++ b/libc/stdio/stdio.cpp
@@ -91,7 +91,7 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 {
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fflush.c b/libc/upstream-openbsd/lib/libc/stdio/fflush.c
deleted file mode 100644
index fd1a4b3..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/fflush.c
+++ /dev/null
@@ -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);
-}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fgets.c b/libc/upstream-openbsd/lib/libc/stdio/fgets.c
deleted file mode 100644
index 3cea8f7..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/fgets.c
+++ /dev/null
@@ -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);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fputs.c b/libc/upstream-openbsd/lib/libc/stdio/fputs.c
deleted file mode 100644
index 05ead5c..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/fputs.c
+++ /dev/null
@@ -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);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
index f04565b..d2257cc 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
+++ b/libc/upstream-openbsd/lib/libc/stdio/fvwrite.h
@@ -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". */
diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c b/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
deleted file mode 100644
index f829398..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/fwrite.c
+++ /dev/null
@@ -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);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/perror.c b/libc/upstream-openbsd/lib/libc/stdio/perror.c
deleted file mode 100644
index fdd6120..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/perror.c
+++ /dev/null
@@ -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);
diff --git a/libc/upstream-openbsd/lib/libc/stdio/puts.c b/libc/upstream-openbsd/lib/libc/stdio/puts.c
deleted file mode 100644
index 57d4b78..0000000
--- a/libc/upstream-openbsd/lib/libc/stdio/puts.c
+++ /dev/null
@@ -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);