- %k added
- %f rounding fixed
This commit is contained in:
parent
7a12fe54cd
commit
6374ef283f
59
embformat.c
59
embformat.c
@ -6,6 +6,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/_types.h>
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
@ -14,17 +15,31 @@
|
||||
|
||||
// format length ((nothing),l)
|
||||
typedef enum {
|
||||
LEN_NORMAL, LEN_LONG
|
||||
LEN_NORMAL,
|
||||
LEN_LONG
|
||||
} FmtLength;
|
||||
|
||||
// format flags ((nothing),0)
|
||||
typedef enum {
|
||||
FLAG_NO = 0, FLAG_LEADING_ZEROS = 1, FLAG_LEADING_SPACES = 2, FLAG_PREPEND_PLUS_SIGN = 4
|
||||
FLAG_NO = 0,
|
||||
FLAG_LEADING_ZEROS = 1,
|
||||
FLAG_LEADING_SPACES = 2,
|
||||
FLAG_PREPEND_PLUS_SIGN = 4
|
||||
} FmtFlags;
|
||||
|
||||
// format type
|
||||
typedef enum {
|
||||
UNKNOWN = -1, LITERAL_PERCENT, SIGNED_INTEGER, UNSIGNED_INTEGER, DOUBLE, DOUBLE_EXPONENTIAL, UNSIGNED_HEXADECIMAL_INT, UNSIGNED_HEXADECIMAL_INT_UPPERCASE, STRING, CHARACTER
|
||||
UNKNOWN = -1,
|
||||
LITERAL_PERCENT,
|
||||
SIGNED_INTEGER,
|
||||
UNSIGNED_INTEGER,
|
||||
DOUBLE,
|
||||
DOUBLE_EXPONENTIAL,
|
||||
DOUBLE_TRUNCATE,
|
||||
UNSIGNED_HEXADECIMAL_INT,
|
||||
UNSIGNED_HEXADECIMAL_INT_UPPERCASE,
|
||||
STRING,
|
||||
CHARACTER
|
||||
} FmtType;
|
||||
|
||||
struct _FmtWord;
|
||||
@ -84,6 +99,21 @@ static uint64_t power(uint64_t a, unsigned long int n) {
|
||||
return a;
|
||||
}
|
||||
|
||||
static double powerf(double d, long int n) {
|
||||
if (n == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
d = (n < 0) ? (1 / d) : d;
|
||||
n = (n < 0) ? -n : n;
|
||||
|
||||
double d_orig = d;
|
||||
for (unsigned long int i = 0; i < n - 1; i++) {
|
||||
d *= d_orig;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
// round to closest base^1 value
|
||||
static uint64_t round_to_base(uint64_t a, uint64_t base) {
|
||||
uint64_t mod = a % base;
|
||||
@ -249,6 +279,12 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
||||
d *= -1;
|
||||
}
|
||||
|
||||
// round to requested precision if trucation is not instructed
|
||||
if (fmt->type != DOUBLE_TRUNCATE) {
|
||||
double r = 0.5 * powerf(10, -fmt->precision);
|
||||
d += r;
|
||||
}
|
||||
|
||||
// normalize if exponential form is required
|
||||
int exponent = 0;
|
||||
if (fmt->type == DOUBLE_EXPONENTIAL) {
|
||||
@ -264,7 +300,7 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
||||
FmtWord int_fmt = {.flags = fmt->flags, .type = UNSIGNED_INTEGER, .width = fmt->width};
|
||||
|
||||
// separate into integer and fractional part
|
||||
uint64_t int_part = (uint64_t) d; // integer part
|
||||
uint64_t int_part = (uint64_t)d; // integer part
|
||||
int copy_len = print_number(int_part, negative, &int_fmt, outbuf, free_space);
|
||||
free_space -= copy_len;
|
||||
outbuf += copy_len;
|
||||
@ -285,7 +321,7 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
||||
FmtWord frac_fmt = {.flags = FLAG_NO, .width = -1, .type = UNSIGNED_INTEGER};
|
||||
|
||||
// get "leading zeros" in fractional part
|
||||
double d_frac = d - (double) int_part;
|
||||
double d_frac = d - (double)int_part;
|
||||
|
||||
// print leading zeros
|
||||
int leading_zeros_printed = 0;
|
||||
@ -300,9 +336,8 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
||||
}
|
||||
|
||||
// extract fractional part as integer
|
||||
d_frac *= (double) power(10, fmt->precision - leading_zeros_printed + 1); // get one more digit
|
||||
uint64_t frac_part = (uint64_t) d_frac;
|
||||
frac_part = round_to_base(frac_part, 10) / 10; // remove last zero digit (result of rounding)
|
||||
d_frac *= (double)power(10, fmt->precision - leading_zeros_printed);
|
||||
uint64_t frac_part = (uint64_t)d_frac;
|
||||
|
||||
// print fractional part
|
||||
copy_len = print_number(frac_part, false, &frac_fmt, outbuf, free_space);
|
||||
@ -348,17 +383,19 @@ static int pfn_char(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space)
|
||||
|
||||
// print string
|
||||
static int pfn_string(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
|
||||
char *str = va_arg((*va), char*);
|
||||
char *str = va_arg((*va), char *);
|
||||
return string_copy(outbuf, str, free_space);
|
||||
}
|
||||
|
||||
// format swting assignment table
|
||||
static FmtTypeDesignatorPair sTypeDesAssignment[] = {{'%', LITERAL_PERCENT, pfn_literal_percent},
|
||||
static FmtTypeDesignatorPair sTypeDesAssignment[] = {
|
||||
{'%', LITERAL_PERCENT, pfn_literal_percent},
|
||||
{'d', SIGNED_INTEGER, pfn_integer},
|
||||
{'i', SIGNED_INTEGER, pfn_integer},
|
||||
{'u', UNSIGNED_INTEGER, pfn_integer},
|
||||
{'f', DOUBLE, pfn_double},
|
||||
{'e', DOUBLE_EXPONENTIAL, pfn_double},
|
||||
{'k', DOUBLE_TRUNCATE, pfn_double},
|
||||
{'x', UNSIGNED_HEXADECIMAL_INT, pfn_integer},
|
||||
{'X', UNSIGNED_HEXADECIMAL_INT_UPPERCASE, pfn_integer},
|
||||
{'p', UNSIGNED_HEXADECIMAL_INT, pfn_integer},
|
||||
@ -575,7 +612,7 @@ unsigned long int vembfmt(char *str, unsigned long int len, const char *format,
|
||||
sum_copy_len += copy_len;
|
||||
|
||||
// print data
|
||||
FmtWord word = { 0 };
|
||||
FmtWord word = {0};
|
||||
int rewind;
|
||||
process_format_word(word_str, &word, &rewind);
|
||||
if (word.type != UNKNOWN) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user