in erts/lib_src/common/erl_printf_format.c [457:850]
int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap)
{
char* ptr0 = fmt;
char* ptr = ptr0;
int count = 0;
int n;
int res = 0;
while(*ptr) {
ErlPfUWord ul_val;
int fmt = 0;
int width = -1;
int precision = -1;
if (res < 0)
return res;
if (*ptr == '%') {
if ((n=ptr-ptr0))
FMT(fn,arg,ptr0,n,count);
ptr++;
do_flag:
switch(*ptr) {
case '#': fmt |= FMTF_alt; ptr++; goto do_flag;
case '0': fmt |= FMTF_pad; ptr++; goto do_flag;
case '-': fmt |= FMTF_adj; ptr++; goto do_flag;
case ' ': fmt |= FMTF_blk; ptr++; goto do_flag;
case '+': fmt |= FMTF_sgn; ptr++; goto do_flag;
case '\'': fmt |= FMTF_cnv; ptr++; goto do_flag;
case 'I': fmt |= FMTF_cnV; ptr++; goto do_flag;
}
/* width */
if (*ptr == '*') {
width = va_arg(ap, int);
ptr++;
}
else if (isdigit((int) *ptr)) {
width = *ptr++ - '0';
while(isdigit((int) *ptr))
width = 10*width + (*ptr++ - '0');
}
/* precision */
if (*ptr == '.') {
ptr++;
if (*ptr == '*') {
precision = va_arg(ap, int);
ptr++;
}
else if (isdigit((int) *ptr)) {
precision = *ptr++ - '0';
while(isdigit((int) *ptr))
precision = 10*precision + (*ptr++ - '0');
}
}
/* length modifier */
switch(*ptr) {
case 'b': {
ptr++;
if (*ptr == 'p') {
ptr++;
#if SIZEOF_INT == SIZEOF_VOID_P
#elif SIZEOF_LONG == SIZEOF_VOID_P
fmt |= FMTL_l;
#elif SIZEOF_LONG_LONG == SIZEOF_VOID_P
fmt |= FMTL_ll;
#else
#error No integer datatype with the same size as 'void *' found
#endif
}
else if (*ptr == 'e') {
ptr++;
#if SIZEOF_INT == ERTS_SIZEOF_ETERM
#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM
fmt |= FMTL_l;
#elif SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM
fmt |= FMTL_ll;
#else
#error No integer datatype with the same size as Eterm found
#endif
}
else {
int bits = 0;
while(isdigit((int) *ptr))
bits = 10*bits + (*ptr++ - '0');
switch (bits) {
case 64:
#if SIZEOF_INT == 8
#elif SIZEOF_LONG == 8
fmt |= FMTL_l;
#elif SIZEOF_LONG_LONG == 8
fmt |= FMTL_ll;
#else
#error No 64-bit integer datatype found
#endif
break;
case 32:
#if SIZEOF_INT == 4
#elif SIZEOF_SHORT == 4
fmt |= FMTL_h;
#elif SIZEOF_LONG == 4
fmt |= FMTL_l;
#elif SIZEOF_LONG_LONG == 4
fmt |= FMTL_ll;
#else
#error No 32-bit integer datatype found
#endif
break;
case 16:
#if SIZEOF_INT == 2
#elif SIZEOF_SHORT == 2
fmt |= FMTL_h;
#elif SIZEOF_LONG == 2
fmt |= FMTL_l;
#else
#error No 16-bit integer datatype found
#endif
case 8:
#if SIZEOF_CHAR == 1
fmt |= FMTL_hh;
#else
#error Unexpected size of char
#endif
break;
default:
return -EINVAL;
}
}
break;
}
case 'h':
ptr++;
if (*ptr == 'h') {
ptr++;
fmt |= FMTL_hh;
}
else
fmt |= FMTL_h;
break;
case 'l':
ptr++;
if (*ptr == 'l') {
ptr++;
#if SIZEOF_LONG_LONG
fmt |= FMTL_ll;
#else
fmt |= FMTL_l;
#endif
}
else
fmt |= FMTL_l;
break;
case 'L': ptr++; fmt |= FMTL_L; break;
case 'j': ptr++; fmt |= FMTL_j; break;
case 't': ptr++; fmt |= FMTL_t; break;
}
/* specifier */
switch(*ptr) {
case 'd': ptr++; fmt |= FMTC_d; break;
case 'i': ptr++; fmt |= FMTC_d; break;
case 'o': ptr++; fmt |= FMTC_o; break;
case 'u': ptr++; fmt |= FMTC_u; break;
case 'x': ptr++; fmt |= FMTC_x; break;
case 'X': ptr++; fmt |= FMTC_X; break;
case 'e': ptr++; fmt |= FMTC_e; break;
case 'E': ptr++; fmt |= FMTC_E; break;
case 'f': ptr++; fmt |= FMTC_f; break;
case 'g': ptr++; fmt |= FMTC_g; break;
case 'G': ptr++; fmt |= FMTC_G; break;
case 'c': ptr++; fmt |= FMTC_c; break;
case 's': ptr++; fmt |= FMTC_s; break;
case 'p': ptr++; fmt |= FMTC_p; break;
case 'n': ptr++; fmt |= FMTC_n; break;
case 'T': ptr++; fmt |= FMTC_T; break;
case '%':
FMT(fn,arg,ptr,1,count);
ptr++;
ptr0 = ptr;
continue;
default:
/* ignore */
ptr0 = ptr;
continue;
}
switch(fmt & FMTC_MASK) {
case FMTC_d:
switch(fmt & FMTL_MASK) {
case FMTL_hh: {
signed char tval = (signed char) va_arg(ap,int);
ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
res = fmt_uword(fn,arg,SIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
case FMTL_h: {
signed short tval = (signed short) va_arg(ap,int);
ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
res = fmt_uword(fn,arg,SIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
case FMTL_l: {
signed long tval = (signed long) va_arg(ap,long);
ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
res = fmt_uword(fn,arg,SIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
#if SIZEOF_LONG_LONG
case FMTL_ll: {
unsigned_long_long ull_val;
signed_long_long tval;
tval = (signed_long_long) va_arg(ap,long_long);
ull_val = (unsigned_long_long) (tval < 0 ? (-tval) : tval);
res = fmt_long_long(fn,arg,SIGN(tval),ull_val,
width,precision,fmt,&count);
break;
}
#endif
default: {
signed int tval = (signed int) va_arg(ap,int);
ul_val = (ErlPfUWord) (tval < 0 ? (-tval) : tval);
res = fmt_uword(fn,arg,SIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
}
break;
case FMTC_o:
case FMTC_u:
case FMTC_x:
case FMTC_X:
switch(fmt & FMTL_MASK) {
case FMTL_hh: {
unsigned char tval = (unsigned char) va_arg(ap,int);
ul_val = (ErlPfUWord) tval;
res = fmt_uword(fn,arg,USIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
case FMTL_h: {
unsigned short tval = (unsigned short) va_arg(ap,int);
ul_val = (ErlPfUWord) tval;
res = fmt_uword(fn,arg,USIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
case FMTL_l: {
ul_val = (ErlPfUWord) va_arg(ap,long);
res = fmt_uword(fn,arg,USIGN(ul_val),ul_val,
width,precision,fmt,&count);
break;
}
#if SIZEOF_LONG_LONG
case FMTL_ll: {
unsigned_long_long ull_val;
ull_val = (signed_long_long) va_arg(ap,long_long);
res = fmt_long_long(fn,arg,USIGN(ull_val),ull_val,
width,precision,fmt,&count);
break;
}
#endif
default: {
unsigned int tval = (unsigned int) va_arg(ap,int);
ul_val = (ErlPfUWord) tval;
res = fmt_uword(fn,arg,USIGN(tval),ul_val,
width,precision,fmt,&count);
break;
}
}
break;
case FMTC_e:
case FMTC_E:
case FMTC_f:
case FMTC_g:
case FMTC_G:
if (precision < 0)
precision = 6;
switch(fmt & FMTL_MASK) {
case FMTL_L:
return -EINVAL;
break;
default:
res = fmt_double(fn,arg,va_arg(ap,double),
width,precision,fmt,&count);
break;
}
break;
case FMTC_c: {
/* fixme: add wide char support l-modifier */
char c = va_arg(ap,int);
int len = 1;
if (precision == 0)
len = 0;
if (width > 0 && !(fmt & FMTF_adj)) {
if (width > len)
BLANKS(fn, arg, width - len, count);
}
if (len)
FMT(fn,arg,&c,len,count);
if (width > len && fmt & FMTF_adj)
BLANKS(fn, arg, width - len, count);
break;
}
case FMTC_s: {
char* str = va_arg(ap,char*);
int len = (precision >= 0) ? my_strnlen(str,precision) : strlen(str);
if (width > 0 && !(fmt & FMTF_adj)) {
if (width > len)
BLANKS(fn, arg, width - len, count);
}
if (len)
FMT(fn,arg,str,len,count);
if (width > len && fmt & FMTF_adj)
BLANKS(fn, arg, width - len, count);
break;
}
case FMTC_p: {
void* addr = va_arg(ap, void*);
res = fmt_uword(fn,
arg,
USIGN((ErlPfUWord) addr),
(ErlPfUWord) addr,
width < 0 ? ((int) 2*sizeof(void *)) : width,
(precision < 0
? ((int) 2*sizeof(void *))
: precision),
FMTC_x|FMTF_pad|FMTF_alt,
&count);
break;
}
case FMTC_n:
switch(fmt & FMTL_MASK) {
case FMTL_hh: *va_arg(ap,char*) = count; break;
case FMTL_h: *va_arg(ap,short*) = count; break;
case FMTL_l: *va_arg(ap,long*) = count; break;
#if SIZEOF_LONG_LONG
case FMTL_ll: *va_arg(ap,long_long*) = count; break;
#endif
default: *va_arg(ap,int*) = count; break;
}
break;
case FMTC_T: { /* Eterm */
long prec;
ErlPfEterm eterm;
if (!erts_printf_eterm_func)
return -EINVAL;
if (precision < 0)
prec = 100000;
else if (precision == INT_MAX)
prec = LONG_MAX;
else
prec = (long) precision;
eterm = va_arg(ap, ErlPfEterm);
if (width > 0 && !(fmt & FMTF_adj)) {
res = (*erts_printf_eterm_func)(noop_fn, NULL, eterm, prec);
if (res < 0)
return res;
if (width > res)
BLANKS(fn, arg, width - res, count);
}
res = (*erts_printf_eterm_func)(fn, arg, eterm, prec);
if (res < 0)
return res;
count += res;
if (width > res && fmt & FMTF_adj)
BLANKS(fn, arg, width - res, count);
break;
}
default:
if ((n=ptr-ptr0))
FMT(fn,arg,ptr0,n,count);
}
ptr0 = ptr;
}
else
ptr++;
}
if ((n=ptr-ptr0))
FMT(fn,arg,ptr0,n,count);
return count;
}