gmio_core: provide a POSIX implementation for gmio_stream_stdio_size()

This commit is contained in:
Hugues Delorme 2015-04-01 15:39:00 +02:00
parent a04b9b2cda
commit 76ee571cd5
4 changed files with 159 additions and 33 deletions

View File

@ -25,7 +25,7 @@ project(gmio C)
# Options # Options
option(BUILD_SHARED_LIBS "Build shared libraries (DLL)" ON) option(BUILD_SHARED_LIBS "Build shared libraries (DLL)" ON)
option(BUILD_STRICT_C90 "Build with strict conformance to C90 standard. If disabled, C99 features can be used (eg. strtof(), <stdint.h>, ...)" ON) option(BUILD_STRICT_C90 "Build with strict conformance to C90 standard" OFF)
option(BUILD_WITH_LIBSTL "Build the libSTL module" ON) option(BUILD_WITH_LIBSTL "Build the libSTL module" ON)
# Add core source files # Add core source files
@ -39,31 +39,49 @@ math(EXPR GMIO_TARGET_ARCH_BIT_SIZE "8 * ${CMAKE_SIZEOF_VOID_P}")
include(TestBigEndian) include(TestBigEndian)
test_big_endian(GMIO_HOST_IS_BIG_ENDIAN) test_big_endian(GMIO_HOST_IS_BIG_ENDIAN)
# Find available C99 features # Adapt C compiler flags to satisfy the BUILD_STRICT_C90 option
if(NOT BUILD_STRICT_C90) # It must be done before checking of C99 and POSIX features
# Have <stdint.h> ? if(BUILD_STRICT_C90)
check_include_files(stdint.h GMIO_HAVE_STDINT_H) if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi")
# Have strtof() ? elseif(MSVC)
check_function_exists(strtof GMIO_HAVE_STRTOF_FUNC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Za")
endif()
# Have powf() ?
check_function_exists(powf GMIO_HAVE_POWF_FUNC)
# Have <stdbool.h> ?
check_include_files(stdbool.h GMIO_HAVE_STDBOOL_H)
endif() endif()
# Have alloca()-like function ? set(CMAKE_REQUIRED_FLAGS "${CMAKE_C_FLAGS}")
check_c_source_compiles(
"#include <alloca.h>
int main() { void* ptr = alloca(256); return 0; }"
GMIO_HAVE_BSD_ALLOCA_FUNC)
check_c_source_compiles( # Some compilers (like GCC v4.9) don't disable <stdint.h> in STRICT_ANSI mode
"#include <malloc.h> check_include_files(stdint.h GMIO_HAVE_STDINT_H)
int main() { void* ptr = _alloca(256); return 0; }"
GMIO_HAVE_WIN_ALLOCA_FUNC) check_include_files(sys/types.h GMIO_HAVE_SYS_TYPES_H)
check_include_files(sys/stat.h GMIO_HAVE_SYS_STAT_H)
check_function_exists(fileno GMIO_HAVE_POSIX_FILENO_FUNC)
check_function_exists(fstat64 GMIO_HAVE_POSIX_FSTAT64_FUNC)
if(WIN32)
check_function_exists(_fstat64 GMIO_HAVE_WIN__FSTAT64_FUNC)
endif()
# Find available C99 and compiler/OS specific features
if(NOT BUILD_STRICT_C90)
check_function_exists(strtof GMIO_HAVE_STRTOF_FUNC)
check_function_exists(powf GMIO_HAVE_POWF_FUNC)
check_include_files(stdbool.h GMIO_HAVE_STDBOOL_H)
# Have BSD-like alloca() function ?
check_c_source_compiles(
"#include <alloca.h>
int main() { void* ptr = alloca(256); return 0; }"
GMIO_HAVE_BSD_ALLOCA_FUNC)
if(WIN32)
# Have Win32 _alloca() function ?
check_c_source_compiles(
"#include <malloc.h>
int main() { void* ptr = _alloca(256); return 0; }"
GMIO_HAVE_WIN_ALLOCA_FUNC) # TODO: rename to GMIO_HAVE_WIN__ALLOCA_FUNC
endif() # WIN32
endif()
# Have builtin byte swap functions ? # Have builtin byte swap functions ?
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
@ -87,9 +105,6 @@ include_directories(${CMAKE_BINARY_DIR}) # For generated "config.h"
# Specific flags for GCC # Specific flags for GCC
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
if(BUILD_STRICT_C90)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors -fstrict-aliasing") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors -fstrict-aliasing")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Wextra -Wstrict-aliasing -Wcast-align -Wlogical-op -Wfloat-equal") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Wextra -Wstrict-aliasing -Wcast-align -Wlogical-op -Wfloat-equal")

View File

@ -23,6 +23,12 @@
#cmakedefine GMIO_HAVE_STRTOF_FUNC #cmakedefine GMIO_HAVE_STRTOF_FUNC
#cmakedefine GMIO_HAVE_POWF_FUNC #cmakedefine GMIO_HAVE_POWF_FUNC
#cmakedefine GMIO_HAVE_SYS_TYPES_H
#cmakedefine GMIO_HAVE_SYS_STAT_H
#cmakedefine GMIO_HAVE_POSIX_FILENO_FUNC
#cmakedefine GMIO_HAVE_POSIX_FSTAT64_FUNC
#cmakedefine GMIO_HAVE_WIN__FSTAT64_FUNC
#cmakedefine GMIO_HAVE_GCC_BUILTIN_BSWAP16_FUNC #cmakedefine GMIO_HAVE_GCC_BUILTIN_BSWAP16_FUNC
#cmakedefine GMIO_HAVE_GCC_BUILTIN_BSWAP32_FUNC #cmakedefine GMIO_HAVE_GCC_BUILTIN_BSWAP32_FUNC

View File

@ -23,6 +23,18 @@
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) \ #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) \
|| defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
|| defined(__NT__) || defined(__NT__)
# define GMIO_OS_WIN
#endif /* Windows */
#if defined(__linux) || defined(__linux__) || defined(linux)
# define GMIO_OS_LINUX
#endif /* Linux */
#if defined(__APPLE__)
# define GMIO_OS_MAC
#endif /* Apple */
#ifdef GMIO_OS_WIN
# define GMIO_DECL_EXPORT __declspec(dllexport) # define GMIO_DECL_EXPORT __declspec(dllexport)
# define GMIO_DECL_IMPORT __declspec(dllimport) # define GMIO_DECL_IMPORT __declspec(dllimport)
#else #else
@ -118,7 +130,7 @@ typedef double gmio_float64_t;
# elif defined(_MSC_VER) # elif defined(_MSC_VER)
# define GMIO_INLINE __inline static # define GMIO_INLINE __inline static
# elif !defined(DOXYGEN) # elif !defined(DOXYGEN)
# define GMIO_INLINE # define GMIO_INLINE static
# else # else
/*! Expands to the C compiler specific inline keyword (if any) */ /*! Expands to the C compiler specific inline keyword (if any) */
# define GMIO_INLINE # define GMIO_INLINE

View File

@ -19,9 +19,53 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/* TODO: add cmake step to check availability of <sys/xxx.h> header files */ #if defined(GMIO_HAVE_SYS_TYPES_H) && defined(GMIO_HAVE_SYS_STAT_H)
#include <sys/types.h>
#include <sys/stat.h> /* Activate 64bit variants of stat(), fstat(), ...
* See:
* http://linux.die.net/man/2/fstat64
* https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fstat.2.html
*/
# ifdef GMIO_OS_LINUX
# if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != 64
# undef _FILE_OFFSET_BITS
# endif
# if !defined(_FILE_OFFSET_BITS)
# define _FILE_OFFSET_BITS=64
# endif
# if !defined(_POSIX_C_SOURCE)
/* This enables fileno() */
# define _POSIX_C_SOURCE
# endif
# define GMIO_FSTAT64_OVERRIDE
# endif /* Linux */
# ifdef GMIO_OS_MAC
# if !defined(_DARWIN_USE_64_BIT_INODE)
# define _DARWIN_USE_64_BIT_INODE
# endif
# define GMIO_FSTAT64_OVERRIDE
# endif /* Apple */
# include <sys/types.h>
# include <sys/stat.h>
/* Define wrapper around the stat structure and the fstat() function */
# ifdef GMIO_HAVE_WIN__FSTAT64_FUNC
typedef struct __stat64 gmio_stat_t;
GMIO_INLINE int gmio_fstat(int fd, gmio_stat_t* buf)
{ return _fstat64(fd, buf); }
# elif defined(GMIO_FSTAT64_OVERRIDE) || !defined(GMIO_HAVE_POSIX_FSTAT64_FUNC)
typedef struct stat gmio_stat_t;
GMIO_INLINE int gmio_fstat(int fd, gmio_stat_t* buf)
{ return fstat(fd, buf); }
# elif defined(GMIO_HAVE_POSIX_FSTAT64_FUNC)
typedef struct stat64 gmio_stat_t;
GMIO_INLINE int gmio_fstat(int fd, gmio_stat_t* buf)
{ return fstat64(fd, buf); }
# endif
#endif /* GMIO_HAVE_SYS_TYPES_H && GMIO_HAVE_SYS_STAT_H */
gmio_stream_t gmio_stream_null() gmio_stream_t gmio_stream_null()
{ {
@ -53,9 +97,58 @@ static size_t gmio_stream_stdio_write(
static size_t gmio_stream_stdio_size(void* cookie) static size_t gmio_stream_stdio_size(void* cookie)
{ {
struct stat stat_buf; FILE* file = (FILE*) cookie;
fstat(fileno((FILE*) cookie), &stat_buf);
return stat_buf.st_size; #if defined(GMIO_HAVE_SYS_TYPES_H) \
&& defined(GMIO_HAVE_SYS_STAT_H) \
&& defined(GMIO_HAVE_POSIX_FILENO_FUNC)
const int fd = fileno(file);
if (fd != -1) {
gmio_stat_t buf;
if (gmio_fstat(fd, &buf) == 0)
return buf.st_size;
}
return 0;
#else
/* Excerpted from: https://www.securecoding.cert.org
* item FIO19-C
*
* Subclause 7.21.9.2 of the C Standard [ISO/IEC 9899:2011] specifies the
* following behavior for fseek() when opening a binary file in binary mode:
* A binary stream need not meaningfully support fseek calls with a
* whence value of SEEK_END.
*
* In addition, footnote 268 of subclause 7.21.3 says:
* Setting the file position indicator to end-of-file, as with
* fseek(file, 0, SEEK_END), has undefined behavior for a binary stream
* (because of possible trailing null characters) or for any stream with
* state-dependent encoding that does not assuredly end in the initial
* shift state.
*
* Subclause 7.21.9.4 of the C Standard [ISO/IEC 9899:2011] specifies the
* following behavior for ftell() when opening a text file in text mode:
* For a text stream, its file position indicator contains unspecified
* information, usable by the fseek function for returning the file
* position indicator for the stream to its position at the time of the
* ftell call.
* Consequently, the return value of ftell() for streams opened in text mode
* should never be used for offset calculations other than in calls to
* fseek().
*/
long size = 0L;
const long old_pos = ftell(file);
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, old_pos, SEEK_SET);
return size;
#endif
} }
static void gmio_stream_stdio_rewind(void* cookie) static void gmio_stream_stdio_rewind(void* cookie)