TwlIPL/build/tests/WirelessChecker/src/util/wprintf.cpp
sato_masaki 662dadd251 本体デバッグ用無線チェックプログラムを追加。
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2071 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2008-08-01 06:11:58 +00:00

388 lines
14 KiB
C++

/*---------------------------------------------------------------------------*
Project: TwlSDK - Nmenu
File: WPrintf.cpp
Copyright 2007 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Date:: $
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include "util/wprintf.h"
namespace util
{
namespace
{
/* inner function for sized-buffer output */
typedef struct dst_string_tag
{
size_t len;
wchar_t *cur;
wchar_t *base;
} dst_string;
void
string_put_char(dst_string *p, wchar_t c)
{
if(p->len > 0) *p->cur = c, --p->len;
++p->cur;
}
void
string_fill_char(dst_string *p, wchar_t c, int n)
{
if(n > 0) {
size_t i, k = p->len;
if(k > (size_t)n) k = (size_t)n;
for( i = 0 ; i < k ; ++i )
p->cur[i] = c;
p->len -= k;
p->cur += n;
}
}
void
string_put_string(dst_string *p, const wchar_t *s, int n)
{
if(n > 0) {
size_t i, k = p->len;
if(k > (size_t)n) k = (size_t)n;
for( i = 0 ; i < k ; ++i )
p->cur[i] = s[i];
p->len -= k;
p->cur += n;
}
}
}
// based on OS_VSNPrintf
/*---------------------------------------------------------------------------*
Name: OS_VSNPrintf
Description: small-size vsnprintf which is similar to 'vsnprintf'
without following supports.
* CodeWarrior Extensions (#s)
* MSL AltiVec Extensions (v, vh, vl, hv, lv, @)
* indexed argments (%m$, *m$)
* floating-point
* wchar_t
Note: '+' and '#' do not work, MSL's sprintf().
to keep same result, they are no implement.
{ // exsample
wchar_t buf[5];
sprintf(buf, "%-i\n", 45); // "45" (OK)
sprintf(buf, "%0i\n", 45); // "45" (OK)
sprintf(buf, "% i\n", 45); // " 45" (OK)
sprintf(buf, "%+i\n", 45); // "%+i" ("+45" expected)
sprintf(buf, "%#x\n", 45); // "%#x" ("0x2d" expected)
// but, this works correctly!
sprintf(buf, "% +i\n", 45); // "+45" (OK)
}
Arguments: dst : destination buffer.
len : destination buffer size.
fmt : format string.
vlist : parameters.
Returns: length of the generated string. (except '\0')
if(result < len),
put NUL in dst[result].
else if(len > 0),
put NUL in dst[len - 1].
else,
do nothing.
*---------------------------------------------------------------------------*/
int
VSNWPrintf(wchar_t *dst, size_t len, const wchar_t *fmt, va_list vlist)
{
wchar_t buf[24];
int n_buf;
wchar_t prefix[2];
int n_prefix;
const wchar_t *s = fmt;
dst_string str;
str.len = len, str.cur = str.base = dst;
while(*s) {
if(*s != L'%') {
/* normal character */
string_put_char(&str, *s++);
} else {
/* output with format */
enum {
flag_blank = 000001, /* L' ' */
flag_plus = 000002, /* L'+' */
flag_sharp = 000004, /* L'#' */
flag_minus = 000010, /* L'-' */
flag_zero = 000020, /* L'0' */
flag_l1 = 000040, /* "l" */
flag_h1 = 000100, /* "h" */
flag_l2 = 000200, /* "ll" */
flag_h2 = 000400, /* "hh" */
flag_unsigned = 010000, /* L'o', L'u', ... */
flag_end } ;
int flag = 0, width = 0, precision = -1, radix = 10;
wchar_t hex_char = L'a' - 10;
const wchar_t *p_start = s;
/* flags */
for( ; ; ) {
switch(*++s) {
case L'+':if(s[-1] != L' ') break;
flag |= flag_plus; continue;
case L' ':flag |= flag_blank;continue;
case L'-':flag |= flag_minus;continue;
case L'0':flag |= flag_zero; continue;
}
break;
}
/* width */
if(*s == L'*') {
++s, width = va_arg(vlist, int);
if(width < 0)
width = -width, flag |= flag_minus;
} else {
while((*s >= L'0') && (*s <= L'9'))
width = (width * 10) + *s++ - L'0';
}
/* precision */
if(*s == L'.') {
++s, precision = 0;
if(*s == L'*') {
++s, precision = va_arg(vlist, int);
if(precision < 0) precision = -1;
} else {
while((*s >= L'0') && (*s <= L'9'))
precision = (precision * 10) + *s++ - L'0';
}
}
/* option */
switch(*s) {
case L'h':
if(*++s != L'h') flag |= flag_h1;
else ++s, flag |= flag_h2;
break;
case L'l':
if(*++s != L'l') flag |= flag_l1;
else ++s, flag |= flag_l2;
break;
}
/* type */
switch(*s) {
case L'd': /* signed decimal */
case L'i': /* signed decimal */
goto put_integer;
case L'o': /* unsigned octal */
radix = 8;
flag |= flag_unsigned;
goto put_integer;
case L'u': /* unsigned decimal */
flag |= flag_unsigned;
goto put_integer;
case L'X': /* unsigned hexadecimal */
hex_char = L'A' - 10;
goto put_hexadecimal;
case L'x': /* unsigned hexadecimal */
goto put_hexadecimal;
case L'p': /* pointer */
/* equal to code warrior */
flag |= flag_sharp;
precision = 8;
goto put_hexadecimal;
case L'c': /* character */
if(precision >= 0)
goto put_invalid;
{
int c = va_arg(vlist, int);
width -= 1;
if(flag & flag_minus) {
string_put_char(&str, (wchar_t)c);
string_fill_char(&str, L' ', width);
} else {
wchar_t pad = (wchar_t)(
(flag & flag_zero) ? L'0' : L' ');
string_fill_char(&str, pad, width);
string_put_char(&str, (wchar_t)c);
}
++s;
}
break;
case L's': /* string */
{
int n_buf = 0;
const wchar_t *p_buf = va_arg(vlist, const wchar_t*);
if(precision < 0) {
while(p_buf[n_buf])
++n_buf;
} else {
while((n_buf < precision) && p_buf[n_buf])
++n_buf;
}
width -= n_buf;
if(flag & flag_minus) {
string_put_string(&str, p_buf, n_buf);
string_fill_char(&str, L' ', width);
} else {
wchar_t pad = (wchar_t)(
(flag & flag_zero) ? L'0' : L' ');
string_fill_char(&str, pad, width);
string_put_string(&str, p_buf, n_buf);
}
++s;
}
break;
case L'n': /* store the number of output */
{
int pos = str.cur - str.base;
if(flag & flag_h2)
;
else if(flag & flag_h1)
*va_arg(vlist, signed short*) = (signed short)pos;
else if(flag & flag_l2)
*va_arg(vlist, u64*) = (u64)pos;
else
*va_arg(vlist, signed int*) = (signed int)pos;
}
++s;
break;
case L'%': /* output L'%' */
if(p_start + 1 != s)
goto put_invalid;
string_put_char(&str, *s++);
break;
default: /* invalid type */
goto put_invalid;
put_invalid:
string_put_string(&str, p_start, s - p_start);
break;
put_hexadecimal:
radix = 16;
flag |= flag_unsigned;
put_integer:
{
u64 val = 0;
n_prefix = 0;
if(flag & flag_minus)
flag &= ~flag_zero;
if(precision < 0) precision = 1;
else flag &= ~flag_zero;
if(flag & flag_unsigned) {
if(flag & flag_h2)
val = va_arg(vlist, wchar_t);
else if(flag & flag_h1)
val = va_arg(vlist, unsigned short);
else if(flag & flag_l2)
val = va_arg(vlist, u64);
else
val = va_arg(vlist, unsigned long);
flag &= ~(flag_plus | flag_blank);
if(flag & flag_sharp) {
if(radix == 16) {
if(val != 0) {
prefix[0] = (wchar_t)(hex_char + (10 + L'x' - L'a'));
prefix[1] = L'0';
n_prefix = 2;
}
} else if(radix == 8) {
prefix[0] = L'0';
n_prefix = 1;
}
}
} else {
if(flag & flag_h2)
val = va_arg(vlist, wchar_t);
else if(flag & flag_h1)
val = va_arg(vlist, short);
else if(flag & flag_l2)
val = va_arg(vlist, u64);
else
val = va_arg(vlist, long);
if((val >> 32) & 0x80000000) {
val = ~val + 1;
prefix[0] = L'-';
n_prefix = 1;
} else {
if(val || precision) {
if(flag & flag_plus) {
prefix[0] = L'+';
n_prefix = 1;
} else
if(flag & flag_blank) {
prefix[0] = L' ';
n_prefix = 1;
}
}
}
}
n_buf = 0;
while(val != 0) {
int d = (int)(val % radix);
val /= radix;
buf[n_buf++] = (wchar_t)((d < 10) ?
(d + L'0') : (d + hex_char));
}
if((n_prefix > 0) && (prefix[0] == L'0')) {
n_prefix = 0;
buf[n_buf++] = L'0';
}
}
goto put_to_stream;
put_to_stream:
{
int n_pad = precision - n_buf;
if(flag & flag_zero) {
if(n_pad < width - n_buf - n_prefix)
n_pad = width - n_buf - n_prefix;
}
if(n_pad > 0) width -= n_pad;
width -= n_prefix + n_buf;
if(!(flag & flag_minus))
string_fill_char(&str, L' ', width);
while(n_prefix > 0)
string_put_char(&str, prefix[--n_prefix]);
string_fill_char(&str, L'0', n_pad);
while(n_buf > 0)
string_put_char(&str, buf[--n_buf]);
if(flag & flag_minus)
string_fill_char(&str, L' ', width);
++s;
}
break;
}
}
}
if(str.len > 0)
*str.cur = '\0';
else if(len > 0)
str.base[len - 1] = '\0';
return str.cur - str.base;
}
}
// end of namespace tlib