programmable field width (e.g. %*c)
This commit is contained in:
parent
9048955245
commit
c1512cde98
58
embformat.c
58
embformat.c
@ -28,6 +28,7 @@ typedef enum {
|
|||||||
} 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
|
||||||
@ -260,7 +261,7 @@ 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 = { .flags = fmt->flags, .type = UNSIGNED_INTEGER, .width = fmt->width };
|
FmtWord int_fmt = {.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
|
||||||
@ -281,7 +282,7 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
|||||||
*outbuf = '\0';
|
*outbuf = '\0';
|
||||||
|
|
||||||
// prepare format for printing fractional part
|
// prepare format for printing fractional part
|
||||||
FmtWord frac_fmt = { .flags = FLAG_NO, .width = -1, .type = UNSIGNED_INTEGER };
|
FmtWord frac_fmt = {.flags = FLAG_NO, .width = -1, .type = UNSIGNED_INTEGER};
|
||||||
|
|
||||||
// get "leading zeros" in fractional part
|
// get "leading zeros" in fractional part
|
||||||
double d_frac = d - (double) int_part;
|
double d_frac = d - (double) int_part;
|
||||||
@ -320,7 +321,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 = { .flags = FLAG_PREPEND_PLUS_SIGN | FLAG_LEADING_ZEROS, .width = 2, .type = UNSIGNED_INTEGER };
|
FmtWord exponent_fmt = {.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;
|
||||||
|
|
||||||
@ -336,11 +337,13 @@ 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) {
|
unsigned rep = (fmt->width == 0) ? 1 : fmt->width; // determine repetition count
|
||||||
outbuf[0] = (char) c;
|
rep = MIN(free_space, rep);
|
||||||
outbuf[1] = '\0';
|
for (unsigned i = 0; i < rep; i++) {
|
||||||
|
outbuf[i] = (char)c;
|
||||||
}
|
}
|
||||||
return 1;
|
outbuf[rep] = '\0';
|
||||||
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print string
|
// print string
|
||||||
@ -350,16 +353,25 @@ static int pfn_string(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
|
|||||||
}
|
}
|
||||||
|
|
||||||
// format swting assignment table
|
// format swting assignment table
|
||||||
static FmtTypeDesignatorPair sTypeDesAssignment[] = { { '%', LITERAL_PERCENT, pfn_literal_percent }, { 'd', SIGNED_INTEGER, pfn_integer }, { 'i', SIGNED_INTEGER, pfn_integer }, { 'u',
|
static FmtTypeDesignatorPair sTypeDesAssignment[] = {{'%', 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 }, { 'p', UNSIGNED_HEXADECIMAL_INT, 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},
|
||||||
|
{'p', UNSIGNED_HEXADECIMAL_INT, 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;
|
||||||
@ -394,7 +406,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++;
|
||||||
@ -413,7 +425,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
|
||||||
@ -447,7 +459,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);
|
||||||
@ -459,7 +471,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++;
|
||||||
@ -468,6 +480,7 @@ static FmtTypeDesignatorPair* get_type_by_designator(char designator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define DEFAULT_PRINT_PRECISION (6)
|
#define DEFAULT_PRINT_PRECISION (6)
|
||||||
|
#define LENGTH_IS_PARAMETER (-2) // -1 is used for something else
|
||||||
|
|
||||||
static char sFlags[] = " 0+";
|
static char sFlags[] = " 0+";
|
||||||
|
|
||||||
@ -507,7 +520,12 @@ static int process_format_word(char *str, FmtWord *word, int *rewind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2.: look for width
|
// 2.: look for width
|
||||||
|
if (*str == '*') { // parametered width
|
||||||
|
str++;
|
||||||
|
word->width = LENGTH_IS_PARAMETER; // read length from the varargs
|
||||||
|
} else {
|
||||||
str = fetch_number(str, &(word->width));
|
str = fetch_number(str, &(word->width));
|
||||||
|
}
|
||||||
|
|
||||||
// 3.: look for precision
|
// 3.: look for precision
|
||||||
word->precision = DEFAULT_PRINT_PRECISION; // default double precision
|
word->precision = DEFAULT_PRINT_PRECISION; // default double precision
|
||||||
@ -555,11 +573,19 @@ unsigned long int vembfmt(char *str, unsigned long int len, char *format, va_lis
|
|||||||
sum_copy_len += copy_len;
|
sum_copy_len += copy_len;
|
||||||
|
|
||||||
// print data
|
// print data
|
||||||
FmtWord word;
|
FmtWord word = { 0 };
|
||||||
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) {
|
||||||
|
if (word.width == LENGTH_IS_PARAMETER) { // if length is passed in parameter...
|
||||||
|
word.width = va_arg(args, unsigned); // read length parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMPILE_FOR_LINUX
|
||||||
|
int copy_len = word.pTypeDes->fn(args, &word, str, free_space); // variable with the same name!
|
||||||
|
#else
|
||||||
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!
|
||||||
|
#endif
|
||||||
free_space -= copy_len;
|
free_space -= copy_len;
|
||||||
str += copy_len;
|
str += copy_len;
|
||||||
sum_copy_len += copy_len;
|
sum_copy_len += copy_len;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user