Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
@ -3,7 +3,6 @@
|
|||
/prefix
|
||||
*.txt
|
||||
!CMakeLists.txt
|
||||
.vxsdk/
|
||||
|
||||
# GiteaPC config files
|
||||
giteapc-config.make
|
||||
|
|
|
@ -12,9 +12,3 @@ int rand(void)
|
|||
{
|
||||
return tinymt32_generate_uint32(&random) & 0x7fffffff;
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void init_prng(void)
|
||||
{
|
||||
srand(1);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(FxLibc VERSION 1.5.0 LANGUAGES C ASM)
|
||||
project(FxLibc VERSION 1.4.4 LANGUAGES C ASM)
|
||||
|
||||
set(CMAKE_INSTALL_MESSAGE LAZY)
|
||||
|
||||
|
@ -15,9 +15,7 @@ if(FXLIBC_TARGET STREQUAL vhex-sh)
|
|||
list(APPEND TARGET_FOLDERS vhex sh-generic)
|
||||
set(FXLIBC_ARCH sh)
|
||||
add_definitions(-D__SUPPORT_VHEX_KERNEL)
|
||||
set(CMAKE_INSTALL_PREFIX "${VXSDK_COMPILER_INSTALL}" CACHE PATH "..." FORCE)
|
||||
set(INCDIR "${VXSDK_COMPILER_INSTALL}/include")
|
||||
set(LIBDIR "${VXSDK_COMPILER_INSTALL}/lib")
|
||||
set(CMAKE_INSTALL_PREFIX "${FXSDK_COMPILER_INSTALL}" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
if(FXLIBC_TARGET STREQUAL gint)
|
||||
|
@ -72,8 +70,6 @@ set(SOURCES
|
|||
3rdparty/grisu2b_59_56/grisu2b_59_56.c
|
||||
3rdparty/tinymt32/rand.c
|
||||
3rdparty/tinymt32/tinymt32.c
|
||||
# C++ API details
|
||||
src/dso.c
|
||||
# assert
|
||||
src/assert/assert.c
|
||||
# ctype
|
||||
|
@ -116,7 +112,6 @@ set(SOURCES
|
|||
src/stdio/fgetc.c
|
||||
src/stdio/fgetpos.c
|
||||
src/stdio/fgets.c
|
||||
src/stdio/fileno.c
|
||||
src/stdio/fileutil.c
|
||||
src/stdio/fopen.c
|
||||
src/stdio/fprintf.c
|
||||
|
@ -124,7 +119,6 @@ set(SOURCES
|
|||
src/stdio/fputs.c
|
||||
src/stdio/fread.c
|
||||
src/stdio/freopen.c
|
||||
src/stdio/fscanf.c
|
||||
src/stdio/fseek.c
|
||||
src/stdio/fsetpos.c
|
||||
src/stdio/ftell.c
|
||||
|
@ -146,28 +140,21 @@ set(SOURCES
|
|||
src/stdio/puts.c
|
||||
src/stdio/remove.c
|
||||
src/stdio/rewind.c
|
||||
src/stdio/scanf.c
|
||||
src/stdio/scanf/scan.c
|
||||
src/stdio/setbuf.c
|
||||
src/stdio/setvbuf.c
|
||||
src/stdio/snprintf.c
|
||||
src/stdio/sprintf.c
|
||||
src/stdio/sscanf.c
|
||||
src/stdio/streams.c
|
||||
src/stdio/ungetc.c
|
||||
src/stdio/vasprintf.c
|
||||
src/stdio/vdprintf.c
|
||||
src/stdio/vfprintf.c
|
||||
src/stdio/vfscanf.c
|
||||
src/stdio/vprintf.c
|
||||
src/stdio/vscanf.c
|
||||
src/stdio/vsnprintf.c
|
||||
src/stdio/vsprintf.c
|
||||
src/stdio/vsscanf.c
|
||||
# stdlib
|
||||
src/stdlib/abort.c
|
||||
src/stdlib/abs.c
|
||||
src/stdlib/atexit.c
|
||||
src/stdlib/atof.c
|
||||
src/stdlib/atoi.c
|
||||
src/stdlib/atol.c
|
||||
|
@ -267,43 +254,22 @@ if(gint IN_LIST TARGET_FOLDERS)
|
|||
src/time/target/gint/time.c)
|
||||
endif()
|
||||
|
||||
# TODO: All targets
|
||||
|
||||
add_library(fxlibc ${SOURCES})
|
||||
|
||||
target_include_directories(fxlibc PRIVATE include/)
|
||||
|
||||
#---
|
||||
# Handle "target-specific" fxlibc output format
|
||||
#---
|
||||
|
||||
if(FXLIBC_TARGET STREQUAL vhex-sh)
|
||||
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
|
||||
add_library(fxlibcStatic STATIC ${SOURCES})
|
||||
add_library(fxlibcShared SHARED ${SOURCES})
|
||||
set(FXLIBC_TARGET_LIBS "fxlibcStatic;fxlibcShared")
|
||||
else()
|
||||
add_library(fxlibcStatic STATIC ${SOURCES})
|
||||
set(FXLIBC_TARGET_LIBS "fxlibcStatic")
|
||||
endif()
|
||||
|
||||
|
||||
foreach(FXLIBC_LIB IN LISTS FXLIBC_TARGET_LIBS)
|
||||
|
||||
target_include_directories(${FXLIBC_LIB} PRIVATE include/)
|
||||
foreach(FOLDER IN LISTS TARGET_FOLDERS)
|
||||
target_include_directories(${FXLIBC_LIB} PRIVATE include/target/${FOLDER}/)
|
||||
endforeach()
|
||||
|
||||
set_target_properties(${FXLIBC_LIB} PROPERTIES OUTPUT_NAME "c")
|
||||
|
||||
install(TARGETS ${FXLIBC_LIB} DESTINATION ${LIBDIR})
|
||||
foreach(FOLDER IN LISTS TARGET_FOLDERS)
|
||||
target_include_directories(fxlibc PRIVATE include/target/${FOLDER}/)
|
||||
endforeach()
|
||||
|
||||
set_target_properties(fxlibc PROPERTIES
|
||||
OUTPUT_NAME "c") # libc.a
|
||||
|
||||
# Install
|
||||
|
||||
|
||||
#---
|
||||
# Do not forget to install headers
|
||||
#---
|
||||
|
||||
install(TARGETS fxlibc DESTINATION ${LIBDIR})
|
||||
install(DIRECTORY include/ DESTINATION ${INCDIR} PATTERN "target" EXCLUDE)
|
||||
|
||||
foreach(FOLDER IN LISTS TARGET_FOLDERS)
|
||||
|
|
20
STATUS
20
STATUS
|
@ -99,22 +99,21 @@ TEST: Function/symbol/macro needs to be tested
|
|||
7.19.5.4 freopen -
|
||||
7.19.5.5 setbuf -
|
||||
7.19.5.6 setvbuf -
|
||||
(EXT) fileno -
|
||||
|
||||
7.19.6.1 fprintf -
|
||||
7.19.6.2 fscanf TEST
|
||||
7.19.6.2 fscanf TODO
|
||||
7.19.6.3 printf -
|
||||
7.19.6.4 scanf TEST
|
||||
7.19.6.4 scanf TODO
|
||||
7.19.6.5 snprintf -
|
||||
7.19.6.6 sprintf -
|
||||
7.19.6.7 sscanf TEST
|
||||
7.19.6.7 sscanf TODO
|
||||
7.19.6.8 vfprintf -
|
||||
7.19.6.9 vfscanf TEST
|
||||
7.19.6.9 vfscanf TODO
|
||||
7.19.6.10 vprintf -
|
||||
7.19.6.11 vscanf TEST
|
||||
7.19.6.11 vscanf TODO
|
||||
7.19.6.12 vsnprintf -
|
||||
7.19.6.13 vsprintf -
|
||||
7.19.6.14 vsscanf TEST
|
||||
7.19.6.14 vsscanf TODO
|
||||
(EXT) asprintf -
|
||||
(EXT) vasprintf -
|
||||
(EXT) dprintf -
|
||||
|
@ -162,7 +161,7 @@ TEST: Function/symbol/macro needs to be tested
|
|||
7.20.3.3 malloc - (gint)
|
||||
7.20.3.4 realloc - (gint)
|
||||
7.20.4.1 abort - (stream flushing/closing/etc?)
|
||||
7.20.4.2 atexit TEST
|
||||
7.20.4.2 atexit TODO
|
||||
7.20.4.3 exit - (stream flushing/closing/etc?)
|
||||
7.20.4.4 _Exit - (gint)
|
||||
7.20.4.5 getenv TODO
|
||||
|
@ -173,8 +172,6 @@ TEST: Function/symbol/macro needs to be tested
|
|||
7.20.6.2 div, ldiv, lldiv -
|
||||
7.20.7 Multibyte/wide char conv TODO
|
||||
7.20.8 Multibyte/wide string conv TODO
|
||||
(EXT) __cxa_atexit TEST
|
||||
(EXT) __cxa_finalize TEST
|
||||
|
||||
7.21 <string.h>
|
||||
7.21.2.1 memcpy -
|
||||
|
@ -225,9 +222,6 @@ TEST: Function/symbol/macro needs to be tested
|
|||
|
||||
7.25 <wctype.h> TODO (not a priority)
|
||||
|
||||
(EXT) <alloca.h>
|
||||
(EXT) alloca -
|
||||
|
||||
# Supporting locales
|
||||
|
||||
What if we wanted to support more locales?
|
||||
|
|
|
@ -12,13 +12,16 @@ set(CMAKE_CXX_FLAGS_INIT "")
|
|||
|
||||
add_compile_options(-nostdlib)
|
||||
add_link_options(-nostdlib)
|
||||
link_libraries(-lgcc)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
if(NOT DEFINED ENV{VXSDK_COMPILER_SYSROOT})
|
||||
message(FATAL_ERROR "You should use the vxSDK to build this project")
|
||||
endif()
|
||||
set(VXSDK_COMPILER_INSTALL $ENV{VXSDK_COMPILER_SYSROOT})
|
||||
# Determine compiler install path
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} --print-file-name=.
|
||||
OUTPUT_VARIABLE FXSDK_COMPILER_INSTALL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef __ALLOCA_H__
|
||||
# define __ALLOCA_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#undef alloca
|
||||
|
||||
/* Allocate a block of memory on the stack. */
|
||||
extern void *alloca(size_t __size);
|
||||
|
||||
#define alloca(size) __builtin_alloca(size)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__ALLOCA_H__*/
|
|
@ -75,6 +75,7 @@ extern int __printf(
|
|||
va_list *__args);
|
||||
|
||||
|
||||
|
||||
/* Format extension API. */
|
||||
|
||||
struct __printf_format {
|
||||
|
@ -83,8 +84,12 @@ struct __printf_format {
|
|||
/* How much significant characters of data, meaning varies. */
|
||||
int16_t precision;
|
||||
|
||||
/* Size of targeted integer type (%o, %x, %i, %d, %u), in bytes */
|
||||
/*
|
||||
** Size specifier for integers (%o, %x, %i, %d, %u), is equal to the
|
||||
** sizeof() of the targeted type. Also used for %lc.
|
||||
*/
|
||||
uint8_t size;
|
||||
|
||||
/* (#) Alternative form: base prefixes, decimal point. */
|
||||
uint8_t alternative :1;
|
||||
/* ( ) Add a blank sign before nonnegative numbers. */
|
||||
|
@ -106,14 +111,15 @@ struct __printf_format {
|
|||
|
||||
/*
|
||||
** Type of format functions.
|
||||
** -> __out specifies the output and is used when generating text
|
||||
** -> __fmt contains the format options and specifier letter
|
||||
** -> __spec is the specifier letter (eg. "d" in "%d")
|
||||
** -> __opts are the length, precision, sign, alignment, etc. options
|
||||
** -> __args is a pointer to the variable list of arguments to read from
|
||||
*/
|
||||
typedef void __printf_formatter_t(
|
||||
struct __printf_output *__out,
|
||||
struct __printf_format *__fmt,
|
||||
va_list *__args);
|
||||
struct __printf_format *__opts,
|
||||
va_list *__args
|
||||
);
|
||||
|
||||
/*
|
||||
** Register a new format.
|
||||
|
@ -121,10 +127,10 @@ typedef void __printf_formatter_t(
|
|||
** The formatter designated by the specified lowercase or uppercase letter
|
||||
** (eg 'p' or 'P') is registered. This functions allows overriding default
|
||||
** formatters, but this is very much discouraged. Letters with special meaning
|
||||
** in the standard cannot be changed. A formatter can be removed of disabled by
|
||||
** in the standard cannot be changed. A formatted can be removed of disabled by
|
||||
** registering NULL.
|
||||
**
|
||||
** Here are the characters used/reserved in the C standard:
|
||||
** Here are used characters in the C standard:
|
||||
**
|
||||
** a: Hexadecimal floating-point A: Hexadecimal floating-point
|
||||
** b: _ B: _
|
||||
|
@ -132,7 +138,7 @@ typedef void __printf_formatter_t(
|
|||
** d: Decimal integer D: _
|
||||
** e: Exponent floating-point E: Exponent floating-point
|
||||
** f: Floating-point F: Floating-point
|
||||
** g: General floating-point G: General floating-point
|
||||
** g: General floating-point G: General: floating-point
|
||||
** h: short or char size H: _
|
||||
** i: Integer I: Locale-aware digits
|
||||
** j: intmax_t size J: _
|
||||
|
|
|
@ -187,7 +187,6 @@ extern void setbuf(FILE * __restrict__ __fp, char * __restrict__ __buf);
|
|||
extern int setvbuf(FILE * __restrict__ __fp, char * __restrict__ __buf,
|
||||
int __mode, size_t __size);
|
||||
|
||||
/* Return the file descriptor associated with __fp. */
|
||||
extern int fileno(FILE *__fp);
|
||||
|
||||
/*
|
||||
|
|
|
@ -38,7 +38,6 @@ extern void free(void *__ptr);
|
|||
__attribute__((noreturn))
|
||||
extern void abort(void);
|
||||
|
||||
/* Register a function to be called at program exit. */
|
||||
extern int atexit(void (*__func)(void));
|
||||
|
||||
/* Exit; calls handlers, flushes and closes streams and temporary files. */
|
||||
|
|
68
src/dso.c
68
src/dso.c
|
@ -1,68 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/* We don't support shared object loading, so provide a single handle */
|
||||
__attribute__((visibility("hidden")))
|
||||
void *__dso_handle = (void *)&__dso_handle;
|
||||
|
||||
/* Number of atexit() calls supported, must be at least 32 (7.20.4.2§3).*/
|
||||
#define ATEXIT_MAX 32
|
||||
|
||||
struct dtor {
|
||||
void (*f)(void *);
|
||||
void *p;
|
||||
void *d;
|
||||
};
|
||||
|
||||
static struct dtor *_dtors;
|
||||
static int _dtor_count = 0;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void alloc_dtors(void)
|
||||
{
|
||||
_dtors = malloc(ATEXIT_MAX * sizeof *_dtors);
|
||||
}
|
||||
|
||||
int __cxa_atexit(void (*f)(void *), void *p, void *d)
|
||||
{
|
||||
if(!_dtors || _dtor_count >= ATEXIT_MAX)
|
||||
return 1;
|
||||
_dtors[_dtor_count++] = (struct dtor){ f, p, d };
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We walk the destructor list in reverse order. Destructors may themselves
|
||||
call __cxa_atexit(), causing new destructors to be added. When that
|
||||
happens, we must call the new ones first before resuming (7.20.4.3§3). We
|
||||
track changes in _dtor_count to detect this situation.
|
||||
|
||||
This function calls destructs in the interval [low..high) that match DSO
|
||||
handle d, plus any other destructors registered as a consequence.
|
||||
_dtor_count may increase. */
|
||||
static void call_dtors_in_interval(void *d, int low, int high)
|
||||
{
|
||||
int end = _dtor_count;
|
||||
|
||||
for(int i = high - 1; i >= low; i--) {
|
||||
if(d == NULL || _dtors[i].d == d)
|
||||
_dtors[i].f(_dtors[i].p);
|
||||
|
||||
if(_dtor_count > end) {
|
||||
call_dtors_in_interval(d, end, _dtor_count);
|
||||
end = _dtor_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __cxa_finalize(void *d)
|
||||
{
|
||||
call_dtors_in_interval(d, 0, _dtor_count);
|
||||
|
||||
/* Re-compact the array to keep only destructors we didn't call. */
|
||||
int j = 0;
|
||||
for(int i = 0; i < _dtor_count; i++) {
|
||||
if(d == NULL || _dtors[i].d == d)
|
||||
continue;
|
||||
_dtors[j++] = _dtors[i];
|
||||
}
|
||||
_dtor_count = j;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int fileno(FILE *fp)
|
||||
{
|
||||
return fp->fd;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int fscanf(FILE * restrict fp, char const * restrict fmt, ...)
|
||||
{
|
||||
struct __scanf_input in = {
|
||||
.fp = fp,
|
||||
};
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
__scanf_start(&in);
|
||||
int count = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
|
||||
va_end(args);
|
||||
return count;
|
||||
}
|
|
@ -59,8 +59,6 @@ void __printf_format_s(
|
|||
size_t len = 0;
|
||||
uint32_t precision = opt->precision ? opt->precision : (-1);
|
||||
while(s[len] && len < precision) len++;
|
||||
/* Cap precision to real value for __printf_compute_geometry() */
|
||||
opt->precision = len;
|
||||
|
||||
struct __printf_geometry g = {
|
||||
.prefix = 0, .sign = 0, .content = len,
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int scanf(char const * restrict fmt, ...)
|
||||
{
|
||||
struct __scanf_input in = {
|
||||
.fp = stdin,
|
||||
};
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
__scanf_start(&in);
|
||||
int count = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
|
||||
va_end(args);
|
||||
return count;
|
||||
}
|
|
@ -1,366 +0,0 @@
|
|||
#include "../stdio_p.h"
|
||||
#include "../../stdlib/stdlib_p.h"
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Features of this implementation:
|
||||
- Specifiers:
|
||||
* Integers (%i, %d, %o, %u, %x, %X)
|
||||
* Floating-point numbers (%e, %f, %F, %g, %a)
|
||||
* Strings (%c, %s, %[])
|
||||
* Pointers (%p)
|
||||
* Total number of bytes read so far (%n)
|
||||
- Integer size modifiers: hh, h, l, ll, L, j, z, t. Supported for all
|
||||
integer conversions, i.e. %i, %d, %u, %o, %x, %X and %n.
|
||||
- Floating-point size modifiers: l, L for %a, %e, %f, %g.
|
||||
- Assignment suppression character '*'.
|
||||
- Maximum field width (but buggy for floating-point, see below).
|
||||
|
||||
NOT SUPPORTED:
|
||||
- Wide characters: %lc, %ls.
|
||||
- q size modifier.
|
||||
- "'" (quote) specifier for locale-specific thousand separators.
|
||||
- String allocation: %mc, %ms.
|
||||
- Out-of-order assignments "%n$".
|
||||
- TODO: Maximum field width for floating-point is mostly untested and likely
|
||||
has bugs when the field ends in the middle of the number. */
|
||||
|
||||
void __scanf_start(struct __scanf_input *in)
|
||||
{
|
||||
if(in->fp)
|
||||
in->buffer = fgetc(in->fp);
|
||||
else {
|
||||
in->buffer = (*in->str ? *in->str : EOF);
|
||||
in->str += (in->buffer != EOF);
|
||||
}
|
||||
}
|
||||
|
||||
int __scanf_fetch(struct __scanf_input *in)
|
||||
{
|
||||
if(in->fp)
|
||||
return fgetc(in->fp);
|
||||
|
||||
int c = *in->str;
|
||||
if(c == 0)
|
||||
return EOF;
|
||||
in->str++;
|
||||
return c;
|
||||
}
|
||||
|
||||
void __scanf_end(struct __scanf_input *in)
|
||||
{
|
||||
if(in->buffer == EOF)
|
||||
return;
|
||||
|
||||
if(in->fp)
|
||||
ungetc(in->buffer, in->fp);
|
||||
else
|
||||
in->str--;
|
||||
}
|
||||
|
||||
static void __skip_spaces(struct __scanf_input *in)
|
||||
{
|
||||
while(isspace(__scanf_peek(in)))
|
||||
__scanf_in(in);
|
||||
}
|
||||
|
||||
static void __scanf_store_i(int64_t value, int size, va_list *args)
|
||||
{
|
||||
if(size == 1)
|
||||
*va_arg(*args, int8_t *) = value;
|
||||
else if(size == 2)
|
||||
*va_arg(*args, int16_t *) = value;
|
||||
else if(size == 4)
|
||||
*va_arg(*args, int32_t *) = value;
|
||||
else if(size == 8)
|
||||
*va_arg(*args, int64_t *) = value;
|
||||
}
|
||||
|
||||
static void __scanf_store_d(long double value, int size, va_list *args)
|
||||
{
|
||||
if(size == sizeof(float))
|
||||
*va_arg(*args, float *) = value;
|
||||
else if(size == sizeof(double))
|
||||
*va_arg(*args, double *) = value;
|
||||
else if(size == sizeof(long double))
|
||||
*va_arg(*args, long double *) = value;
|
||||
}
|
||||
|
||||
struct scanf_format {
|
||||
/* Maximum field width */
|
||||
int field_width;
|
||||
/* Size of the assigned (integer or floating-point) type, in bytes */
|
||||
uint8_t size;
|
||||
/* Whether to skip assignment */
|
||||
bool skip;
|
||||
/* Set of bytes allowed for bracket sets in %[] */
|
||||
uint8_t bracket_set[32];
|
||||
};
|
||||
|
||||
/* Allow/disallow the entire set */
|
||||
static void bracket_set_init(uint8_t *set, bool allow)
|
||||
{
|
||||
memset(set, allow ? 0xff : 0x00, 32);
|
||||
}
|
||||
|
||||
/* Allow/disallow a range of characters. Both ends are included. */
|
||||
static void bracket_set_range(
|
||||
uint8_t *set, uint8_t start, uint8_t end, bool allow)
|
||||
{
|
||||
for(int u = start; u <= end; u++) {
|
||||
int byte = u >> 3;
|
||||
int bit = 1 << (u & 7);
|
||||
if(allow)
|
||||
set[byte] |= bit;
|
||||
else
|
||||
set[byte] &= ~bit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether a byte is allowed by the bracket set. */
|
||||
static bool bracket_set_test(uint8_t *set, int c)
|
||||
{
|
||||
return (c != EOF) && (set[c >> 3] & (1 << (c & 7)));
|
||||
}
|
||||
|
||||
/* Parse a bracket set from a format string. Returns true on success. */
|
||||
static bool bracket_set_parse(uint8_t *set, char const *format, int *pos)
|
||||
{
|
||||
int last = 0;
|
||||
bool allow = true;
|
||||
bracket_set_init(set, false);
|
||||
|
||||
/* '^' denotes a negated set */
|
||||
if(format[*pos] == '^') {
|
||||
allow = false;
|
||||
(*pos)++;
|
||||
bracket_set_init(set, true);
|
||||
}
|
||||
/* ']' as the first character adds ']' to the set */
|
||||
if(format[*pos] == ']' ) {
|
||||
bracket_set_range(set, ']', ']', allow);
|
||||
(*pos)++;
|
||||
}
|
||||
|
||||
for(; format[*pos] && format[*pos] != ']'; (*pos)++) {
|
||||
/* '-' as the last character, thus explicitly in the set */
|
||||
if(format[*pos] == '-' && format[*pos + 1] == ']')
|
||||
bracket_set_range(set, '-', '-', allow);
|
||||
/* '-' as denoting a range */
|
||||
else if(format[*pos] == '-') {
|
||||
(*pos)++;
|
||||
bracket_set_range(set, last, format[*pos], allow);
|
||||
}
|
||||
/* Any other character */
|
||||
else {
|
||||
last = format[*pos];
|
||||
bracket_set_range(set, last, last, allow);
|
||||
}
|
||||
}
|
||||
|
||||
return (format[*pos] == ']');
|
||||
}
|
||||
|
||||
/* Parse a format in the format string. Returns specifier, 0 on error. */
|
||||
static int parse_fmt(char const *fmt, int *pos, struct scanf_format *opt)
|
||||
{
|
||||
opt->field_width = INT_MAX;
|
||||
opt->size = sizeof(int);
|
||||
opt->skip = false;
|
||||
|
||||
int width = 0;
|
||||
char size_letter = 0;
|
||||
|
||||
for((*pos)++;; (*pos)++) {
|
||||
int c = fmt[*pos];
|
||||
|
||||
if(c == '*')
|
||||
opt->skip = true;
|
||||
else if(strchr("hlzjtL", c)) {
|
||||
if(c == 'h')
|
||||
opt->size = (size_letter=='h') ? sizeof(char) : sizeof(short);
|
||||
else if(c == 'l')
|
||||
opt->size = (size_letter=='l') ? sizeof(long long) :
|
||||
sizeof(long);
|
||||
else if(c == 'z')
|
||||
opt->size = sizeof(size_t);
|
||||
else if(c == 'j')
|
||||
opt->size = sizeof(intmax_t);
|
||||
else if(c == 't')
|
||||
opt->size = sizeof(ptrdiff_t);
|
||||
else if(c == 'L')
|
||||
opt->size = sizeof(long double);
|
||||
|
||||
size_letter = c;
|
||||
}
|
||||
else if(isdigit(c)) {
|
||||
width = width * 10 + (fmt[*pos] - '0');
|
||||
opt->field_width = width;
|
||||
}
|
||||
else if(c == '[') {
|
||||
(*pos)++;
|
||||
return bracket_set_parse(opt->bracket_set, fmt, pos) ? '[' : 0;
|
||||
}
|
||||
else if(strchr("diouxXpsn", c))
|
||||
return c;
|
||||
else if(strchr("aAeEfFgG", c)) {
|
||||
/* Adjust interpretation of no size / 'l' size */
|
||||
if(size_letter == 0)
|
||||
opt->size = sizeof(float);
|
||||
if(size_letter == 'l')
|
||||
opt->size = sizeof(double);
|
||||
return c;
|
||||
}
|
||||
else if(c == 'c') {
|
||||
if(opt->field_width == INT_MAX)
|
||||
opt->field_width = 1;
|
||||
return c;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __scanf(
|
||||
struct __scanf_input * __restrict__ in,
|
||||
char const * __restrict__ format,
|
||||
va_list *args)
|
||||
{
|
||||
/* Number of successful assignments */
|
||||
int validrets = 0;
|
||||
|
||||
for(int pos = 0; format[pos]; pos++) {
|
||||
if(format[pos] == ' ') {
|
||||
__skip_spaces(in);
|
||||
continue;
|
||||
}
|
||||
else if(format[pos] != '%' || format[pos + 1] == '%') {
|
||||
/* Expect this specific character */
|
||||
if(__scanf_peek(in) != format[pos])
|
||||
return validrets;
|
||||
__scanf_in(in);
|
||||
pos += (format[pos] == '%');
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Perform a conversion */
|
||||
struct scanf_format opt;
|
||||
int spec = parse_fmt(format, &pos, &opt);
|
||||
if(spec == 0)
|
||||
return validrets;
|
||||
|
||||
switch(spec) {
|
||||
case '[': {
|
||||
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
||||
int i;
|
||||
for(i = 0; i < opt.field_width; i++) {
|
||||
int temp = __scanf_peek(in);
|
||||
if(bracket_set_test(opt.bracket_set, temp)) {
|
||||
__scanf_in(in);
|
||||
if(c) *c++ = temp;
|
||||
}
|
||||
else if(temp==EOF && !i && !validrets)
|
||||
return EOF;
|
||||
else break;
|
||||
}
|
||||
if(!i)
|
||||
return validrets;
|
||||
*c = '\0';
|
||||
validrets += !opt.skip;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n':
|
||||
__scanf_store_i(in->bytes_read, opt.size, args);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X': {
|
||||
int f = format[pos];
|
||||
int base = (f == 'd' || f == 'u') ? 10 :
|
||||
(f == 'o') ? 8:
|
||||
(f == 'x' || f == 'X') ? 16 : 0;
|
||||
bool use_unsigned = (f == 'o' || f == 'x' || f == 'X');
|
||||
|
||||
long long int temp;
|
||||
int err = __strto_int(in, base, NULL, &temp, use_unsigned,
|
||||
opt.field_width);
|
||||
if(err == EOF && validrets == 0) return EOF;
|
||||
if(err) return validrets;
|
||||
if(!opt.skip)
|
||||
__scanf_store_i(temp, opt.size, args);
|
||||
validrets++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
case 'A':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G': {
|
||||
long double temp;
|
||||
int err = __strto_fp(in, NULL, NULL, &temp, opt.field_width);
|
||||
if(err == EOF && validrets == 0) return EOF;
|
||||
if(err) return validrets;
|
||||
if(!opt.skip)
|
||||
__scanf_store_d(temp, opt.size, args);
|
||||
validrets++;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p': {
|
||||
void *p = opt.skip ? NULL : va_arg(*args, void *);
|
||||
_Static_assert(sizeof(p) == sizeof(long));
|
||||
int err = __strto_int(in, 0, p, NULL, true, opt.field_width);
|
||||
if(err) return validrets;
|
||||
validrets += !opt.skip;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c': {
|
||||
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
||||
|
||||
for(int u = 0; u < opt.field_width; u++) {
|
||||
int temp = __scanf_in(in);
|
||||
if(temp==EOF) return EOF;
|
||||
else if(c) *c++ = temp;
|
||||
}
|
||||
validrets += !opt.skip;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
char *c = opt.skip ? NULL : va_arg(*args, char *);
|
||||
__skip_spaces(in);
|
||||
|
||||
for(int i = 0; i < opt.field_width; i++) {
|
||||
int temp = __scanf_peek(in);
|
||||
if(temp==EOF && !i) return validrets;
|
||||
if(isspace(temp) || temp==EOF) {
|
||||
if(c) {
|
||||
*c = 0;
|
||||
validrets++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
int temp = __scanf_in(in);
|
||||
if(c) *c++ = temp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validrets;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int sscanf(const char * restrict str, char const * restrict fmt, ...)
|
||||
{
|
||||
struct __scanf_input in = {
|
||||
.str = str,
|
||||
};
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
__scanf_start(&in);
|
||||
int count = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
|
||||
va_end(args);
|
||||
return count;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
#ifndef __STDIO_P_H__
|
||||
# define __STDIO_P_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
** General utilities for scanf(); we expose them here as we use subfunctions of
|
||||
** strto*() from <stdlib.h> to implement numerical specifiers.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Input for scanf; exactly one of str and fp must be non-NULL. We include a
|
||||
** single-character buffer for convenience for scanning functions to test the
|
||||
** next character, which can be flushed back by ungetc().
|
||||
*/
|
||||
struct __scanf_input {
|
||||
char const * __restrict__ str;
|
||||
FILE *fp;
|
||||
|
||||
/* Single-character lookahead buffer */
|
||||
int buffer;
|
||||
|
||||
/* Total numbers of bytes read in a scall to *scanf() */
|
||||
int bytes_read;
|
||||
};
|
||||
|
||||
/* Generic formatted scaning. */
|
||||
extern int __scanf(
|
||||
struct __scanf_input * __restrict__ __in,
|
||||
char const * __restrict__ __format,
|
||||
va_list *__args);
|
||||
|
||||
|
||||
/* Initialize the input by feeding the buffer byte. */
|
||||
void __scanf_start(struct __scanf_input *__in);
|
||||
|
||||
/* Fetch the next byte from the input and return it (don't call directly). */
|
||||
int __scanf_fetch(struct __scanf_input *__in);
|
||||
|
||||
/* Read the next byte while maintaining the buffer. */
|
||||
static inline int __scanf_in(struct __scanf_input *__in)
|
||||
{
|
||||
int c = __in->buffer;
|
||||
__in->buffer = __scanf_fetch(__in);
|
||||
__in->bytes_read++;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read the next byte and also decrease a total count of available reads. */
|
||||
static inline int __scanf_in_limit(struct __scanf_input *__in, int *__N)
|
||||
{
|
||||
(*__N)--;
|
||||
return __scanf_in(__in);
|
||||
}
|
||||
|
||||
/* Peek the next byte without advancing. */
|
||||
static inline int __scanf_peek(struct __scanf_input *__in)
|
||||
{
|
||||
return __in->buffer;
|
||||
}
|
||||
|
||||
/* Close the input by unsending the buffer once finished. */
|
||||
void __scanf_end(struct __scanf_input *__in);
|
||||
|
||||
#endif /* __STDIO_P_H__ */
|
|
@ -1,14 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int vfscanf(FILE * restrict fp, char const * restrict fmt, va_list args)
|
||||
{
|
||||
struct __scanf_input in = {
|
||||
.fp = fp,
|
||||
};
|
||||
|
||||
__scanf_start(&in);
|
||||
int rc = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
return rc;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int vscanf(char const * restrict fmt, va_list args)
|
||||
{
|
||||
struct __scanf_input in = {
|
||||
.fp = stdin,
|
||||
};
|
||||
|
||||
__scanf_start(&in);
|
||||
int rc = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
return rc;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "stdio_p.h"
|
||||
|
||||
int vsscanf(const char * restrict str, char const * restrict fmt, va_list args)
|
||||
{
|
||||
/* This is valid even if str=NULL. */
|
||||
struct __scanf_input in = {
|
||||
.str = str,
|
||||
};
|
||||
|
||||
__scanf_start(&in);
|
||||
int rc = __scanf(&in, fmt, &args);
|
||||
__scanf_end(&in);
|
||||
return rc;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
extern int __cxa_atexit(void (*f)(void *), void *p, void *d);
|
||||
|
||||
int atexit(void (*f)(void))
|
||||
{
|
||||
return __cxa_atexit((void (*)(void *))f, NULL, NULL);
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
extern void __cxa_finalize(void *d);
|
||||
|
||||
void exit(int rc)
|
||||
{
|
||||
__cxa_finalize(NULL);
|
||||
|
||||
/* TODO: invoke atexit callbacks */
|
||||
/* TODO: exit: Flush all streams */
|
||||
/* TODO: exit: Close all streams */
|
||||
/* TODO: exit: Remove temporary files */
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include "../stdio/stdio_p.h"
|
||||
|
||||
/*
|
||||
** Parse an integer from a string. This is the base function for strtol,
|
||||
|
@ -23,17 +21,14 @@
|
|||
** On platforms where long is 32-bit, 64-bit operations are performed only if
|
||||
** outll is non-NULL. This is because multiplications with overflow can be
|
||||
** expensive.
|
||||
**
|
||||
** N is the bound on the number of characters to read. To disable the bound,
|
||||
** specify INT_MAX.
|
||||
*/
|
||||
int __strto_int(
|
||||
struct __scanf_input *__input,
|
||||
char const * restrict __ptr,
|
||||
char ** restrict __endptr,
|
||||
int __base,
|
||||
long *__outl,
|
||||
long long *__outll,
|
||||
bool __use_unsigned,
|
||||
int __N);
|
||||
bool __use_unsigned);
|
||||
|
||||
/*
|
||||
** Parse a floating-point value from a string. This is the base function for
|
||||
|
@ -44,10 +39,10 @@ int __strto_int(
|
|||
** and outl is set.
|
||||
*/
|
||||
int __strto_fp(
|
||||
struct __scanf_input *__input,
|
||||
double *__out,
|
||||
float *__outf,
|
||||
long double *__outl,
|
||||
int __N);
|
||||
char const * restrict __ptr,
|
||||
char ** restrict __endptr,
|
||||
double *__out,
|
||||
float *__outf,
|
||||
long double *__outl);
|
||||
|
||||
#endif /*__STDLIB_P_H__*/
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include "stdlib_p.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -38,11 +37,12 @@
|
|||
** -> In hexadecimal notation, we read as many bits as the mantissa of a long
|
||||
** double, then later multiply by a power of 2. There are no approximations.
|
||||
*/
|
||||
static int parse_digits(struct __scanf_input *input,
|
||||
SIGNIFICAND_TYPE *digits, long *exponent, bool hexadecimal, int *N)
|
||||
static void parse_digits(char const * restrict *ptr0, bool *valid,
|
||||
SIGNIFICAND_TYPE *digits, long *exponent, bool hexadecimal)
|
||||
{
|
||||
char const *ptr = *ptr0;
|
||||
bool dot_found = false;
|
||||
int digits_found=0, c=0;
|
||||
int digits_found = 0;
|
||||
|
||||
*digits = 0;
|
||||
*exponent = 0;
|
||||
|
@ -53,16 +53,13 @@ static int parse_digits(struct __scanf_input *input,
|
|||
int dot_character = '.';
|
||||
int exp_character = (hexadecimal ? 'p' : 'e');
|
||||
|
||||
for(int i = 0; *N >= 0; i++) {
|
||||
c = __scanf_peek(input);
|
||||
if(i == 0 && c == EOF)
|
||||
return EOF;
|
||||
if(!(isdigit(c) ||
|
||||
(hexadecimal && isxdigit(c)) ||
|
||||
(c == dot_character && !dot_found))) break;
|
||||
__scanf_in_limit(input, N);
|
||||
for(int i = 0; isdigit(*ptr) || (hexadecimal && isxdigit(*ptr))
|
||||
|| *ptr == dot_character; i++, ptr++) {
|
||||
|
||||
if(c == dot_character) {
|
||||
/* Allow only one dot in the string, stop at the second one */
|
||||
if(*ptr == dot_character && dot_found) break;
|
||||
|
||||
if(*ptr == dot_character) {
|
||||
dot_found = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -70,12 +67,12 @@ static int parse_digits(struct __scanf_input *input,
|
|||
/* Count digits only until SIGNIFICAND_DIGITS */
|
||||
if(digits_found < max_digits) {
|
||||
if(hexadecimal) {
|
||||
int v = c - '0';
|
||||
if(!isdigit(c)) v = tolower(c) - 'a' + 10;
|
||||
int v = *ptr - '0';
|
||||
if(!isdigit(*ptr)) v = tolower(*ptr)-'a'+10;
|
||||
*digits = (*digits << 4) + v;
|
||||
}
|
||||
else {
|
||||
*digits = (*digits * 10) + (c - '0');
|
||||
*digits = (*digits * 10) + (*ptr - '0');
|
||||
}
|
||||
}
|
||||
else (*exponent)++;
|
||||
|
@ -83,7 +80,7 @@ static int parse_digits(struct __scanf_input *input,
|
|||
if(dot_found) (*exponent)--;
|
||||
|
||||
/* But also round at the first discarded one */
|
||||
if(digits_found == max_digits && c >= '5')
|
||||
if(digits_found == max_digits && *ptr >= '5')
|
||||
(*digits)++;
|
||||
|
||||
digits_found++;
|
||||
|
@ -91,60 +88,46 @@ static int parse_digits(struct __scanf_input *input,
|
|||
|
||||
/* Require at least one digit to be present; if not, the whole string
|
||||
is considered invalid */
|
||||
if(!digits_found)
|
||||
return false;
|
||||
if(!digits_found) {
|
||||
*valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* In hexadecimal, each character is worth 4 bits of exponent */
|
||||
if(hexadecimal) (*exponent) *= 4;
|
||||
|
||||
/* Parse exponent */
|
||||
if(tolower(__scanf_peek(input)) == exp_character) {
|
||||
/* Hack: Restore the str pointer if this fails (which we
|
||||
cannot determine with a single lookahead) so that *endptr is
|
||||
set correctly */
|
||||
struct __scanf_input backup = *input;
|
||||
if(tolower(*ptr) == exp_character) {
|
||||
char *end;
|
||||
long e = strtol(ptr + 1, &end, 10);
|
||||
|
||||
__scanf_in_limit(input, N);
|
||||
long e = 0;
|
||||
// TODO: strto_fp: Pass limit to __strto_int
|
||||
if(__strto_int(input, 10, &e, NULL, false, *N) == 0)
|
||||
/* If an integer cannot be parsed, ignore the 'e...' part */
|
||||
if(end != ptr + 1) {
|
||||
ptr = end;
|
||||
*exponent += e;
|
||||
else
|
||||
*input = backup;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
*ptr0 = ptr;
|
||||
*valid = true;
|
||||
}
|
||||
|
||||
static bool expect(struct __scanf_input *input, char const *sequence)
|
||||
int __strto_fp(char const * restrict ptr, char ** restrict endptr, double *out,
|
||||
float *outf, long double *outl)
|
||||
{
|
||||
for(int i = 0; sequence[i]; i++) {
|
||||
int c = __scanf_in(input);
|
||||
if(tolower(c) != tolower(sequence[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* Save the value of ptr in endptr, in case format is invalid */
|
||||
if(endptr) *endptr = (char *)ptr;
|
||||
|
||||
int __strto_fp(struct __scanf_input *input, double *out, float *outf,
|
||||
long double *outl, int N)
|
||||
{
|
||||
/* Skip initial whitespace */
|
||||
while(isspace(__scanf_peek(input))) __scanf_in(input);
|
||||
|
||||
// TODO: strto_fp() doesn't support size limits well, affecting %5f etc.
|
||||
|
||||
if(N <= 0)
|
||||
return EOF;
|
||||
while(isspace(*ptr)) ptr++;
|
||||
|
||||
/* Read optional sign */
|
||||
bool negative = false;
|
||||
int sign = __scanf_peek(input);
|
||||
if(sign == '-') negative = true;
|
||||
if(sign == '-' || sign == '+') __scanf_in_limit(input, &N);
|
||||
if(*ptr == '-') negative = true;
|
||||
if(*ptr == '-' || *ptr == '+') ptr++;
|
||||
|
||||
int errno_value = 0;
|
||||
bool valid = false;
|
||||
bool valid = true;
|
||||
|
||||
/* Result variable */
|
||||
if(out) *out = 0.0;
|
||||
|
@ -152,75 +135,47 @@ int __strto_fp(struct __scanf_input *input, double *out, float *outf,
|
|||
if(outl) *outl = 0.0l;
|
||||
|
||||
/* NaN possibly with an argument */
|
||||
if(tolower(__scanf_peek(input)) == 'n') {
|
||||
if(!expect(input, "nan"))
|
||||
return EINVAL;
|
||||
|
||||
/* Get the argument for up to 32 bytes */
|
||||
char arg[32];
|
||||
int i = 0;
|
||||
|
||||
if(__scanf_peek(input) == '(') {
|
||||
while(i < 31) {
|
||||
int c = __scanf_in_limit(input, &N);
|
||||
if(c == ')') break;
|
||||
if(c == EOF || N <= 0)
|
||||
return EOF;
|
||||
arg[i++] = c;
|
||||
}
|
||||
arg[i] = 0;
|
||||
if(!strncasecmp(ptr, "nan", 3)) {
|
||||
char const *arg = "";
|
||||
ptr += 3;
|
||||
if(ptr[0] == '(') {
|
||||
arg = ptr + 1;
|
||||
do ptr++;
|
||||
while(ptr[-1] != ')');
|
||||
}
|
||||
|
||||
if(out) *out = __builtin_nan(arg);
|
||||
if(outf) *outf = __builtin_nanf(arg);
|
||||
if(outl) *outl = __builtin_nanl(arg);
|
||||
valid = true;
|
||||
}
|
||||
else if(tolower(__scanf_peek(input)) == 'i') {
|
||||
if(!expect(input, "inf"))
|
||||
return EINVAL;
|
||||
if(tolower(__scanf_peek(input)) == 'i' &&
|
||||
!expect(input, "inity"))
|
||||
return EINVAL;
|
||||
/* Infinity */
|
||||
else if(!strncasecmp(ptr, "infinity", 8)) {
|
||||
if(out) *out = __builtin_inf();
|
||||
if(outf) *outf = __builtin_inff();
|
||||
if(outl) *outl = __builtin_infl();
|
||||
valid = true;
|
||||
ptr += 8;
|
||||
}
|
||||
else if(__scanf_peek(input) == EOF) {
|
||||
return EOF;
|
||||
else if(!strncasecmp(ptr, "inf", 3)) {
|
||||
if(out) *out = __builtin_inf();
|
||||
if(outf) *outf = __builtin_inff();
|
||||
if(outl) *outl = __builtin_infl();
|
||||
ptr += 3;
|
||||
}
|
||||
else {
|
||||
SIGNIFICAND_TYPE digits = 0;
|
||||
long e = 0;
|
||||
|
||||
/* Check for the 0x prefix. Skipping a 0 if we start with 0 but
|
||||
not 0x isn't a problem. */
|
||||
bool hexa = false;
|
||||
if(__scanf_peek(input) == '0') {
|
||||
__scanf_in_limit(input, &N);
|
||||
if(tolower(__scanf_peek(input)) == 'x') {
|
||||
__scanf_in_limit(input, &N);
|
||||
hexa = true;
|
||||
}
|
||||
/* Count the 0 as a digit */
|
||||
else valid = true;
|
||||
}
|
||||
if(ptr[0] == '0' && tolower(ptr[1]) == 'x') {
|
||||
ptr += 2;
|
||||
parse_digits(&ptr, &valid, &digits, &e, true);
|
||||
|
||||
if(hexa) {
|
||||
int rc = parse_digits(input, &digits, &e, true, &N);
|
||||
if(!valid && rc == EOF)
|
||||
return EOF;
|
||||
valid |= rc;
|
||||
if(out) *out = (double)digits * exp2(e);
|
||||
if(outf) *outf = (float)digits * exp2f(e);
|
||||
if(outl) *outl = (long double)digits * exp2l(e);
|
||||
}
|
||||
else {
|
||||
int rc = parse_digits(input, &digits, &e, false, &N);
|
||||
if(!valid && rc == EOF)
|
||||
return EOF;
|
||||
valid |= rc;
|
||||
parse_digits(&ptr, &valid, &digits, &e, false);
|
||||
|
||||
if(out) *out = (double)digits * pow(10, e);
|
||||
if(outf) *outf = (float)digits * powf(10, e);
|
||||
if(outl) *outl = (long double)digits * powl(10, e);
|
||||
|
@ -245,5 +200,8 @@ int __strto_fp(struct __scanf_input *input, double *out, float *outf,
|
|||
if(outl) *outl = -(*outl);
|
||||
}
|
||||
|
||||
return valid ? errno_value : EINVAL;
|
||||
/* Save the result pointer */
|
||||
if(endptr && valid) *endptr = (char *)ptr;
|
||||
|
||||
return errno_value;
|
||||
}
|
||||
|
|
|
@ -4,20 +4,19 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
int __strto_int(struct __scanf_input *input, int base, long *outl,
|
||||
long long *outll, bool use_unsigned, int N)
|
||||
int __strto_int(char const * restrict ptr, char ** restrict endptr, int base,
|
||||
long *outl, long long *outll, bool use_unsigned)
|
||||
{
|
||||
/* Skip initial whitespace */
|
||||
while(isspace(__scanf_peek(input))) __scanf_in(input);
|
||||
/* Save the value of ptr in endptr now in case the format is invalid */
|
||||
if(endptr) *endptr = (char *)ptr;
|
||||
|
||||
if(N <= 0)
|
||||
return EOF;
|
||||
/* Skip initial whitespace */
|
||||
while(isspace(*ptr)) ptr++;
|
||||
|
||||
/* Accept a sign character */
|
||||
bool negative = false;
|
||||
int sign = __scanf_peek(input);
|
||||
if(sign == '-') negative = true;
|
||||
if(sign == '-' || sign == '+') __scanf_in_limit(input, &N);
|
||||
if(*ptr == '-') negative = true;
|
||||
if(*ptr == '-' || *ptr == '+') ptr++;
|
||||
|
||||
/* Use unsigned variables as only these have defined overflow */
|
||||
unsigned long xl = 0;
|
||||
|
@ -27,36 +26,29 @@ int __strto_int(struct __scanf_input *input, int base, long *outl,
|
|||
bool valid = false;
|
||||
|
||||
/* Read prefixes and determine base */
|
||||
if(__scanf_peek(input) == '0') {
|
||||
__scanf_in_limit(input, &N);
|
||||
if((base == 0 || base == 16) &&
|
||||
tolower(__scanf_peek(input)) == 'x') {
|
||||
__scanf_in_limit(input, &N);
|
||||
base = 16;
|
||||
}
|
||||
/* If we don't consume the x then count the 0 as a digit */
|
||||
else valid = true;
|
||||
if(base == 0)
|
||||
base = 8;
|
||||
if((base == 0 || base == 16) && ptr[0]=='0' && tolower(ptr[1])=='x') {
|
||||
ptr += 2;
|
||||
base = 16;
|
||||
}
|
||||
if(!valid && (N <= 0 || __scanf_peek(input) == EOF))
|
||||
return EOF;
|
||||
if(base == 0)
|
||||
else if(base == 0 && ptr[0] == '0') {
|
||||
ptr++;
|
||||
base = 8;
|
||||
}
|
||||
else if(base == 0) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
/* Read digits */
|
||||
while(N > 0) {
|
||||
while(1) {
|
||||
int v = -1;
|
||||
int c = __scanf_peek(input);
|
||||
if(isdigit(c)) v = c - '0';
|
||||
if(islower(c)) v = c - 'a' + 10;
|
||||
if(isdigit(*ptr)) v = *ptr - '0';
|
||||
if(islower(*ptr)) v = *ptr - 'a' + 10;
|
||||
if(v == -1 || v >= base) break;
|
||||
|
||||
/* The value is valid as long as there is at least one digit */
|
||||
valid = true;
|
||||
|
||||
/* (x = base*x + v) but with overflow checks */
|
||||
/* TODO: strto_int: We might fail to represent [L]LONG_MIN */
|
||||
if(outl) {
|
||||
if(__builtin_umull_overflow(xl, base, &xl))
|
||||
errno_value = ERANGE;
|
||||
|
@ -70,7 +62,7 @@ int __strto_int(struct __scanf_input *input, int base, long *outl,
|
|||
errno_value = ERANGE;
|
||||
}
|
||||
|
||||
__scanf_in_limit(input, &N);
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Handle sign and range */
|
||||
|
@ -109,6 +101,6 @@ int __strto_int(struct __scanf_input *input, int base, long *outl,
|
|||
|
||||
if(outl) *outl = xl;
|
||||
if(outll) *outll = xll;
|
||||
|
||||
return valid ? errno_value : EINVAL;
|
||||
if(endptr && valid) *endptr = (char *)ptr;
|
||||
return errno_value;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,7 @@
|
|||
double strtod(char const * restrict ptr, char ** restrict endptr)
|
||||
{
|
||||
double d = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_fp(&in, &d, NULL, NULL, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_fp(ptr, endptr, &d, NULL, NULL);
|
||||
if(err != 0) errno = err;
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,7 @@
|
|||
float strtof(char const * restrict ptr, char ** restrict endptr)
|
||||
{
|
||||
float f = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_fp(&in, NULL, &f, NULL, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_fp(ptr, endptr, NULL, &f, NULL);
|
||||
if(err != 0) errno = err;
|
||||
return f;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,7 @@
|
|||
long int strtol(char const * restrict ptr, char ** restrict endptr, int base)
|
||||
{
|
||||
long n = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_int(&in, base, &n, NULL, false, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_int(ptr, endptr, base, &n, NULL, false);
|
||||
if(err != 0) errno = err;
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,7 @@
|
|||
long double strtold(char const * restrict ptr, char ** restrict endptr)
|
||||
{
|
||||
long double ld = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_fp(&in, NULL, NULL, &ld, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_fp(ptr, endptr, NULL, NULL, &ld);
|
||||
if(err != 0) errno = err;
|
||||
return ld;
|
||||
}
|
||||
|
|
|
@ -5,17 +5,7 @@ long long int strtoll(char const * restrict ptr, char ** restrict endptr,
|
|||
int base)
|
||||
{
|
||||
long long n = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_int(&in, base, NULL, &n, false, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_int(ptr, endptr, base, NULL, &n, false);
|
||||
if(err != 0) errno = err;
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -5,17 +5,7 @@ unsigned long int strtoul(char const * restrict ptr, char ** restrict endptr,
|
|||
int base)
|
||||
{
|
||||
unsigned long n = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_int(&in, base, (long *)&n, NULL, true, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_int(ptr, endptr, base, (long *)&n, NULL, true);
|
||||
if(err != 0) errno = err;
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -5,17 +5,7 @@ unsigned long long int strtoull(char const * restrict ptr,
|
|||
char ** restrict endptr, int base)
|
||||
{
|
||||
unsigned long long n = 0;
|
||||
if(endptr)
|
||||
*endptr = (char *)ptr;
|
||||
|
||||
struct __scanf_input in = { .str = ptr, .fp = NULL };
|
||||
__scanf_start(&in);
|
||||
int err = __strto_int(&in, base, NULL, (long long *)&n, true, INT_MAX);
|
||||
__scanf_end(&in);
|
||||
|
||||
if(err != 0)
|
||||
errno = (err == EOF) ? EINVAL : err;
|
||||
if(err != EINVAL && endptr)
|
||||
*endptr = (char *)in.str;
|
||||
int err = __strto_int(ptr, endptr, base, NULL, (long long *)&n, true);
|
||||
if(err != 0) errno = err;
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ int strcmp(const char *s1, const char *s2)
|
|||
s1 += 1;
|
||||
s2 += 1;
|
||||
}
|
||||
return ((unsigned char) *s1 - (unsigned char) *s2);
|
||||
return (*s1 - *s2);
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@ int strncmp(const char *s1, const char *s2, size_t n)
|
|||
size_t i = -1;
|
||||
while (++i < n - 1 && s1[i] != '\0' && s2[i] != '\0'
|
||||
&& s1[i] == s2[i]) ;
|
||||
return ((unsigned char) s1[i] - (unsigned char) s2[i]);
|
||||
return (s1[i] - s2[i]);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ static const char *month_names[12] = {
|
|||
}; break
|
||||
/* Perform a sub-call to strftime to expand a complex format */
|
||||
#define do_strftime(fmt) { \
|
||||
size_t _written = strftime(s+len, n-len, fmt, time); \
|
||||
size_t _written = strftime2(s+len, n-len, fmt, time); \
|
||||
if(_written == 0) goto full; \
|
||||
len += _written; \
|
||||
}; break
|
||||
|
||||
size_t strftime(char * restrict s, size_t n, const char * restrict format,
|
||||
size_t strftime2(char * restrict s, size_t n, const char * restrict format,
|
||||
const struct tm * restrict time)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
|
22
vxsdk.toml
22
vxsdk.toml
|
@ -1,26 +1,14 @@
|
|||
[project]
|
||||
name = 'fxlibc'
|
||||
version = '1.4.1'
|
||||
type = 'app'
|
||||
target = [
|
||||
'superh'
|
||||
]
|
||||
|
||||
[superh.build]
|
||||
configure = """ \
|
||||
cmake \
|
||||
-B build-vhex \
|
||||
-DFXLIBC_PIC=1 \
|
||||
-DFXLIBC_TARGET=vhex-sh \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-vhex.cmake
|
||||
"""
|
||||
build = 'cmake --build build-vhex'
|
||||
install = 'cmake --install build-vhex'
|
||||
[build]
|
||||
configure = 'cmake -DFXLIBC_PIC=1 -DFXLIBC_TARGET=vhex-sh -B build-vhex -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-vhex.cmake'
|
||||
build = 'make -C build-vhex'
|
||||
install = 'make -C build-vhex install'
|
||||
uninstall = """ \
|
||||
if [ -e build-vhex/install_manifest.txt ]; then \
|
||||
xargs rm -f < build-vhex/install_manifest.txt; \
|
||||
fi \
|
||||
"""
|
||||
|
||||
[superh.dependencies]
|
||||
vxOpenLibm = 'master@superh'
|
||||
sh-elf-vhex = 'master@superh'
|
||||
|
|
Loading…
Reference in New Issue