mirror of
https://github.com/rvtr/TwlToolsRED.git
synced 2025-10-31 06:41:18 -04:00
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlToolsRED@275 7061adef-622a-194b-ae81-725974e89856
371 lines
14 KiB
C
371 lines
14 KiB
C
/*---------------------------------------------------------------------------*
|
|
Project: NITRO-System - demos - g2d - Text - textdemolib
|
|
File: wprintf.c
|
|
|
|
Copyright 2004-2008 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.
|
|
|
|
$Revision$
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include "g2d_textdemolib.h"
|
|
|
|
/* inner function for sized-buffer output */
|
|
typedef struct dst_string_tag {
|
|
size_t len;
|
|
wchar_t *cur;
|
|
wchar_t *base;
|
|
} dst_string;
|
|
|
|
static void string_put_char(dst_string *p, wchar_t c)
|
|
{
|
|
if(p->len > 0) *p->cur = c, --p->len;
|
|
++p->cur;
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
}
|
|
|
|
static 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 NNSi_G2dVSNWPrintf(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;
|
|
}
|