42#define LARGEST_SIGNED long long int
44#define LARGEST_SIGNED long int
48#ifndef LARGEST_UNSIGNED
50#define LARGEST_UNSIGNED unsigned long long int
52#define LARGEST_UNSIGNED unsigned long int
57#define POINTER_INT uintptr_t
60typedef uint32_t FormatFlags;
62#define MAKE_MASK(shift, size) (((1 << size) - 1) << (shift))
64#define JUSTIFY_SHIFT 0
66#define JUSTIFY_RIGHT 0x0000
67#define JUSTIFY_LEFT 0x0001
68#define JUSTIFY_MASK MAKE_MASK(JUSTIFY_SHIFT, JUSTIFY_SIZE)
71#define POSITIVE_SHIFT (JUSTIFY_SHIFT + JUSTIFY_SIZE)
72#define POSITIVE_NONE (0x0000 << POSITIVE_SHIFT)
73#define POSITIVE_SPACE (0x0001 << POSITIVE_SHIFT)
74#define POSITIVE_PLUS (0x0003 << POSITIVE_SHIFT)
75#define POSITIVE_MASK MAKE_MASK(POSITIVE_SHIFT, POSITIVE_SIZE)
77#define POSITIVE_SIZE 2
79#define ALTERNATE_FORM_SHIFT (POSITIVE_SHIFT + POSITIVE_SIZE)
80#define ALTERNATE_FORM_SIZE 1
81#define ALTERNATE_FORM (0x0001 << ALTERNATE_FORM_SHIFT)
83#define PAD_SHIFT (ALTERNATE_FORM_SHIFT + ALTERNATE_FORM_SIZE)
85#define PAD_SPACE (0x0000 << PAD_SHIFT)
86#define PAD_ZERO (0x0001 << PAD_SHIFT)
88#define SIZE_SHIFT (PAD_SHIFT + PAD_SIZE)
90#define SIZE_CHAR (0x0001 << SIZE_SHIFT)
91#define SIZE_SHORT (0x0002 << SIZE_SHIFT)
92#define SIZE_INT (0x0000 << SIZE_SHIFT)
93#define SIZE_LONG (0x0003 << SIZE_SHIFT)
94#define SIZE_LONGLONG (0x0004 << SIZE_SHIFT)
95#define SIZE_MASK MAKE_MASK(SIZE_SHIFT, SIZE_SIZE)
97#define CONV_SHIFT (SIZE_SHIFT + SIZE_SIZE)
99#define CONV_INTEGER (0x0001 << CONV_SHIFT)
100#define CONV_FLOAT (0x0002 << CONV_SHIFT)
101#define CONV_POINTER (0x0003 << CONV_SHIFT)
102#define CONV_STRING (0x0004 << CONV_SHIFT)
103#define CONV_CHAR (0x0005 << CONV_SHIFT)
104#define CONV_PERCENT (0x0006 << CONV_SHIFT)
105#define CONV_WRITTEN (0x0007 << CONV_SHIFT)
106#define CONV_MASK MAKE_MASK(CONV_SHIFT, CONV_SIZE)
108#define RADIX_SHIFT (CONV_SHIFT + CONV_SIZE)
110#define RADIX_DECIMAL (0x0001 << RADIX_SHIFT)
111#define RADIX_OCTAL (0x0002 << RADIX_SHIFT)
112#define RADIX_HEX (0x0003 << RADIX_SHIFT)
113#define RADIX_MASK MAKE_MASK(RADIX_SHIFT, RADIX_SIZE)
115#define SIGNED_SHIFT (RADIX_SHIFT + RADIX_SIZE)
117#define SIGNED_NO (0x0000 << SIGNED_SHIFT)
118#define SIGNED_YES (0x0001 << SIGNED_SHIFT)
119#define SIGNED_MASK MAKE_MASK(SIGNED_SHIFT, SIGNED_SIZE)
121#define CAPS_SHIFT (SIGNED_SHIFT + SIGNED_SIZE)
123#define CAPS_NO (0x0000 << CAPS_SHIFT)
124#define CAPS_YES (0x0001 << CAPS_SHIFT)
125#define CAPS_MASK MAKE_MASK(CAPS_SHIFT, CAPS_SIZE)
127#define FLOAT_SHIFT (CAPS_SHIFT + CAPS_SIZE)
129#define FLOAT_NORMAL (((uint32_t)0x0000) << FLOAT_SHIFT)
130#define FLOAT_EXPONENT (((uint32_t)0x0001) << FLOAT_SHIFT)
131#define FLOAT_DEPENDANT (((uint32_t)0x0002) << FLOAT_SHIFT)
132#define FLOAT_HEX (((uint32_t)0x0003) << FLOAT_SHIFT)
133#define FLOAT_MASK MAKE_MASK(FLOAT_SHIFT, FLOAT_SIZE)
135#define CHECKCB(res) { if((res) != STRFORMAT_OK) { va_end(ap); return -1; } }
137#define MAXCHARS_HEX ((sizeof(LARGEST_UNSIGNED) * 8) / 4)
140#define MAXCHARS ((sizeof(LARGEST_UNSIGNED) * 8 + 2) / 3)
143parse_flags(
const char **posp)
145 FormatFlags flags = 0;
146 const char *pos = *posp;
151 flags |= JUSTIFY_LEFT;
154 flags |= POSITIVE_PLUS;
157 flags |= POSITIVE_SPACE;
160 flags |= ALTERNATE_FORM;
175parse_uint(
const char **posp)
178 const char *pos = *posp;
181 while((ch = *pos) >=
'0' && ch <=
'9') {
182 v = v * 10 + (ch -
'0');
192output_uint_decimal(
char **posp, LARGEST_UNSIGNED v)
198 *--pos = (v % 10) +
'0';
209output_uint_hex(
char **posp, LARGEST_UNSIGNED v,
unsigned int flags)
212 const char *hex = (flags & CAPS_YES) ?
"0123456789ABCDEF" :
"0123456789abcdef";
216 *--pos = hex[(v % 16)];
227output_uint_octal(
char **posp, LARGEST_UNSIGNED v)
233 *--pos = (v % 8) +
'0';
243static strformat_result
244fill_space(
const strformat_context_t *ctxt,
unsigned int len)
246 strformat_result res;
247 static const char buffer[16] =
" ";
250 res = ctxt->write_str(ctxt->user_data, buffer, 16);
251 if(res != STRFORMAT_OK) {
261 return ctxt->write_str(ctxt->user_data, buffer, len);
264static strformat_result
265fill_zero(
const strformat_context_t *ctxt,
unsigned int len)
267 strformat_result res;
268 static const char buffer[16] =
"0000000000000000";
271 res = ctxt->write_str(ctxt->user_data, buffer, 16);
272 if(res != STRFORMAT_OK) {
281 return ctxt->write_str(ctxt->user_data, buffer, len);
285format_str(
const strformat_context_t *ctxt,
const char *format, ...)
289 va_start(ap, format);
290 ret = format_str_v(ctxt, format, ap);
296format_str_v(
const strformat_context_t *ctxt,
const char *format, va_list ap)
298 unsigned int written = 0;
299 const char *pos = format;
301 while(*pos !=
'\0') {
303 unsigned int minwidth = 0;
306 const char *
start = pos;
308 while((ch = *pos) !=
'\0' && ch !=
'%') {
313 CHECKCB(ctxt->write_str(ctxt->user_data,
start, pos -
start));
314 written += pos -
start;
329 flags = parse_flags(&pos);
332 if(*pos >=
'1' && *pos <=
'9') {
333 minwidth = parse_uint(&pos);
334 }
else if(*pos ==
'*') {
335 int w = va_arg(ap,
int);
338 flags |= JUSTIFY_LEFT;
351 if(*pos >=
'0' && *pos <=
'9') {
352 precision = parse_uint(&pos);
353 }
else if(*pos ==
'*') {
355 precision = va_arg(ap,
int);
363 flags |= SIZE_LONGLONG;
368 }
else if(*pos ==
'h') {
377 }
else if(*pos ==
'z') {
378 if(
sizeof(
size_t) ==
sizeof(
short)) {
380 }
else if(
sizeof(
size_t) ==
sizeof(
long)) {
383 }
else if(
sizeof(
size_t) ==
sizeof(
long long)) {
384 flags |= SIZE_LONGLONG;
394 flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_YES;
397 flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_NO;
400 flags |= CONV_INTEGER | RADIX_OCTAL | SIGNED_NO;
403 flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO;
406 flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO | CAPS_YES;
410 flags |= CONV_FLOAT | FLOAT_NORMAL;
413 flags |= CONV_FLOAT | FLOAT_NORMAL | CAPS_YES;
416 flags |= CONV_FLOAT | FLOAT_EXPONENT;
419 flags |= CONV_FLOAT | FLOAT_EXPONENT | CAPS_YES;
422 flags |= CONV_FLOAT | FLOAT_DEPENDANT;
425 flags |= CONV_FLOAT | FLOAT_DEPENDANT | CAPS_YES;
428 flags |= CONV_FLOAT | FLOAT_HEX;
431 flags |= CONV_FLOAT | FLOAT_HEX | CAPS_YES;
438 flags |= CONV_STRING;
441 flags |= CONV_POINTER;
444 flags |= CONV_WRITTEN;
447 flags |= CONV_PERCENT;
455 switch(flags & CONV_MASK) {
457 CHECKCB(ctxt->write_str(ctxt->user_data,
"%", 1));
464 unsigned int prefix_len = 0;
465 char buffer[MAXCHARS];
466 char *conv_pos = buffer + MAXCHARS;
467 unsigned int conv_len = 0;
468 unsigned int width = 0;
469 unsigned int precision_fill;
470 unsigned int field_fill;
471 LARGEST_UNSIGNED uvalue = 0;
480 if(flags & SIGNED_YES) {
482 LARGEST_SIGNED value = 0;
483 switch(flags & SIZE_MASK) {
485 value = (
signed char)va_arg(ap,
int);
488 value = (short)va_arg(ap,
int);
491 value = va_arg(ap,
int);
497 value = va_arg(ap,
long);
501 value = va_arg(ap,
long long);
513 switch(flags & SIZE_MASK) {
515 uvalue = (
unsigned char)va_arg(ap,
unsigned int);
518 uvalue = (
unsigned short)va_arg(ap,
unsigned int);
521 uvalue = va_arg(ap,
unsigned int);
527 uvalue = va_arg(ap,
unsigned long);
531 uvalue = va_arg(ap,
unsigned long long);
537 switch(flags & (RADIX_MASK)) {
539 conv_len = output_uint_decimal(&conv_pos, uvalue);
542 conv_len = output_uint_octal(&conv_pos, uvalue);
545 conv_len = output_uint_hex(&conv_pos, uvalue, flags);
550 precision_fill = (precision > conv_len) ? precision - conv_len : 0;
551 if((flags & (RADIX_MASK | ALTERNATE_FORM))
552 == (RADIX_OCTAL | ALTERNATE_FORM)) {
553 if(precision_fill < 1) {
558 width += precision_fill;
560 if((flags & (RADIX_MASK | ALTERNATE_FORM))
561 == (RADIX_HEX | ALTERNATE_FORM) && uvalue != 0) {
563 if(flags & CAPS_YES) {
570 if(flags & SIGNED_YES) {
575 switch(flags & POSITIVE_MASK) {
590 field_fill = (minwidth > width) ? minwidth - width : 0;
592 if((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
593 if(flags & PAD_ZERO) {
594 precision_fill += field_fill;
597 CHECKCB(fill_space(ctxt, field_fill));
602 CHECKCB(ctxt->write_str(ctxt->user_data, prefix, prefix_len));
604 written += prefix_len;
606 CHECKCB(fill_zero(ctxt, precision_fill));
607 written += precision_fill;
609 CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos, conv_len));
612 if((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
613 CHECKCB(fill_space(ctxt, field_fill));
615 written += field_fill;
620 unsigned int field_fill;
622 char *str = va_arg(ap,
char *);
626 while(*pos !=
'\0') pos++;
633 if(precision >= 0 && precision < len) {
637 field_fill = (minwidth > len) ? minwidth - len : 0;
639 if((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
640 CHECKCB(fill_space(ctxt, field_fill));
643 CHECKCB(ctxt->write_str(ctxt->user_data, str, len));
646 if((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
647 CHECKCB(fill_space(ctxt, field_fill));
649 written += field_fill;
654 LARGEST_UNSIGNED uvalue =
655 (LARGEST_UNSIGNED)(POINTER_INT)va_arg(ap,
void *);
656 char buffer[MAXCHARS_HEX + 3];
657 char *conv_pos = buffer + MAXCHARS_HEX + 3;
658 unsigned int conv_len;
659 unsigned int field_fill;
661 conv_len = output_uint_hex(&conv_pos, uvalue, flags);
673 field_fill = (minwidth > conv_len) ? minwidth - conv_len : 0;
675 if((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
676 CHECKCB(fill_space(ctxt, field_fill));
679 CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos, conv_len));
682 if((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
683 CHECKCB(fill_space(ctxt, field_fill));
686 written += field_fill;
691 char ch = va_arg(ap,
int);
692 unsigned int field_fill = (minwidth > 1) ? minwidth - 1 : 0;
694 if((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
695 CHECKCB(fill_space(ctxt, field_fill));
696 written += field_fill;
699 CHECKCB(ctxt->write_str(ctxt->user_data, &ch, 1));
702 if((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
703 CHECKCB(fill_space(ctxt, field_fill));
705 written += field_fill;
710 int *p = va_arg(ap,
int *);
static void start(void)
Start measurement.