diff --git a/mio/lib/fmtoutv.h b/mio/lib/fmtoutv.h index 322d3bd..a6059df 100644 --- a/mio/lib/fmtoutv.h +++ b/mio/lib/fmtoutv.h @@ -89,6 +89,16 @@ } \ } while (0) +#define PUT_BYTE_IN_HEX(byte) do { \ + mio_bch_t __xbuf[3]; \ + mio_byte_to_bcstr (byte, __xbuf, MIO_COUNTOF(__xbuf), (16 | (ch == 'w'? MIO_BYTE_TO_BCSTR_LOWERCASE: 0)), '0'); \ + PUT_OOCH(__xbuf[0], 1); \ + PUT_OOCH(__xbuf[1], 1); \ +} while (0) + +/* TODO: redefine this */ +#define BYTE_PRINTABLE(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || (x == ' ')) + static int fmtoutv (mio_t* mio, const fmtchar_t* fmt, mio_fmtout_data_t* data, va_list ap) { const fmtchar_t* percent; @@ -598,6 +608,172 @@ static int fmtoutv (mio_t* mio, const fmtchar_t* fmt, mio_fmtout_data_t* data, v break; } + case 'k': + case 'K': + { + /* byte or multibyte character string in escape sequence */ + + const mio_uint8_t* bsp; + mio_oow_t k_hex_width; + + /* zeropad must not take effect for 'k' and 'K' + * + * 'h' & 'l' is not used to differentiate qse_mchar_t and qse_wchar_t + * because 'k' means qse_byte_t. + * 'l', results in uppercase hexadecimal letters. + * 'h' drops the leading \x in the output + * -------------------------------------------------------- + * hk -> \x + non-printable in lowercase hex + * k -> all in lowercase hex + * lk -> \x + all in lowercase hex + * -------------------------------------------------------- + * hK -> \x + non-printable in uppercase hex + * K -> all in uppercase hex + * lK -> \x + all in uppercase hex + * -------------------------------------------------------- + * with 'k' or 'K', i don't substitute "(null)" for the NULL pointer + */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + + bsp = va_arg(ap, mio_uint8_t*); + k_hex_width = (lm_flag & (LF_H | LF_L))? 4: 2; + + if (lm_flag& LF_H) + { + if (flagc & FLAGC_DOT) + { + /* if precision is specifed, it doesn't stop at the value of zero unlike 's' or 'S' */ + for (n = 0; n < precision; n++) width -= BYTE_PRINTABLE(bsp[n])? 1: k_hex_width; + } + else + { + for (n = 0; bsp[n]; n++) width -= BYTE_PRINTABLE(bsp[n])? 1: k_hex_width; + } + } + else + { + if (flagc & FLAGC_DOT) + { + /* if precision is specifed, it doesn't stop at the value of zero unlike 's' or 'S' */ + for (n = 0; n < precision; n++) /* nothing */; + } + else + { + for (n = 0; bsp[n]; n++) /* nothing */; + } + width -= (n * k_hex_width); + } + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + + while (n--) + { + if ((lm_flag & LF_H) && BYTE_PRINTABLE(*bsp)) + { + PUT_OOCH(*bsp, 1); + } + else + { + mio_bch_t xbuf[3]; + mio_byte_to_bcstr (*bsp, xbuf, MIO_COUNTOF(xbuf), (16 | (ch == 'k'? MIO_BYTE_TO_BCSTR_LOWERCASE: 0)), '0'); + if (lm_flag & (LF_H | LF_L)) + { + PUT_OOCH('\\', 1); + PUT_OOCH('x', 1); + } + PUT_OOCH(xbuf[0], 1); + PUT_OOCH(xbuf[1], 1); + } + bsp++; + } + + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + break; + } + + case 'w': + case 'W': + { + /* unicode string in unicode escape sequence. + * + * hw -> \uXXXX, \UXXXXXXXX, printable-byte(only in ascii range) + * w -> \uXXXX, \UXXXXXXXX + * lw -> all in \UXXXXXXXX + */ + const mio_uch_t* usp; + mio_oow_t uwid; + + if (flagc & FLAGC_ZEROPAD) padc = ' '; + usp = va_arg(ap, mio_uch_t*); + + if (flagc & FLAGC_DOT) + { + /* if precision is specifed, it doesn't stop at the value of zero unlike 's' or 'S' */ + for (n = 0; n < precision; n++) + { + if ((lm_flag & LF_H) && BYTE_PRINTABLE(usp[n])) uwid = 1; + else if (!(lm_flag & LF_L) && usp[n] <= 0xFFFF) uwid = 6; + else uwid = 10; + width -= uwid; + } + } + else + { + for (n = 0; usp[n]; n++) + { + if ((lm_flag & LF_H) && BYTE_PRINTABLE(usp[n])) uwid = 1; + else if (!(lm_flag & LF_L) && usp[n] <= 0xFFFF) uwid = 6; + else uwid = 10; + width -= uwid; + } + } + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + + while (n--) + { + if ((lm_flag & LF_H) && BYTE_PRINTABLE(*usp)) + { + PUT_OOCH(*usp, 1); + } + else if (!(lm_flag & LF_L) && *usp <= 0xFFFF) + { + mio_uint16_t u16 = *usp; + mio_uint8_t* bsp = (mio_uint8_t*)&u16; + PUT_OOCH('\\', 1); + PUT_OOCH('u', 1); + #if defined(MIO_ENDIAN_BIG) + PUT_BYTE_IN_HEX(bsp[0]); + PUT_BYTE_IN_HEX(bsp[1]); + #else + PUT_BYTE_IN_HEX(bsp[1]); + PUT_BYTE_IN_HEX(bsp[0]); + #endif + } + else + { + mio_uint32_t u32 = *usp; + mio_uint8_t* bsp = (mio_uint8_t*)&u32; + PUT_OOCH('\\', 1); + PUT_OOCH('U', 1); + #if defined(MIO_ENDIAN_BIG) + PUT_BYTE_IN_HEX(bsp[0]); + PUT_BYTE_IN_HEX(bsp[1]); + PUT_BYTE_IN_HEX(bsp[2]); + PUT_BYTE_IN_HEX(bsp[3]); + #else + PUT_BYTE_IN_HEX(bsp[3]); + PUT_BYTE_IN_HEX(bsp[2]); + PUT_BYTE_IN_HEX(bsp[1]); + PUT_BYTE_IN_HEX(bsp[0]); + #endif + } + usp++; + } + + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (padc, width); + break; + } #if 0 case 'e': case 'E': diff --git a/mio/lib/mio-utl.h b/mio/lib/mio-utl.h index 52ecba8..5d3333c 100644 --- a/mio/lib/mio-utl.h +++ b/mio/lib/mio-utl.h @@ -243,8 +243,18 @@ MIO_EXPORT mio_oow_t mio_count_bcstr ( # define mio_find_oochar_in_oocstr(ptr,c) mio_find_bchar_in_bcstr(ptr,c) # define mio_count_oocstr(str) mio_count_bcstr(str) #endif +/* ------------------------------------------------------------------------- */ - +#define MIO_BYTE_TO_BCSTR_RADIXMASK (0xFF) +#define MIO_BYTE_TO_BCSTR_LOWERCASE (1 << 8) + +mio_oow_t mio_byte_to_bcstr ( + mio_uint8_t byte, + mio_bch_t* buf, + mio_oow_t size, + int flagged_radix, + mio_bch_t fill +); /* ------------------------------------------------------------------------- */ diff --git a/mio/lib/utl.c b/mio/lib/utl.c index d9e63ea..8c4e6bb 100644 --- a/mio/lib/utl.c +++ b/mio/lib/utl.c @@ -656,6 +656,42 @@ mio_bch_t* mio_find_bchar_in_bcstr (const mio_bch_t* ptr, mio_bch_t c) /* ========================================================================= */ +mio_oow_t mio_byte_to_bcstr (mio_uint8_t byte, mio_bch_t* buf, mio_oow_t size, int flagged_radix, mio_bch_t fill) +{ + mio_bch_t tmp[(MIO_SIZEOF(mio_uint8_t) * 8)]; + mio_bch_t* p = tmp, * bp = buf, * be = buf + size - 1; + int radix; + mio_bch_t radix_char; + + radix = (flagged_radix & MIO_BYTE_TO_BCSTR_RADIXMASK); + radix_char = (flagged_radix & MIO_BYTE_TO_BCSTR_LOWERCASE)? 'a': 'A'; + if (radix < 2 || radix > 36 || size <= 0) return 0; + + do + { + mio_uint8_t digit = byte % radix; + if (digit < 10) *p++ = digit + '0'; + else *p++ = digit + radix_char - 10; + byte /= radix; + } + while (byte > 0); + + if (fill != '\0') + { + while (size - 1 > p - tmp) + { + *bp++ = fill; + size--; + } + } + + while (p > tmp && bp < be) *bp++ = *--p; + *bp = '\0'; + return bp - buf; +} + +/* ========================================================================= */ + MIO_INLINE int mio_conv_bchars_to_uchars_with_cmgr ( const mio_bch_t* bcs, mio_oow_t* bcslen, mio_uch_t* ucs, mio_oow_t* ucslen, mio_cmgr_t* cmgr, int all)