mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-20 11:06:41 -05:00
Maintenance (#114)
This commit is contained in:
parent
cb834226a7
commit
84319ac0b2
25 changed files with 138 additions and 64 deletions
9
.github/workflows/main.yml
vendored
9
.github/workflows/main.yml
vendored
|
@ -137,10 +137,5 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: dependencies
|
- name: dependencies
|
||||||
run: sudo apt-get --yes install cppcheck
|
run: sudo apt-get --yes install cppcheck
|
||||||
- name: cppcheck source code
|
- name: cppcheck
|
||||||
# TODO: don't suppress "src/printf.c"
|
run: cppcheck --quiet --error-exitcode=1 --std=c99 --enable=warning,style,performance,portability --inline-suppr examples/ include/ libc/ src/ tests/
|
||||||
run: cppcheck --quiet --error-exitcode=1 --std=c99 --enable=warning,style,performance,portability --suppress='*:src/printf.c' include/ src/ libc/
|
|
||||||
- name: cppcheck examples
|
|
||||||
run: cppcheck --quiet --error-exitcode=1 --std=c99 --enable=warning,style,performance,portability --suppress=duplicateExpression --suppress=staticStringCompare examples/
|
|
||||||
- name: cppcheck tests
|
|
||||||
run: cppcheck --quiet --error-exitcode=1 --std=c99 --enable=warning,style,performance,portability --suppress=unusedStructMember tests/
|
|
||||||
|
|
|
@ -62,6 +62,13 @@ Avoid stupid errors with:
|
||||||
* Default case in switch statements
|
* Default case in switch statements
|
||||||
* Braces (curly brackets) around code blocks
|
* Braces (curly brackets) around code blocks
|
||||||
|
|
||||||
|
### Things to review periodically
|
||||||
|
|
||||||
|
* `git grep -i fixme`
|
||||||
|
* `git grep -i todo`
|
||||||
|
* `git grep -i cppcheck-suppress`
|
||||||
|
* `git grep -i rubocop:disable`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
C language
|
C language
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
2022-12-01 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
|
* src/printf.c: Fix a bug with too big float precision
|
||||||
|
|
||||||
2022-11-30 Alex Kotov <kotovalexarian@gmail.com>
|
2022-11-30 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
* configure.ac: Fix CFLAGS setting
|
* configure.ac: Fix CFLAGS setting
|
||||||
|
@ -10,6 +14,10 @@
|
||||||
"KERNAUX_RETURNS_TWICE", "KERNAUX_ASM"
|
"KERNAUX_RETURNS_TWICE", "KERNAUX_ASM"
|
||||||
* include/kernaux/printf_fmt.h: Make stable
|
* include/kernaux/printf_fmt.h: Make stable
|
||||||
|
|
||||||
|
2022-11-27 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
|
* src/free_list.c: Bug fixed
|
||||||
|
|
||||||
2022-11-26 Alex Kotov <kotovalexarian@gmail.com>
|
2022-11-26 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
libkernaux 0.5.0 released
|
libkernaux 0.5.0 released
|
||||||
|
|
|
@ -30,7 +30,6 @@ lib_LTLIBRARIES = libkernaux.la
|
||||||
libkernaux_la_LIBADD =
|
libkernaux_la_LIBADD =
|
||||||
libkernaux_la_SOURCES = \
|
libkernaux_la_SOURCES = \
|
||||||
src/assert.c \
|
src/assert.c \
|
||||||
src/libc.h \
|
|
||||||
src/generic/malloc.c \
|
src/generic/malloc.c \
|
||||||
src/generic/mutex.c
|
src/generic/mutex.c
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ API
|
||||||
### Headers
|
### Headers
|
||||||
|
|
||||||
We use [semantic versioning](https://semver.org) for stable APIs. Stable APIs
|
We use [semantic versioning](https://semver.org) for stable APIs. Stable APIs
|
||||||
can only change when major version number is increased (or minor while major is
|
may only change when major version number is increased (or minor while major is
|
||||||
zero). Work-in-progress APIs can change at any time.
|
zero). Work-in-progress APIs can change at any time.
|
||||||
|
|
||||||
* Basic features
|
* Basic features
|
||||||
|
|
|
@ -37,7 +37,7 @@ void mrb_mruby_kernaux_gem_init(mrb_state *const mrb)
|
||||||
#endif // KERNAUX_VERSION_WITH_PRINTF
|
#endif // KERNAUX_VERSION_WITH_PRINTF
|
||||||
}
|
}
|
||||||
|
|
||||||
void current_mrb_start(mrb_state *mrb)
|
void current_mrb_start(mrb_state *const mrb)
|
||||||
{
|
{
|
||||||
mrb_assert(mrb_stack_count < MRB_STACK_SIZE - 1);
|
mrb_assert(mrb_stack_count < MRB_STACK_SIZE - 1);
|
||||||
mrb_assert(mrb_stack[mrb_stack_count] == NULL);
|
mrb_assert(mrb_stack[mrb_stack_count] == NULL);
|
||||||
|
@ -46,7 +46,7 @@ void current_mrb_start(mrb_state *mrb)
|
||||||
mrb_stack[mrb_stack_count++] = mrb;
|
mrb_stack[mrb_stack_count++] = mrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void current_mrb_finish(mrb_state *mrb)
|
void current_mrb_finish(mrb_state *const mrb)
|
||||||
{
|
{
|
||||||
mrb_assert(mrb_stack_count > 0);
|
mrb_assert(mrb_stack_count > 0);
|
||||||
mrb_assert(mrb_stack[mrb_stack_count - 1] != NULL);
|
mrb_assert(mrb_stack[mrb_stack_count - 1] != NULL);
|
||||||
|
|
|
@ -89,7 +89,43 @@
|
||||||
- result: '1.200000'
|
- result: '1.200000'
|
||||||
args: [['%f', 1.2]]
|
args: [['%f', 1.2]]
|
||||||
float: true
|
float: true
|
||||||
|
|
||||||
- result: '123.456789'
|
- result: '123.456789'
|
||||||
args: [['%f', 123.456789]]
|
args: [['%f', 123.456789]]
|
||||||
float: true
|
float: true
|
||||||
|
|
||||||
|
- result: '0.01234568'
|
||||||
|
args: [['%.8f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '0.012345679'
|
||||||
|
args: [['%.9f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
# Actual precision is no more than 9
|
||||||
|
- result: '0.0123456790'
|
||||||
|
args: [['%.10f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '0.01234567900'
|
||||||
|
args: [['%.11f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '0.012345679000'
|
||||||
|
args: [['%.12f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '0.012345679000000000000000000000'
|
||||||
|
args: [['%.30f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
# Actual length is no more than 32
|
||||||
|
- result: '0.012345679000000000000000000000'
|
||||||
|
args: [['%.31f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '0.012345679000000000000000000000'
|
||||||
|
args: [['%.32f', 0.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
# Actual length is no more than 32
|
||||||
|
- result: '10.01234567900000000000000000000'
|
||||||
|
args: [['%.32f', 10.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '100.0123456790000000000000000000'
|
||||||
|
args: [['%.32f', 100.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
- result: '1000.012345679000000000000000000'
|
||||||
|
args: [['%.32f', 1000.0123456789012345678901234567890123456789]]
|
||||||
|
float: true
|
||||||
|
|
|
@ -25,6 +25,7 @@ int main()
|
||||||
{
|
{
|
||||||
kernaux_assert_cb = assert_cb;
|
kernaux_assert_cb = assert_cb;
|
||||||
|
|
||||||
|
// cppcheck-suppress duplicateExpression
|
||||||
KERNAUX_ASSERT(1 == 1);
|
KERNAUX_ASSERT(1 == 1);
|
||||||
|
|
||||||
assert(count == 0);
|
assert(count == 0);
|
||||||
|
@ -32,6 +33,7 @@ int main()
|
||||||
assert(last_line == 0);
|
assert(last_line == 0);
|
||||||
assert(last_str == NULL);
|
assert(last_str == NULL);
|
||||||
|
|
||||||
|
// cppcheck-suppress duplicateExpression
|
||||||
KERNAUX_ASSERT(1 != 1);
|
KERNAUX_ASSERT(1 != 1);
|
||||||
|
|
||||||
assert(count == 1);
|
assert(count == 1);
|
||||||
|
@ -39,6 +41,7 @@ int main()
|
||||||
assert(last_line == __LINE__ - 4);
|
assert(last_line == __LINE__ - 4);
|
||||||
assert(strcmp(last_str, "1 != 1") == 0);
|
assert(strcmp(last_str, "1 != 1") == 0);
|
||||||
|
|
||||||
|
// cppcheck-suppress staticStringCompare
|
||||||
KERNAUX_ASSERT(strcmp("qwe", "rty") == 0);
|
KERNAUX_ASSERT(strcmp("qwe", "rty") == 0);
|
||||||
|
|
||||||
assert(count == 2);
|
assert(count == 2);
|
||||||
|
|
|
@ -35,12 +35,14 @@ static void *MyMalloc_realloc(void *malloc, void *ptr, size_t size);
|
||||||
|
|
||||||
struct MyMalloc MyMalloc_create()
|
struct MyMalloc MyMalloc_create()
|
||||||
{
|
{
|
||||||
struct MyMalloc my_malloc;
|
return (struct MyMalloc){
|
||||||
my_malloc.malloc.calloc = MyMalloc_calloc;
|
.malloc = {
|
||||||
my_malloc.malloc.free = MyMalloc_free;
|
.calloc = MyMalloc_calloc,
|
||||||
my_malloc.malloc.malloc = MyMalloc_malloc;
|
.free = MyMalloc_free,
|
||||||
my_malloc.malloc.realloc = MyMalloc_realloc;
|
.malloc = MyMalloc_malloc,
|
||||||
return my_malloc;
|
.realloc = MyMalloc_realloc,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MyMalloc_calloc(void *const malloc, const size_t nmemb, const size_t size)
|
void *MyMalloc_calloc(void *const malloc, const size_t nmemb, const size_t size)
|
||||||
|
|
|
@ -35,9 +35,12 @@ static void MyMutex_unlock(void *mutex);
|
||||||
|
|
||||||
struct MyMutex MyMutex_create()
|
struct MyMutex MyMutex_create()
|
||||||
{
|
{
|
||||||
struct MyMutex my_mutex;
|
struct MyMutex my_mutex = {
|
||||||
my_mutex.mutex.lock = MyMutex_lock;
|
.mutex = {
|
||||||
my_mutex.mutex.unlock = MyMutex_unlock;
|
.lock = MyMutex_lock,
|
||||||
|
.unlock = MyMutex_unlock,
|
||||||
|
},
|
||||||
|
};
|
||||||
if (pthread_mutex_init(&my_mutex.pthread_mutex, NULL) != 0) abort();
|
if (pthread_mutex_init(&my_mutex.pthread_mutex, NULL) != 0) abort();
|
||||||
return my_mutex;
|
return my_mutex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <kernaux/macro.h>
|
#include <kernaux/macro.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
const char *hello;
|
const char *hello;
|
||||||
|
@ -29,5 +30,6 @@ void example_main()
|
||||||
|
|
||||||
assert(bar_ptr->a == 143);
|
assert(bar_ptr->a == 143);
|
||||||
assert(bar_ptr->b == 820794098);
|
assert(bar_ptr->b == 820794098);
|
||||||
|
assert(strcmp(bar_ptr->foo.hello, "Hello, World!") == 0);
|
||||||
assert(bar_ptr->c == 10981);
|
assert(bar_ptr->c == 10981);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ static const struct {
|
||||||
// of type "KernAux_Multiboot2_HTag_InfoReq"
|
// of type "KernAux_Multiboot2_HTag_InfoReq"
|
||||||
// when the number of requested information
|
// when the number of requested information
|
||||||
// tag types is even (n % 2 == 0).
|
// tag types is even (n % 2 == 0).
|
||||||
|
//
|
||||||
|
// cppcheck-suppress unknownMacro
|
||||||
KERNAUX_MULTIBOOT2_HFIELDS_INFO_REQ_EVEN(
|
KERNAUX_MULTIBOOT2_HFIELDS_INFO_REQ_EVEN(
|
||||||
// This is the name of the structure field.
|
// This is the name of the structure field.
|
||||||
tag_info_req_even,
|
tag_info_req_even,
|
||||||
|
@ -22,6 +24,8 @@ static const struct {
|
||||||
// of type "KernAux_Multiboot2_HTag_InfoReq"
|
// of type "KernAux_Multiboot2_HTag_InfoReq"
|
||||||
// when the number of requested information
|
// when the number of requested information
|
||||||
// tag types is odd (n % 2 == 1).
|
// tag types is odd (n % 2 == 1).
|
||||||
|
//
|
||||||
|
// cppcheck-suppress unknownMacro
|
||||||
KERNAUX_MULTIBOOT2_HFIELDS_INFO_REQ_ODD(
|
KERNAUX_MULTIBOOT2_HFIELDS_INFO_REQ_ODD(
|
||||||
// This is the name of the structure field.
|
// This is the name of the structure field.
|
||||||
tag_info_req_odd,
|
tag_info_req_odd,
|
||||||
|
@ -34,6 +38,8 @@ static const struct {
|
||||||
_align1
|
_align1
|
||||||
)
|
)
|
||||||
// This macro may be used for all other header tag types.
|
// This macro may be used for all other header tag types.
|
||||||
|
//
|
||||||
|
// cppcheck-suppress unknownMacro
|
||||||
KERNAUX_MULTIBOOT2_HFIELDS_COMMON(
|
KERNAUX_MULTIBOOT2_HFIELDS_COMMON(
|
||||||
// This is the name of the structure field.
|
// This is the name of the structure field.
|
||||||
tag_none,
|
tag_none,
|
||||||
|
|
|
@ -12,7 +12,7 @@ static const char *const data = "foobar";
|
||||||
static char buffer[BUFFER_SIZE];
|
static char buffer[BUFFER_SIZE];
|
||||||
static size_t buffer_index = 0;
|
static size_t buffer_index = 0;
|
||||||
|
|
||||||
static void my_putchar(const char chr, void *arg)
|
static void my_putchar(const char chr, void *const arg)
|
||||||
{
|
{
|
||||||
assert(arg == data);
|
assert(arg == data);
|
||||||
if (buffer_index >= BUFFER_SIZE) abort();
|
if (buffer_index >= BUFFER_SIZE) abort();
|
||||||
|
|
|
@ -12,7 +12,7 @@ static const char *const data = "foobar";
|
||||||
static char buffer[BUFFER_SIZE];
|
static char buffer[BUFFER_SIZE];
|
||||||
static size_t buffer_index = 0;
|
static size_t buffer_index = 0;
|
||||||
|
|
||||||
static void my_putchar(const char chr, void *arg)
|
static void my_putchar(const char chr, void *const arg)
|
||||||
{
|
{
|
||||||
assert(arg == data);
|
assert(arg == data);
|
||||||
if (buffer_index >= BUFFER_SIZE) abort();
|
if (buffer_index >= BUFFER_SIZE) abort();
|
||||||
|
|
|
@ -7,9 +7,8 @@ extern "C" {
|
||||||
|
|
||||||
#include <kernaux/macro.h>
|
#include <kernaux/macro.h>
|
||||||
|
|
||||||
KERNAUX_NORETURN
|
KERNAUX_NORETURN void kernaux_drivers_shutdown_halt();
|
||||||
void kernaux_drivers_shutdown_halt();
|
KERNAUX_NORETURN void kernaux_drivers_shutdown_poweroff();
|
||||||
void kernaux_drivers_shutdown_poweroff();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,13 @@ extern "C" {
|
||||||
#define KERNAUX_MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
#define KERNAUX_MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||||
#define KERNAUX_MULTIBOOT2_INFO_MAGIC 0x36d76289
|
#define KERNAUX_MULTIBOOT2_INFO_MAGIC 0x36d76289
|
||||||
|
|
||||||
#define KERNAUX_MULTIBOOT2_HEADER_ALIGN 4
|
// @see https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#OS-image-format
|
||||||
|
#define KERNAUX_MULTIBOOT2_HEADER_ALIGN 8
|
||||||
|
// @see https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Basic-tags-structure
|
||||||
|
#define KERNAUX_MULTIBOOT2_INFO_ALIGN 8
|
||||||
|
// @see https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Header-tags
|
||||||
|
// @see https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Basic-tags-structure
|
||||||
|
#define KERNAUX_MULTIBOOT2_TAG_ALIGN 8
|
||||||
|
|
||||||
#define KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(arch, total_size) \
|
#define KERNAUX_MULTIBOOT2_HEADER_CHECKSUM(arch, total_size) \
|
||||||
((uint32_t)(-( \
|
((uint32_t)(-( \
|
||||||
|
@ -26,8 +32,6 @@ extern "C" {
|
||||||
|
|
||||||
#define KERNAUX_MULTIBOOT2_DATA(ptr) (((uint8_t*)(ptr)) + sizeof(*(ptr)))
|
#define KERNAUX_MULTIBOOT2_DATA(ptr) (((uint8_t*)(ptr)) + sizeof(*(ptr)))
|
||||||
|
|
||||||
#define KERNAUX_MULTIBOOT2_TAG_ALIGN 8
|
|
||||||
|
|
||||||
#define KERNAUX_MULTIBOOT2_HTAG_NEXT(tag_base) \
|
#define KERNAUX_MULTIBOOT2_HTAG_NEXT(tag_base) \
|
||||||
((struct KernAux_Multiboot2_HTagBase*)KERNAUX_MULTIBOOT2_TAG_NEXT(tag_base))
|
((struct KernAux_Multiboot2_HTagBase*)KERNAUX_MULTIBOOT2_TAG_NEXT(tag_base))
|
||||||
#define KERNAUX_MULTIBOOT2_ITAG_NEXT(tag_base) \
|
#define KERNAUX_MULTIBOOT2_ITAG_NEXT(tag_base) \
|
||||||
|
|
18
src/libc.h
18
src/libc.h
|
@ -1,18 +0,0 @@
|
||||||
// TODO: remove this file, require needed headers separately
|
|
||||||
|
|
||||||
#ifndef KERNAUX_INCLUDED_SRC_LIBC
|
|
||||||
#define KERNAUX_INCLUDED_SRC_LIBC
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -47,8 +47,10 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix)
|
||||||
char *pos = buffer;
|
char *pos = buffer;
|
||||||
if (value == 0) *(pos++) = '0';
|
if (value == 0) *(pos++) = '0';
|
||||||
while (value > 0) {
|
while (value > 0) {
|
||||||
|
// cppcheck-suppress zerodivcond
|
||||||
const char mod = value % base;
|
const char mod = value % base;
|
||||||
*(pos++) = mod < 10 ? mod + '0' : mod - 10 + alpha;
|
*(pos++) = mod < 10 ? mod + '0' : mod - 10 + alpha;
|
||||||
|
// cppcheck-suppress zerodivcond
|
||||||
value /= base;
|
value /= base;
|
||||||
}
|
}
|
||||||
char *const result = pos;
|
char *const result = pos;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <kernaux/macro.h>
|
#include <kernaux/macro.h>
|
||||||
#include <kernaux/pfa.h>
|
#include <kernaux/pfa.h>
|
||||||
|
|
||||||
#include "libc.h"
|
#include <string.h>
|
||||||
|
|
||||||
#define PAGE_INDEX(page_addr) ((page_addr) / KERNAUX_PFA_PAGE_SIZE)
|
#define PAGE_INDEX(page_addr) ((page_addr) / KERNAUX_PFA_PAGE_SIZE)
|
||||||
|
|
||||||
|
|
39
src/printf.c
39
src/printf.c
|
@ -17,10 +17,9 @@
|
||||||
#include <kernaux/printf.h>
|
#include <kernaux/printf.h>
|
||||||
#include <kernaux/printf_fmt.h>
|
#include <kernaux/printf_fmt.h>
|
||||||
|
|
||||||
#include "libc.h"
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// import float.h for DBL_MAX
|
// import float.h for DBL_MAX
|
||||||
#ifdef ENABLE_FLOAT
|
#ifdef ENABLE_FLOAT
|
||||||
|
@ -245,6 +244,7 @@ int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char*
|
||||||
case KERNAUX_PRINTF_FMT_TYPE_PTR:
|
case KERNAUX_PRINTF_FMT_TYPE_PTR:
|
||||||
{
|
{
|
||||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||||
|
// cppcheck-suppress knownConditionTrueFalse
|
||||||
if (is_ll) {
|
if (is_ll) {
|
||||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16u, spec.precision, spec.width, spec.flags);
|
idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16u, spec.precision, spec.width, spec.flags);
|
||||||
} else {
|
} else {
|
||||||
|
@ -425,10 +425,6 @@ size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen
|
||||||
// internal ftoa for fixed decimal floating point
|
// internal ftoa for fixed decimal floating point
|
||||||
size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
|
||||||
{
|
{
|
||||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
|
||||||
size_t len = 0u;
|
|
||||||
double diff = 0.0;
|
|
||||||
|
|
||||||
// powers of 10
|
// powers of 10
|
||||||
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
|
||||||
|
@ -457,16 +453,18 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
||||||
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) {
|
if (!(flags & KERNAUX_PRINTF_FMT_FLAGS_PRECISION)) {
|
||||||
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
prec = PRINTF_DEFAULT_FLOAT_PRECISION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||||
|
size_t len = 0u;
|
||||||
|
|
||||||
|
const unsigned int orig_prec = prec;
|
||||||
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
|
||||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9u)) {
|
if (prec > 9u) prec = 9u;
|
||||||
buf[len++] = '0';
|
|
||||||
prec--;
|
|
||||||
}
|
|
||||||
|
|
||||||
int whole = (int)value;
|
int whole = (int)value;
|
||||||
double tmp = (value - whole) * pow10[prec];
|
double tmp = (value - whole) * pow10[prec];
|
||||||
unsigned long frac = (unsigned long)tmp;
|
unsigned long frac = (unsigned long)tmp;
|
||||||
diff = tmp - frac;
|
double diff = tmp - frac;
|
||||||
|
|
||||||
if (diff > 0.5) {
|
if (diff > 0.5) {
|
||||||
++frac;
|
++frac;
|
||||||
|
@ -484,6 +482,7 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
||||||
|
|
||||||
if (prec == 0u) {
|
if (prec == 0u) {
|
||||||
diff = value - (double)whole;
|
diff = value - (double)whole;
|
||||||
|
// cppcheck-suppress redundantCondition
|
||||||
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
|
||||||
// exactly 0.5 and ODD, then round up
|
// exactly 0.5 and ODD, then round up
|
||||||
// 1.5 -> 2, but 2.5 -> 2
|
// 1.5 -> 2, but 2.5 -> 2
|
||||||
|
@ -537,6 +536,24 @@ size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This slows down the algorighm, but
|
||||||
|
// only if the precision was more than 9.
|
||||||
|
if (orig_prec > prec) {
|
||||||
|
const size_t space_left = PRINTF_FTOA_BUFFER_SIZE - len;
|
||||||
|
const size_t zeroes_wanted = orig_prec - prec;
|
||||||
|
const size_t delta =
|
||||||
|
space_left < zeroes_wanted ? space_left : zeroes_wanted;
|
||||||
|
|
||||||
|
for (size_t rev_index = 0; rev_index < len; ++rev_index) {
|
||||||
|
const size_t index = len - 1 - rev_index;
|
||||||
|
buf[index + delta] = buf[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
len += delta;
|
||||||
|
|
||||||
|
for (size_t index = 0; index < delta; ++index) buf[index] = '0';
|
||||||
|
}
|
||||||
|
|
||||||
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#include <kernaux/assert.h>
|
#include <kernaux/assert.h>
|
||||||
#include <kernaux/printf_fmt.h>
|
#include <kernaux/printf_fmt.h>
|
||||||
|
|
||||||
#include "libc.h"
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef struct KernAux_PrintfFmt_Spec *Spec;
|
typedef struct KernAux_PrintfFmt_Spec *Spec;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <kernaux/ntoa.h>
|
#include <kernaux/ntoa.h>
|
||||||
#include <kernaux/units.h>
|
#include <kernaux/units.h>
|
||||||
|
|
||||||
#include "libc.h"
|
#include <string.h>
|
||||||
|
|
||||||
#define TMP_BUFFER_SIZE (64)
|
#define TMP_BUFFER_SIZE (64)
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ static void test(const char *const expected, const char *const format, ...)
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
result = kernaux_vfprintf(test_putc, (void*)data, format, va);
|
result = kernaux_vfprintf(test_putc, (void*)data, format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
|
printf("Exp: %s\n", expected);
|
||||||
|
printf("Got: %s\n\n", buffer);
|
||||||
|
|
||||||
assert((size_t)result == strlen(expected));
|
assert((size_t)result == strlen(expected));
|
||||||
assert(strcmp(expected, buffer) == 0);
|
assert(strcmp(expected, buffer) == 0);
|
||||||
|
|
||||||
|
@ -48,6 +52,7 @@ static void test(const char *const expected, const char *const format, ...)
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
result = kernaux_vsnprintf(buffer, sizeof(buffer), format, va);
|
result = kernaux_vsnprintf(buffer, sizeof(buffer), format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
assert((size_t)result == strlen(expected));
|
assert((size_t)result == strlen(expected));
|
||||||
assert(strcmp(expected, buffer) == 0);
|
assert(strcmp(expected, buffer) == 0);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +68,6 @@ void test_main()
|
||||||
{% if case.float %}
|
{% if case.float %}
|
||||||
#ifdef ENABLE_FLOAT
|
#ifdef ENABLE_FLOAT
|
||||||
{% endif %}
|
{% endif %}
|
||||||
printf("%s\n", {{ escape_str(case.result) }});
|
|
||||||
test({{ escape_str(case.result) }}, {{ escape_str(fmt(case.args)) }}{{ values(case.args) }});
|
test({{ escape_str(case.result) }}, {{ escape_str(fmt(case.args)) }}{{ values(case.args) }});
|
||||||
{% if case.float %}
|
{% if case.float %}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,6 +37,7 @@ static void before_assert()
|
||||||
static void expect_assert()
|
static void expect_assert()
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DEBUG
|
#ifdef ENABLE_DEBUG
|
||||||
|
// cppcheck-suppress assignmentInAssert
|
||||||
assert(assert_count_ctr == ++assert_count_exp);
|
assert(assert_count_ctr == ++assert_count_exp);
|
||||||
assert(strstr(assert_last_file, "src/memmap.c") != NULL);
|
assert(strstr(assert_last_file, "src/memmap.c") != NULL);
|
||||||
assert_last_file = NULL;
|
assert_last_file = NULL;
|
||||||
|
|
|
@ -42,6 +42,7 @@ static void test_utoa_assert(char *const buffer, const int base)
|
||||||
if (setjmp(jmpbuf) == 0) {
|
if (setjmp(jmpbuf) == 0) {
|
||||||
kernaux_utoa(0, buffer, base, NULL);
|
kernaux_utoa(0, buffer, base, NULL);
|
||||||
} else {
|
} else {
|
||||||
|
// cppcheck-suppress assignmentInAssert
|
||||||
assert(assert_count_ctr == ++assert_count_exp);
|
assert(assert_count_ctr == ++assert_count_exp);
|
||||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||||
assert(assert_last_line != 0);
|
assert(assert_last_line != 0);
|
||||||
|
@ -58,6 +59,7 @@ static void test_itoa_assert(char *const buffer, const int base)
|
||||||
if (setjmp(jmpbuf) == 0) {
|
if (setjmp(jmpbuf) == 0) {
|
||||||
kernaux_itoa(0, buffer, base, NULL);
|
kernaux_itoa(0, buffer, base, NULL);
|
||||||
} else {
|
} else {
|
||||||
|
// cppcheck-suppress assignmentInAssert
|
||||||
assert(assert_count_ctr == ++assert_count_exp);
|
assert(assert_count_ctr == ++assert_count_exp);
|
||||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||||
assert(assert_last_line != 0);
|
assert(assert_last_line != 0);
|
||||||
|
@ -96,6 +98,7 @@ void test_main()
|
||||||
kernaux_utoa(123, buffer, 'd', TOO_LONG_PREFIX);
|
kernaux_utoa(123, buffer, 'd', TOO_LONG_PREFIX);
|
||||||
} else {
|
} else {
|
||||||
assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
|
assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
|
||||||
|
// cppcheck-suppress assignmentInAssert
|
||||||
assert(assert_count_ctr == ++assert_count_exp);
|
assert(assert_count_ctr == ++assert_count_exp);
|
||||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||||
assert(assert_last_line != 0);
|
assert(assert_last_line != 0);
|
||||||
|
@ -131,6 +134,7 @@ void test_main()
|
||||||
kernaux_itoa(123, buffer, 'd', TOO_LONG_PREFIX);
|
kernaux_itoa(123, buffer, 'd', TOO_LONG_PREFIX);
|
||||||
} else {
|
} else {
|
||||||
assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
|
assert(strcmp(buffer, VALID_LONG_PREFIX) == 0);
|
||||||
|
// cppcheck-suppress assignmentInAssert
|
||||||
assert(assert_count_ctr == ++assert_count_exp);
|
assert(assert_count_ctr == ++assert_count_exp);
|
||||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||||
assert(assert_last_line != 0);
|
assert(assert_last_line != 0);
|
||||||
|
|
Loading…
Reference in a new issue