va_list fixed; printing 0 value fixed

This commit is contained in:
Wiesner András 2022-09-30 14:53:20 +02:00
parent 877b6fc017
commit a4ff669e7b

View File

@ -14,34 +14,21 @@
// format length ((nothing),l) // format length ((nothing),l)
typedef enum { typedef enum {
LEN_NORMAL, LEN_NORMAL, LEN_LONG
LEN_LONG
} FmtLength; } FmtLength;
// format flags ((nothing),0) // format flags ((nothing),0)
typedef enum { typedef enum {
FLAG_NO = 0, FLAG_NO = 0, FLAG_LEADING_ZEROS = 1, FLAG_LEADING_SPACES = 2, FLAG_PREPEND_PLUS_SIGN = 4
FLAG_LEADING_ZEROS = 1,
FLAG_LEADING_SPACES = 2,
FLAG_PREPEND_PLUS_SIGN = 4
} FmtFlags; } FmtFlags;
// format type // format type
typedef enum { typedef enum {
UNKNOWN = -1, UNKNOWN = -1, LITERAL_PERCENT, SIGNED_INTEGER, UNSIGNED_INTEGER, DOUBLE, DOUBLE_EXPONENTIAL, UNSIGNED_HEXADECIMAL_INT, UNSIGNED_HEXADECIMAL_INT_UPPERCASE, STRING, CHARACTER
LITERAL_PERCENT,
SIGNED_INTEGER,
UNSIGNED_INTEGER,
DOUBLE,
DOUBLE_EXPONENTIAL,
UNSIGNED_HEXADECIMAL_INT,
UNSIGNED_HEXADECIMAL_INT_UPPERCASE,
STRING,
CHARACTER
} FmtType; } FmtType;
struct _FmtWord; struct _FmtWord;
typedef int (*printfn)(va_list va, struct _FmtWord *fmt, char *outbuf, size_t free_space); typedef int (*printfn)(va_list *va, struct _FmtWord *fmt, char *outbuf, size_t free_space);
// pair of type and designator character // pair of type and designator character
typedef struct { typedef struct {
@ -140,10 +127,10 @@ static int scientific_form_exponent(uint64_t l, unsigned int base, uint64_t *gnt
if (*gntpd > 1) { if (*gntpd > 1) {
(*gntpd) /= base; (*gntpd) /= base;
} }
return e; return MAX(e, 0);
} }
static int pfn_literal_percent(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) { static int pfn_literal_percent(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
if (free_space >= 1) { if (free_space >= 1) {
outbuf[0] = '%'; outbuf[0] = '%';
outbuf[1] = '\0'; outbuf[1] = '\0';
@ -219,15 +206,15 @@ static int print_number(uint64_t u, bool negative, FmtWord *fmt, char *outbuf, s
return copy_len; return copy_len;
} }
static int pfn_integer(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) { static int pfn_integer(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
uint64_t u = 0; uint64_t u = 0;
bool negative = false; bool negative = false;
if (fmt->type == SIGNED_INTEGER) { // for signed integers if (fmt->type == SIGNED_INTEGER) { // for signed integers
int64_t si; int64_t si;
if (fmt->length == LEN_NORMAL) { // ...without length specifiers if (fmt->length == LEN_NORMAL) { // ...without length specifiers
si = va_arg(va, int); si = va_arg((*va), int);
} else { // ...with length specifiers } else { // ...with length specifiers
si = va_arg(va, int64_t); si = va_arg((*va), int64_t);
} }
// absolute value // absolute value
@ -239,10 +226,10 @@ static int pfn_integer(va_list va, FmtWord *fmt, char *outbuf, size_t free_space
} }
} else if (fmt->type == UNSIGNED_INTEGER || fmt->type == UNSIGNED_HEXADECIMAL_INT || fmt->type == UNSIGNED_HEXADECIMAL_INT_UPPERCASE) { // for UNsigned integers } else if (fmt->type == UNSIGNED_INTEGER || fmt->type == UNSIGNED_HEXADECIMAL_INT || fmt->type == UNSIGNED_HEXADECIMAL_INT_UPPERCASE) { // for UNsigned integers
if (fmt->length == LEN_NORMAL) { // ...without length specifiers if (fmt->length == LEN_NORMAL) { // ...without length specifiers
unsigned int d = va_arg(va, unsigned int); unsigned int d = va_arg((*va), unsigned int);
u = d; u = d;
} else { // ...with length specifiers } else { // ...with length specifiers
u = va_arg(va, uint64_t); u = va_arg((*va), uint64_t);
} }
} }
@ -253,9 +240,9 @@ static int pfn_integer(va_list va, FmtWord *fmt, char *outbuf, size_t free_space
#define DECIMAL_POINT ('.') #define DECIMAL_POINT ('.')
static int pfn_double(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) { static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
// get passed double variable // get passed double variable
double d = va_arg(va, double); double d = va_arg((*va), double);
bool negative = d < 0; bool negative = d < 0;
if (negative) { if (negative) {
d *= -1; d *= -1;
@ -272,13 +259,8 @@ static int pfn_double(va_list va, FmtWord *fmt, char *outbuf, size_t free_space)
} }
} }
// formatting of the integer part // formatting of the integer part
FmtWord int_fmt = { FmtWord int_fmt = { .flags = fmt->flags, .type = UNSIGNED_INTEGER, .width = fmt->width };
.flags = fmt->flags,
.type = UNSIGNED_INTEGER,
.width = fmt->width
};
// separate into integer and fractional part // separate into integer and fractional part
uint64_t int_part = (uint64_t) d; // integer part uint64_t int_part = (uint64_t) d; // integer part
@ -299,11 +281,7 @@ static int pfn_double(va_list va, FmtWord *fmt, char *outbuf, size_t free_space)
*outbuf = '\0'; *outbuf = '\0';
// prepare format for // prepare format for
FmtWord frac_fmt = { FmtWord frac_fmt = { .flags = FLAG_NO, .width = -1, .type = UNSIGNED_INTEGER };
.flags = FLAG_NO,
.width = -1,
.type = UNSIGNED_INTEGER
};
// extract fractional part as integer // extract fractional part as integer
double d_frac = d - (double) int_part; double d_frac = d - (double) int_part;
@ -328,11 +306,7 @@ static int pfn_double(va_list va, FmtWord *fmt, char *outbuf, size_t free_space)
sum_copy_len++; sum_copy_len++;
// print value of exponent // print value of exponent
FmtWord exponent_fmt = { FmtWord exponent_fmt = { .flags = FLAG_PREPEND_PLUS_SIGN | FLAG_LEADING_ZEROS, .width = 2, .type = UNSIGNED_INTEGER };
.flags = FLAG_PREPEND_PLUS_SIGN | FLAG_LEADING_ZEROS,
.width = 2,
.type = UNSIGNED_INTEGER
};
unsigned int exponent_abs = exponent > 0 ? exponent : -exponent; unsigned int exponent_abs = exponent > 0 ? exponent : -exponent;
@ -346,8 +320,8 @@ static int pfn_double(va_list va, FmtWord *fmt, char *outbuf, size_t free_space)
} }
// print character // print character
static int pfn_char(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) { static int pfn_char(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
int c = va_arg(va, int); int c = va_arg((*va), int);
if (free_space >= 1) { if (free_space >= 1) {
outbuf[0] = (char) c; outbuf[0] = (char) c;
outbuf[1] = '\0'; outbuf[1] = '\0';
@ -356,31 +330,22 @@ static int pfn_char(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) {
} }
// print string // print string
static int pfn_string(va_list va, FmtWord *fmt, char *outbuf, size_t free_space) { 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); return string_copy(outbuf, str, free_space);
} }
// format swting assignment table // format swting assignment table
static FmtTypeDesignatorPair sTypeDesAssignment[] = { static FmtTypeDesignatorPair sTypeDesAssignment[] = { { '%', LITERAL_PERCENT, pfn_literal_percent }, { 'd', SIGNED_INTEGER, pfn_integer }, { 'i', SIGNED_INTEGER, pfn_integer }, { 'u',
{'%', LITERAL_PERCENT, pfn_literal_percent}, UNSIGNED_INTEGER, pfn_integer }, { 'f', DOUBLE, pfn_double }, { 'e', DOUBLE_EXPONENTIAL, pfn_double }, { 'x', UNSIGNED_HEXADECIMAL_INT, pfn_integer }, { 'X',
{'d', SIGNED_INTEGER, pfn_integer}, UNSIGNED_HEXADECIMAL_INT_UPPERCASE, pfn_integer }, { 's', STRING, pfn_string }, { 'c', CHARACTER, pfn_char }, { '\0', UNKNOWN } // termination
{'i', SIGNED_INTEGER, pfn_integer},
{'u', UNSIGNED_INTEGER, pfn_integer},
{'f', DOUBLE, pfn_double},
{'e', DOUBLE_EXPONENTIAL, pfn_double},
{'x', UNSIGNED_HEXADECIMAL_INT, pfn_integer},
{'X', UNSIGNED_HEXADECIMAL_INT_UPPERCASE, pfn_integer},
{'s', STRING, pfn_string},
{'c', CHARACTER, pfn_char},
{'\0', UNKNOWN} // termination
}; };
// ------------------------------------------------------------ // ------------------------------------------------------------
// try to fetch number from the start of the string // try to fetch number from the start of the string
// return: number found OR -1 on failure // return: number found OR -1 on failure
static char *fetch_number(char *str, int *num) { static char* fetch_number(char *str, int *num) {
char *start = str; char *start = str;
char *end = start; char *end = start;
*num = 0; *num = 0;
@ -415,7 +380,7 @@ static int get_number_of_arguments_by_format_string(char *format_str) {
} }
// seek for format delimiter ('%') // seek for format delimiter ('%')
static char *seek_delimiter(char *str) { static char* seek_delimiter(char *str) {
// iterate over characters until either '%' is found or end of string is reached // iterate over characters until either '%' is found or end of string is reached
while (*(str) != '\0' && *(str) != FORMAT_DELIMITER) { while (*(str) != '\0' && *(str) != FORMAT_DELIMITER) {
str++; str++;
@ -434,7 +399,7 @@ static char *seek_delimiter(char *str) {
// begin: pointer to pointer to the begin of the format word // begin: pointer to pointer to the begin of the format word
// length: length of the format word (number of bytes to be copied after) // length: length of the format word (number of bytes to be copied after)
// return: pointer to unprocessed input string // return: pointer to unprocessed input string
static char *locate_format_word(char *str, char **begin, size_t *length) { static char* locate_format_word(char *str, char **begin, size_t *length) {
char *delim_pos = seek_delimiter(str); // seek for format specifier begin char *delim_pos = seek_delimiter(str); // seek for format specifier begin
if (delim_pos == NULL) { // if not found... if (delim_pos == NULL) { // if not found...
*length = 0; // set to zero if not found *length = 0; // set to zero if not found
@ -468,7 +433,7 @@ static char *locate_format_word(char *str, char **begin, size_t *length) {
// preceding_text: text before format word // preceding_text: text before format word
// maxlen: maximum STRING LENGTH of the output // maxlen: maximum STRING LENGTH of the output
// return: pointer to unprocessed text OR NULL on failure // return: pointer to unprocessed text OR NULL on failure
static char *fetch_format_word(char *str, char *word, char **word_begin, size_t maxlen) { static char* fetch_format_word(char *str, char *word, char **word_begin, size_t maxlen) {
// locate word // locate word
size_t len; size_t len;
char *unproc_text = locate_format_word(str, word_begin, &len); char *unproc_text = locate_format_word(str, word_begin, &len);
@ -480,7 +445,7 @@ static char *fetch_format_word(char *str, char *word, char **word_begin, size_t
} }
// fetch type from designator character // fetch type from designator character
static FmtTypeDesignatorPair *get_type_by_designator(char designator) { static FmtTypeDesignatorPair* get_type_by_designator(char designator) {
FmtTypeDesignatorPair *iter = sTypeDesAssignment; FmtTypeDesignatorPair *iter = sTypeDesAssignment;
while (iter->designator != '\0' && iter->designator != designator) { while (iter->designator != '\0' && iter->designator != designator) {
iter++; iter++;
@ -509,7 +474,7 @@ static bool is_flag(char c) {
// word: output format specifier // word: output format specifier
// rewind: number of characters to rewind input (some characters may be considered wrongly as being part of the format word) // rewind: number of characters to rewind input (some characters may be considered wrongly as being part of the format word)
// return: 0 on success, -1 on failure // return: 0 on success, -1 on failure
static int process_format_word(char *str, FmtWord *word, int * rewind) { static int process_format_word(char *str, FmtWord *word, int *rewind) {
// 1.: look for flags // 1.: look for flags
word->flags = FLAG_NO; word->flags = FLAG_NO;
while (is_flag(*str)) { while (is_flag(*str)) {
@ -580,7 +545,7 @@ unsigned long int vembfmt(char *str, unsigned long int len, char *format, va_lis
int rewind; int rewind;
process_format_word(word_str, &word, &rewind); process_format_word(word_str, &word, &rewind);
if (word.type != UNKNOWN) { if (word.type != UNKNOWN) {
int copy_len = word.pTypeDes->fn(args, &word, str, free_space); // variable with the same name! int copy_len = word.pTypeDes->fn(&args, &word, str, free_space); // variable with the same name!
free_space -= copy_len; free_space -= copy_len;
str += copy_len; str += copy_len;
sum_copy_len += copy_len; sum_copy_len += copy_len;