From f52d48d5673a5323a17dfc7ee4331b284e058ee3 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Tue, 27 Jun 2017 15:42:40 -0700 Subject: [PATCH] Make stdio buildable by the NDK. No functional change intended. This just rearranges some pieces of stdio so we can build them with the NDK (as part of libandroid_support). The definition of struct __sFILE is moved to stdio/bits/struct_file.h. When building for older API levels, stdio.h includes the public version of this header and gets a definition which conflicts with ours. Match the public header name so we can shadow it. The definition of fpos_t moves into bits/fpos_t.h to accommodate for the above. Move __sglue into its own source file. We don't need the rest of stdio.cpp (and don't want duplicates of things like __sF). Move the *wprintf family into their own source file for the same reason. We may end up doing this with more functions, but for now all libandroid_support needs is the *wprintf family. Test: make checkbuild Test: Able to add vswprintf.c and wprintf.cpp (and everything they need) to libandroid_support and pass libc++ tests in the NDK. Bug: https://github.com/android-ndk/ndk/issues/300 Change-Id: I4127071906fc9dacf40e41cff35e403b48ba297c --- libc/Android.bp | 2 + libc/include/bits/fpos_t.h | 42 ++++++++++++++ libc/include/stdio.h | 4 +- libc/stdio/bits/struct_file.h | 104 ++++++++++++++++++++++++++++++++++ libc/stdio/glue.cpp | 36 ++++++++++++ libc/stdio/glue.h | 1 + libc/stdio/local.h | 60 +------------------- libc/stdio/printf_impl.h | 38 +++++++++++++ libc/stdio/stdio.cpp | 25 +------- libc/stdio/wprintf.cpp | 47 +++++++++++++++ 10 files changed, 273 insertions(+), 86 deletions(-) create mode 100644 libc/include/bits/fpos_t.h create mode 100644 libc/stdio/bits/struct_file.h create mode 100644 libc/stdio/glue.cpp create mode 100644 libc/stdio/printf_impl.h create mode 100644 libc/stdio/wprintf.cpp diff --git a/libc/Android.bp b/libc/Android.bp index 4f6ff1a7e1..76ce68c2bc 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -14,12 +14,14 @@ libc_common_src_files = [ "bionic/siginterrupt.c", "bionic/sigsetmask.c", "stdio/fread.c", + "stdio/glue.cpp", "stdio/parsefloat.c", "stdio/refill.c", "stdio/stdio.cpp", "stdio/stdio_ext.cpp", "stdio/vfscanf.c", "stdio/vfwscanf.c", + "stdio/wprintf.cpp", "stdlib/atexit.c", "stdlib/exit.c", ] diff --git a/libc/include/bits/fpos_t.h b/libc/include/bits/fpos_t.h new file mode 100644 index 0000000000..67a8b2c41d --- /dev/null +++ b/libc/include/bits/fpos_t.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + */ + +#ifndef BIONIC_BITS_FPOS_T_H +#define BIONIC_BITS_FPOS_T_H + +#include +#include + +__BEGIN_DECLS + +typedef off_t fpos_t; +typedef off64_t fpos64_t; + +__END_DECLS + +#endif /* BIONIC_BITS_FPOS_T_H */ diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 24916d6758..3bda68474d 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -47,6 +47,7 @@ #define __need_NULL #include +#include #include #if __ANDROID_API__ < __ANDROID_API_N__ @@ -60,9 +61,6 @@ __BEGIN_DECLS #pragma clang diagnostic ignored "-Wnullability-completeness" #endif -typedef off_t fpos_t; -typedef off64_t fpos64_t; - struct __sFILE; typedef struct __sFILE FILE; diff --git a/libc/stdio/bits/struct_file.h b/libc/stdio/bits/struct_file.h new file mode 100644 index 0000000000..124eebfaa0 --- /dev/null +++ b/libc/stdio/bits/struct_file.h @@ -0,0 +1,104 @@ +/* $OpenBSD: local.h,v 1.12 2005/10/10 17:37:44 espie 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. + */ + +#ifndef BIONIC_STDIO_BITS_STRUCT_FILE_H +#define BIONIC_STDIO_BITS_STRUCT_FILE_H + +#include +#include + +__BEGIN_DECLS + +struct __sbuf { + unsigned char* _base; +#if defined(__LP64__) + size_t _size; +#else + int _size; +#endif +}; + +struct __sFILE { + unsigned char* _p; /* current position in (some) buffer */ + int _r; /* read space left for getc() */ + int _w; /* write space left for putc() */ +#if defined(__LP64__) + int _flags; /* flags, below; this FILE is free if 0 */ + int _file; /* fileno, if Unix descriptor, else -1 */ +#else + short _flags; /* flags, below; this FILE is free if 0 */ + short _file; /* fileno, if Unix descriptor, else -1 */ +#endif + struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ + int _lbfsize; /* 0 or -_bf._size, for inline putc */ + + // Function pointers used by `funopen`. + // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set. + // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s. + // TODO: glibc has `fopencookie` which passes the function pointers in a struct. + void* _cookie; /* cookie passed to io functions */ + int (*_close)(void*); + int (*_read)(void*, char*, int); + fpos_t (*_seek)(void*, fpos_t, int); + int (*_write)(void*, const char*, int); + + /* extension data, to avoid further ABI breakage */ + struct __sbuf _ext; + /* data for long sequences of ungetc() */ + unsigned char* _up; /* saved _p when _p is doing ungetc data */ + int _ur; /* saved _r when _r is counting ungetc data */ + + /* tricks to meet minimum requirements even when malloc() fails */ + unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ + unsigned char _nbuf[1]; /* guarantee a getc() buffer */ + + /* separate buffer for fgetln() when line crosses buffer boundary */ + struct __sbuf _lb; /* buffer for fgetln() */ + + /* Unix stdio files get aligned to block boundaries on fseek() */ + int _blksize; /* stat.st_blksize (may be != _bf._size) */ + + fpos_t _unused_0; // This was the `_offset` field (see below). + + // Do not add new fields here. (Or remove or change the size of any above.) + // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols, + // that still hasn't made it to the NDK. All NDK-built apps index directly + // into an array of this struct (which was in historically), so if + // you need to make any changes, they need to be in the `__sfileext` struct + // below, and accessed via `_EXT`. +}; + +__END_DECLS + +#endif /* BIONIC_STDIO_BITS_STRUCT_FILE_H */ diff --git a/libc/stdio/glue.cpp b/libc/stdio/glue.cpp new file mode 100644 index 0000000000..4f0a570fbd --- /dev/null +++ b/libc/stdio/glue.cpp @@ -0,0 +1,36 @@ +/* $OpenBSD: findfp.c,v 1.15 2013/12/17 16:33:27 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 "glue.h" + +extern FILE __sF[3]; +struct glue __sglue = { NULL, 3, __sF }; diff --git a/libc/stdio/glue.h b/libc/stdio/glue.h index cb1d18203f..62a25c702c 100644 --- a/libc/stdio/glue.h +++ b/libc/stdio/glue.h @@ -32,6 +32,7 @@ * SUCH DAMAGE. */ +#include #include __BEGIN_DECLS diff --git a/libc/stdio/local.h b/libc/stdio/local.h index 575a4285c6..d872f16197 100644 --- a/libc/stdio/local.h +++ b/libc/stdio/local.h @@ -38,6 +38,7 @@ #include #include #include +#include "bits/struct_file.h" #include "wcio.h" /* @@ -47,65 +48,6 @@ __BEGIN_DECLS -struct __sbuf { - unsigned char* _base; -#if defined(__LP64__) - size_t _size; -#else - int _size; -#endif -}; - -struct __sFILE { - unsigned char *_p; /* current position in (some) buffer */ - int _r; /* read space left for getc() */ - int _w; /* write space left for putc() */ -#if defined(__LP64__) - int _flags; /* flags, below; this FILE is free if 0 */ - int _file; /* fileno, if Unix descriptor, else -1 */ -#else - short _flags; /* flags, below; this FILE is free if 0 */ - short _file; /* fileno, if Unix descriptor, else -1 */ -#endif - struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ - int _lbfsize; /* 0 or -_bf._size, for inline putc */ - - // Function pointers used by `funopen`. - // Note that `_seek` is ignored if `_seek64` (in __sfileext) is set. - // TODO: NetBSD has `funopen2` which corrects the `int`s to `size_t`s. - // TODO: glibc has `fopencookie` which passes the function pointers in a struct. - void* _cookie; /* cookie passed to io functions */ - int (*_close)(void*); - int (*_read)(void*, char*, int); - fpos_t (*_seek)(void*, fpos_t, int); - int (*_write)(void*, const char*, int); - - /* extension data, to avoid further ABI breakage */ - struct __sbuf _ext; - /* data for long sequences of ungetc() */ - unsigned char *_up; /* saved _p when _p is doing ungetc data */ - int _ur; /* saved _r when _r is counting ungetc data */ - - /* tricks to meet minimum requirements even when malloc() fails */ - unsigned char _ubuf[3]; /* guarantee an ungetc() buffer */ - unsigned char _nbuf[1]; /* guarantee a getc() buffer */ - - /* separate buffer for fgetln() when line crosses buffer boundary */ - struct __sbuf _lb; /* buffer for fgetln() */ - - /* Unix stdio files get aligned to block boundaries on fseek() */ - int _blksize; /* stat.st_blksize (may be != _bf._size) */ - - fpos_t _unused_0; // This was the `_offset` field (see below). - - // Do not add new fields here. (Or remove or change the size of any above.) - // Although bionic currently exports `stdin`, `stdout`, and `stderr` symbols, - // that still hasn't made it to the NDK. All NDK-built apps index directly - // into an array of this struct (which was in historically), so if - // you need to make any changes, they need to be in the `__sfileext` struct - // below, and accessed via `_EXT`. -}; - struct __sfileext { // ungetc buffer. struct __sbuf _ub; diff --git a/libc/stdio/printf_impl.h b/libc/stdio/printf_impl.h new file mode 100644 index 0000000000..ad12ab9136 --- /dev/null +++ b/libc/stdio/printf_impl.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + */ +#ifndef BIONIC_STDIO_PRINTF_IMPL_H +#define BIONIC_STDIO_PRINTF_IMPL_H + +#define PRINTF_IMPL(expr) \ + va_list ap; \ + va_start(ap, fmt); \ + int result = (expr); \ + va_end(ap); \ + return result; + +#endif /* BIONIC_STDIO_PRINTF_IMPL_H */ diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index b0f5c607f6..2f52f8f088 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -49,19 +49,13 @@ #include "private/bionic_fortify.h" #include "private/ErrnoRestorer.h" #include "private/thread_private.h" +#include "printf_impl.h" #define ALIGNBYTES (sizeof(uintptr_t) - 1) #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) #define NDYNAMIC 10 /* add ten more whenever necessary */ -#define PRINTF_IMPL(expr) \ - va_list ap; \ - va_start(ap, fmt); \ - int result = (expr); \ - va_end(ap); \ - return result; - #define std(flags, file) \ {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,nullptr,__swrite, \ {(unsigned char *)(__sFext+file), 0},nullptr,0,{0},{0},{0,0},0,0} @@ -95,7 +89,6 @@ FILE* stdin = &__sF[0]; FILE* stdout = &__sF[1]; FILE* stderr = &__sF[2]; -struct glue __sglue = { NULL, 3, __sF }; static struct glue* lastglue = &__sglue; class ScopedFileLock { @@ -673,10 +666,6 @@ int fscanf(FILE* fp, const char* fmt, ...) { PRINTF_IMPL(vfscanf(fp, fmt, ap)); } -int fwprintf(FILE* fp, const wchar_t* fmt, ...) { - PRINTF_IMPL(vfwprintf(fp, fmt, ap)); -} - int fwscanf(FILE* fp, const wchar_t* fmt, ...) { PRINTF_IMPL(vfwscanf(fp, fmt, ap)); } @@ -787,10 +776,6 @@ int sscanf(const char* s, const char* fmt, ...) { PRINTF_IMPL(vsscanf(s, fmt, ap)); } -int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) { - PRINTF_IMPL(vswprintf(s, n, fmt, ap)); -} - int swscanf(const wchar_t* s, const wchar_t* fmt, ...) { PRINTF_IMPL(vswscanf(s, fmt, ap)); } @@ -833,18 +818,10 @@ int vsprintf(char* s, const char* fmt, va_list ap) { return vsnprintf(s, SSIZE_MAX, fmt, ap); } -int vwprintf(const wchar_t* fmt, va_list ap) { - return vfwprintf(stdout, fmt, ap); -} - int vwscanf(const wchar_t* fmt, va_list ap) { return vfwscanf(stdin, fmt, ap); } -int wprintf(const wchar_t* fmt, ...) { - PRINTF_IMPL(vfwprintf(stdout, fmt, ap)); -} - int wscanf(const wchar_t* fmt, ...) { PRINTF_IMPL(vfwscanf(stdin, fmt, ap)); } diff --git a/libc/stdio/wprintf.cpp b/libc/stdio/wprintf.cpp new file mode 100644 index 0000000000..1ae7fc2354 --- /dev/null +++ b/libc/stdio/wprintf.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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 +#include + +#include "printf_impl.h" + +int fwprintf(FILE* fp, const wchar_t* fmt, ...) { + PRINTF_IMPL(vfwprintf(fp, fmt, ap)); +} + +int swprintf(wchar_t* s, size_t n, const wchar_t* fmt, ...) { + PRINTF_IMPL(vswprintf(s, n, fmt, ap)); +} + +int vwprintf(const wchar_t* fmt, va_list ap) { + return vfwprintf(stdout, fmt, ap); +} + +int wprintf(const wchar_t* fmt, ...) { + PRINTF_IMPL(vfwprintf(stdout, fmt, ap)); +}