/*---------------------------------------------------------------------------* Project: NitroSDK - libraries - OS File: os_printf.c Copyright 2003-2006 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. $Log: os_printf.c,v $ Revision 1.48 2006/01/18 02:11:30 kitase_hirotake do-indent Revision 1.47 2005/10/12 08:32:38 yada OS_PutString() is deadstripped in case of SDK_FINALROM Revision 1.46 2005/06/23 12:08:37 yasu SDK_LITTLE_ENDIAN を使用しないように修正 Revision 1.45 2005/06/07 09:49:34 yasu UnitTest 対策のため OSi_Panic の OS_Terminate 呼び出しを変更可能にする Revision 1.44 2005/03/04 11:09:27 yasu __declspec(weak) を SDK_WEAK_SYMBOL に置き換え Revision 1.43 2005/02/28 05:26:29 yosizaki do-indent. Revision 1.42 2005/02/28 04:26:25 yosizaki SDK_NO_MESSAGE に関する小さな修正. Revision 1.41 2005/02/18 06:22:52 yasu Signed/Unsigned 変換警告抑制 Revision 1.40 2005/02/04 11:02:15 yasu 著作年の修正 Revision 1.39 2005/01/31 03:16:15 seiki_masashi 除算の除去のため、常に速度優先で最適化を行うように指定 Revision 1.38 2005/01/28 12:58:25 seiki_masashi OS_VSNPrintf で除算をできるだけ使わないように変更 Revision 1.37 2004/11/24 11:07:37 yada Let a few functions be weak symbol. Revision 1.36 2004/11/24 08:50:22 yada Let a few functions be weak symbol. Revision 1.35 2004/11/12 10:45:30 yada just fix comment Revision 1.34 2004/10/08 07:49:13 yada consider for the situation of not calling OS_InitPrintServer() Revision 1.33 2004/10/04 10:06:30 yasu support SDK_NO_MESSAGE Revision 1.32 2004/09/11 06:00:34 yasu Add OS_TPrintf Revision 1.31 2004/06/08 01:22:47 yada add stub OS_Printf() for FINALROM Revision 1.30 2004/06/08 00:31:31 yada invalidate debug functions(OS_Printf, etc.) when FINALROM Revision 1.29 2004/05/06 02:54:39 yada stop by OS_Terminate() in OSi_Panic(), not by OS_Halt() Revision 1.28 2004/04/08 02:47:05 takano_makoto Change to use OS_VSNPrintf() in ARM7. Revision 1.27 2004/03/26 06:52:15 yosizaki add OS_SPrintf, OS_VSPrintf, OS_SNPrintf, and OS_VSNPrintf. Revision 1.26 2004/03/05 09:41:48 yasu add SDK_NO_VSNPRINTF to disable vsnprintf Revision 1.25 2004/03/04 12:41:05 yasu change function typedef name Revision 1.24 2004/02/28 12:07:55 yasu fix buffer handling Revision 1.23 2004/02/28 09:47:10 yasu fix comment Revision 1.22 2004/02/18 01:09:26 yasu force to turn byte access warning off Revision 1.21 2004/02/16 11:43:42 yasu fix OS_PrintServer Revision 1.20 2004/02/14 09:40:59 yasu workaround for unused warning message Revision 1.19 2004/02/14 09:26:08 yasu move printserver into os_printf Revision 1.18 2004/02/14 07:07:24 yasu support printserver component Revision 1.17 2004/02/13 08:58:52 yasu nitro_sp.h -> nitro.h Revision 1.16 2004/02/13 01:50:10 yada ARM9とAMR7 でインクルードファイル場合わけ Revision 1.15 2004/02/05 08:38:44 yada only modify comment Revision 1.14 2004/02/05 07:09:02 yasu change SDK prefix iris -> nitro Revision 1.13 2004/01/26 09:05:05 yasu Link stub of ISDPrintf if no IS_IRIS_DIR Revision 1.12 2003/12/29 04:27:24 yasu workaround for OS_Warning, OS_Panic Revision 1.11 2003/12/25 07:31:26 yada 型ルール統一による変更 Revision 1.10 2003/12/17 08:21:56 yasu ARM7 との共用コード化 Revision 1.9 2003/12/16 10:46:16 yasu ARM9/7 共用コード化 Revision 1.8 2003/12/12 05:03:48 yasu vsprintf の strb 対応版がリリースされるまでのワークアラウンド追加 Revision 1.7 2003/12/10 12:20:50 yasu IS ライブラリに関する小修正 Revision 1.6 2003/12/10 10:57:08 yasu ISDPrint の組み込み TEG ボードへの出力可能になる Revision 1.5 2003/12/02 07:28:59 yasu warning の回避 Revision 1.4 2003/12/02 06:51:51 yasu 空行変更 Revision 1.3 2003/12/02 03:44:50 yasu IS-IRIS-EMULATOR 用ライブラリ向けの修正2 Revision 1.2 2003/12/02 02:38:49 yasu ISDebugger での printout の組み込みの初段階 Revision 1.1 2003/11/29 01:25:46 yada ファイル名称変更 Revision 1.8 2003/11/25 11:17:37 yasu エミュレータの自動判別追加 Revision 1.7 2003/11/25 00:03:44 yasu OS_PutChar/OS_PutString/OS_VPrintf の公開 Revision 1.6 2003/11/21 12:20:31 yada reg_EMU_CONSOLE_OUT を reg_OS_EMU_CONSOLE_OUT にした。 Revision 1.5 2003/11/14 08:07:46 yasu string buffer をスタックから取るのを止めて static にする Revision 1.4 2003/11/14 07:46:00 yasu 微修正 Revision 1.3 2003/11/14 06:14:03 yasu OS_Warning() OS_Panic() の追加 Revision 1.2 2003/11/13 11:59:01 yasu 初版作成 Revision 1.1 2003/11/13 11:24:08 yasu 初版作成 エミュレータ側の実装が終わっていないため動作しないと思われる $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #ifdef SDK_LINK_ISD # pragma warn_extracomma off # include // has extracomma in enum # pragma warn_extracomma reset #else void ISDPrint(const char *); #endif #ifndef SDK_FINALROM static char common_buffer[256]; // thread unsafe, but less use of stack #endif #if !defined(SDK_FINALROM) && defined(SDK_NO_MESSAGE) #undef OSi_Warning #undef OSi_TWarning #undef OSi_Panic #undef OSi_TPanic void OSi_Warning(const char *file, int line, const char *fmt, ...); void OSi_TWarning(const char *file, int line, const char *fmt, ...); void OSi_Panic(const char *file, int line, const char *fmt, ...); void OSi_TPanic(const char *file, int line, const char *fmt, ...); #endif /* SDK_NO_MESSAGE */ /*---------------------------------------------------------------------------* Name: OS_PutChar Description: put a letter for debug console Arguments: c : char code , shuild be 0x01-0xff Returns: None. *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM SDK_WEAK_SYMBOL void OS_PutChar(char c) { char str[2]; str[0] = c; str[1] = '\0'; // Because of no putchar-type function on ISDebugger library, // use 'putstring' for a single letter outputting OS_PutString(str); } #endif /*---------------------------------------------------------------------------* Name: OS_PutString Description: put a string to debug console. console port are automatically switched depends on emu/hw Arguments: str : string Returns: None. *---------------------------------------------------------------------------*/ static void OS_PutStringInit(const char *str); #ifndef SDK_FINALROM static void OS_PutStringAris(const char *str); static void OS_PutStringISD(const char *str); static void OS_PutStringKMC(const char *str); void OS_PutStringARM(const char *str); #ifdef SDK_ARM7 static void OS_PutStringPrnSrv(const char *str); #endif #endif #ifndef SDK_FINALROM void (*OS_PutString) (const char *str) = OS_PutStringInit; #endif /*---------------------------------------------------------------------------* Name: OS_PutStringInit Description: OS_PutString initializer *---------------------------------------------------------------------------*/ static void OS_PutStringInit(const char *str) { #ifndef SDK_FINALROM OSIntrMode intr = OS_DisableInterrupts(); #ifdef SDK_ARM9 if (OS_IsRunOnEmulator()) { OS_PutString = OS_PutStringAris; } else #endif { #ifdef SDK_ARM7 OS_PutString = OS_PutStringPrnSrv; #else OS_PutString = OS_PutStringKMC; #endif OS_PutString = OS_PutStringKMC; #if defined( SDK_DEBUGGER_ISD ) _ISDbgLib_Initialize(); OS_PutString = OS_PutStringISD; #elif defined( SDK_DEBUGGER_ARM ) OS_PutString = OS_PutStringARM; #endif } OS_PutString(str); (void)OS_RestoreInterrupts(intr); #else (void)str; // avoiding to unused warning #endif } /*---------------------------------------------------------------------------* Name: OS_PutStringAris Description: OS_PutString for software simulator called ARIS *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM #ifdef SDK_CW_WARNOFF_SAFESTRB #include #endif static void OS_PutStringAris(const char *str) { char c; while ('\0' != (c = *str)) { reg_OS_EMU_CONSOLE_OUT = (u8)c; // Console out str++; } } #ifdef SDK_CW_WARNOFF_SAFESTRB #include #endif #endif /*---------------------------------------------------------------------------* Name: OS_PutStringISD Description: OS_PutString for hardware emulator called IS Debugger *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM static void OS_PutStringISD(const char *str) { // ISDPrint の初期化処理 OS_InitLock(); OS_PutString = ISDPrint; OS_PutString(str); } #endif /*---------------------------------------------------------------------------* Name: OS_PutStringKMC Description: OS_PutString for hardware emulator called KMC Debugger *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM static void OS_PutStringKMC(const char *str) { if ( OSi_IsRunOnDebuggerTWL() ) { vlink_dos_putstring_console((char *)str, STD_GetStringLength(str)); } } #endif /*---------------------------------------------------------------------------* Name: OS_PutStringARM Description: OS_PutString for hardware emulator called ARM Debugger *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM #include asm void OS_PutStringARM(const char *str) { // SWIハンドラで対処しているためデバッガ識別不要 mov r1, r0 mov r0, #0x04 swi 0x123456 bx lr } #include #endif /*---------------------------------------------------------------------------* Name: OS_VPrintf/OS_TVPrintf Description: print formatted strings (vprintf ver.) Arguments: fmt : format string vlist : parameters Returns: None. *---------------------------------------------------------------------------*/ // If you want to use "vsnprintf()" in ARM7, define SDK_USE_VSNPRINTF. // "vsnprintf()" is able to print float format but the code size become hugely bigger. // #define SDK_USE_VSNPRINTF #ifndef SDK_FINALROM #if defined(SDK_ARM9) || defined(SDK_USE_VSNPRINTF) SDK_WEAK_SYMBOL void OS_VPrintf(const char *fmt, va_list vlist) { (void)vsnprintf(common_buffer, sizeof(common_buffer), fmt, vlist); OS_PutString(common_buffer); } #else SDK_WEAK_SYMBOL void OS_VPrintf(const char *fmt, va_list vlist) { OS_TVPrintf(fmt, vlist); } #endif SDK_WEAK_SYMBOL void OS_TVPrintf(const char *fmt, va_list vlist) { (void)OS_VSNPrintf(common_buffer, sizeof(common_buffer), fmt, vlist); OS_PutString(common_buffer); } #endif /*---------------------------------------------------------------------------* Name: OS_Printf/OS_TPrintf Description: print formatted strings. Arguments: fmt : format string ... and parameters Returns: None. *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM SDK_WEAK_SYMBOL void OS_Printf(const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); OS_VPrintf(fmt, vlist); va_end(vlist); } SDK_WEAK_SYMBOL void OS_TPrintf(const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); OS_TVPrintf(fmt, vlist); va_end(vlist); } #endif /*---------------------------------------------------------------------------* Name: OSi_Warning / OSi_TWarning Description: print warning message. Arguments: file : filename of warning location line : line number of warning location fmt : format string ... and parameters Returns: None. *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM SDK_WEAK_SYMBOL void OSi_Warning(const char *file, int line, const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); OS_Printf("%s:%d Warning:", file, line); OS_VPrintf(fmt, vlist); OS_Printf("\n"); va_end(vlist); } SDK_WEAK_SYMBOL void OSi_TWarning(const char *file, int line, const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); OS_TPrintf("%s:%d Warning:", file, line); OS_TVPrintf(fmt, vlist); OS_TPrintf("\n"); va_end(vlist); } #endif /*---------------------------------------------------------------------------* Name: OSi_Panic/OSi_TPanic Description: print panic message and halt cpu. Arguments: file : filename of panic location line : line number of panic location fmt : format string ... and parameters Returns: None. *---------------------------------------------------------------------------*/ #ifndef SDK_FINALROM void (*OSi_FuncTerminate) (void) = OS_Terminate; SDK_WEAK_SYMBOL void OSi_Panic(const char *file, int line, const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); (void)OS_DisableInterrupts(); OS_Printf("%s:%d Panic:", file, line); OS_VPrintf(fmt, vlist); OS_Printf("\n"); OSi_FuncTerminate(); // Never Returns } SDK_WEAK_SYMBOL void OSi_TPanic(const char *file, int line, const char *fmt, ...) { va_list vlist; va_start(vlist, fmt); (void)OS_DisableInterrupts(); OS_TPrintf("%s:%d Panic:", file, line); OS_TVPrintf(fmt, vlist); OS_TPrintf("\n"); OSi_FuncTerminate(); // Never Returns } #endif /*---------------------------------------------------------------------------* Name: OS_InitPrintServer Description: initialize print server - this code should be called before OS_InitLock() - OS_InitLock() are also called from OS_Init() Arguments: None Returns: None *---------------------------------------------------------------------------*/ #ifdef SDK_ARM9 #ifndef SDK_FINALROM void OS_InitPrintServer(void) { OSPrintServerBuffer *p; // first, allocate buffer and register it. OS_InitArena(); p = OS_AllocFromSharedArenaHi(sizeof(OSPrintServerBuffer), 4); p->in = p->out = 0UL; PXI_SetComponentParam((u32)p); } #endif //SDK_FINALROM #endif //SDK_ARM9 /*---------------------------------------------------------------------------* Name: OS_PrintServer Description: print a string comes from ARM7 via shared memory Arguments: str string Returns: None. *---------------------------------------------------------------------------*/ #ifdef SDK_ARM9 #ifndef SDK_FINALROM #include // to access 'common_buffer' via cache void OS_PrintServer(void) { OSPrintServerBuffer *p; register OSPrintWChar word; u32 in, out; int i; p = (OSPrintServerBuffer *)PXI_GetComponentParam(); //---- If print buffer isn't set up, do nothing. if (!p) { return; } out = p->out; in = p->in; while (in != out) { i = 0; while (in != out && i < sizeof(common_buffer) - 3) { word.s = p->buffer[out].s; if (word.c[0]) { common_buffer[i++] = word.c[0]; // store via cache if (word.c[1]) { common_buffer[i++] = word.c[1]; // store via cache } } out++; if (out >= OS_PRINTSRV_WCHARSIZE) out = 0; } common_buffer[i] = '\0'; // store via cache OS_PutString(common_buffer); } // tell finished p->out = out; } #include #endif //SDK_FINALROM #endif //SDK_ARM9 /*---------------------------------------------------------------------------* Name: OS_PutStringPrnSrv Description: sends string to ARM9 via shared memory Arguments: str string to be sent Returns: None *---------------------------------------------------------------------------*/ #ifdef SDK_ARM7 static void OS_PutStringPrnSrv(const char *str) { #ifndef SDK_FINALROM OSPrintServerBuffer *p; register OSPrintWChar word; u32 in, in_tmp, out; u32 isOdd; p = (OSPrintServerBuffer *)PXI_GetComponentParam(); in = p->in; out = p->out; isOdd = ((u32)str) & 1; while (1) { in_tmp = in + 1; if (in_tmp >= OS_PRINTSRV_WCHARSIZE) in_tmp = 0; if (out == in_tmp) break; // Buffer full, then exit if (isOdd) { p->buffer[in].s = word.s = (u16)((*(u16 *)(str - 1)) & 0xff00); str++; isOdd = 0UL; if (!word.c[1]) break; in = in_tmp; } else { p->buffer[in].s = word.s = *(u16 *)str; str += 2; if (!word.c[0]) break; in = in_tmp; if (!word.c[1]) break; } } p->in = in; #else //SDK_FINALROM (void)str; #endif //SDK_FINALROM } #endif //SDK_ARM7 #if defined(SDK_CW_WARNOFF_SAFESTRB) #include #endif /* inner function for sized-buffer output */ typedef struct dst_string_tag { size_t len; char *cur; char *base; } dst_string; static void string_put_char(dst_string * p, char c) { if (p->len > 0) *p->cur = c, --p->len; ++p->cur; } static void string_fill_char(dst_string * p, char 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 char *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; } } /*---------------------------------------------------------------------------* Name: OS_SPrintf Description: equal to 'OS_VSPrintf' except argument style. Arguments: dst : destination buffer. fmt : format string. Returns: length of the generated string. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL int OS_SPrintf(char *dst, const char *fmt, ...) { int ret; va_list va; va_start(va, fmt); ret = OS_VSPrintf(dst, fmt, va); va_end(va); return ret; } /*---------------------------------------------------------------------------* Name: OS_VSPrintf Description: equal to 'OS_VSNPrintf' except buffer size argument. Arguments: dst : destination buffer. fmt : format string. vlist : parameters. Returns: length of the generated string. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL int OS_VSPrintf(char *dst, const char *fmt, va_list vlist) { return OS_VSNPrintf(dst, 0x7FFFFFFF, fmt, vlist); } /*---------------------------------------------------------------------------* Name: OS_SNPrintf Description: equal to 'OS_VSNPrintf' except argument style. Arguments: dst : destination buffer. len : destination buffer size. fmt : format string. 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. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL int OS_SNPrintf(char *dst, size_t len, const char *fmt, ...) { int ret; va_list va; va_start(va, fmt); ret = OS_VSNPrintf(dst, len, fmt, va); va_end(va); return ret; } /*---------------------------------------------------------------------------* 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 char 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. *---------------------------------------------------------------------------*/ SDK_WEAK_SYMBOL int OS_VSNPrintf(char *dst, size_t len, const char *fmt, va_list vlist) { char buf[24]; int n_buf; char prefix[2]; int n_prefix; const char *s = fmt; dst_string str; str.len = len, str.cur = str.base = dst; while (*s) { if ((unsigned int)(((unsigned char)*s ^ 0x20) - 0xA1) < 0x3C) { /* Shift JIS character */ string_put_char(&str, *s++); if (*s) string_put_char(&str, *s++); } else if (*s != '%') { /* normal ASCII character */ string_put_char(&str, *s++); } else { /* output with format */ enum { flag_blank = 000001, /* ' ' */ flag_plus = 000002, /* '+' */ flag_sharp = 000004, /* '#' */ flag_minus = 000010, /* '-' */ flag_zero = 000020, /* '0' */ flag_l1 = 000040, /* "l" */ flag_h1 = 000100, /* "h" */ flag_l2 = 000200, /* "ll" */ flag_h2 = 000400, /* "hh" */ flag_unsigned = 010000, /* 'o', 'u', ... */ flag_end }; int flag = 0, width = 0, precision = -1, radix = 10; char hex_char = 'a' - 10; const char *p_start = s; /* flags */ for (;;) { switch (*++s) { case '+': if (s[-1] != ' ') break; flag |= flag_plus; continue; case ' ': flag |= flag_blank; continue; case '-': flag |= flag_minus; continue; case '0': flag |= flag_zero; continue; } break; } /* width */ if (*s == '*') { ++s, width = va_arg(vlist, int); if (width < 0) width = -width, flag |= flag_minus; } else { while ((*s >= '0') && (*s <= '9')) width = (width * 10) + *s++ - '0'; } /* precision */ if (*s == '.') { ++s, precision = 0; if (*s == '*') { ++s, precision = va_arg(vlist, int); if (precision < 0) precision = -1; } else { while ((*s >= '0') && (*s <= '9')) precision = (precision * 10) + *s++ - '0'; } } /* option */ switch (*s) { case 'h': if (*++s != 'h') flag |= flag_h1; else ++s, flag |= flag_h2; break; case 'l': if (*++s != 'l') flag |= flag_l1; else ++s, flag |= flag_l2; break; } /* type */ switch (*s) { case 'd': /* signed decimal */ case 'i': /* signed decimal */ goto put_integer; case 'o': /* unsigned octal */ radix = 8; flag |= flag_unsigned; goto put_integer; case 'u': /* unsigned decimal */ flag |= flag_unsigned; goto put_integer; case 'X': /* unsigned hexadecimal */ hex_char = 'A' - 10; goto put_hexadecimal; case 'x': /* unsigned hexadecimal */ goto put_hexadecimal; case 'p': /* pointer */ /* equal to code warrior */ flag |= flag_sharp; precision = 8; goto put_hexadecimal; case 'c': /* character */ if (precision >= 0) goto put_invalid; { int c = va_arg(vlist, int); width -= 1; if (flag & flag_minus) { string_put_char(&str, (char)c); string_fill_char(&str, ' ', width); } else { char pad = (char)((flag & flag_zero) ? '0' : ' '); string_fill_char(&str, pad, width); string_put_char(&str, (char)c); } ++s; } break; case 's': /* string */ { int n_buf = 0; const char *p_buf = va_arg(vlist, const char *); 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, ' ', width); } else { char pad = (char)((flag & flag_zero) ? '0' : ' '); string_fill_char(&str, pad, width); string_put_string(&str, p_buf, n_buf); } ++s; } break; case '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 '%': /* output '%' */ 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, unsigned char); 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] = (char)(hex_char + (10 + 'x' - 'a')); prefix[1] = '0'; n_prefix = 2; } } else if (radix == 8) { prefix[0] = '0'; n_prefix = 1; } } } else { if (flag & flag_h2) val = va_arg(vlist, char); 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] = '-'; n_prefix = 1; } else { if (val || precision) { if (flag & flag_plus) { prefix[0] = '+'; n_prefix = 1; } else if (flag & flag_blank) { prefix[0] = ' '; n_prefix = 1; } } } } n_buf = 0; switch (radix) { case 8: while (val != 0) { int d = (int)(val & 0x07); val >>= 3; buf[n_buf++] = (char)(d + '0'); } break; case 10: if ((val >> 32) == 0) { #if defined(SDK_CW) || defined(__MWERKS__) #pragma optimize_for_size off #endif u32 v = (u32)val; while (v != 0) { // u32 と定数の除算であれば、コンパイラが自動的に // マジックナンバーを使用した積算に変換する u32 r = v / 10; int d = (int)(v - (r * 10)); v = r; buf[n_buf++] = (char)(d + '0'); } } else { while (val != 0) { u64 r = val / 10; int d = (int)(val - (r * 10)); val = r; buf[n_buf++] = (char)(d + '0'); } } break; case 16: while (val != 0) { int d = (int)(val & 0x0f); val >>= 4; buf[n_buf++] = (char)((d < 10) ? (d + '0') : (d + hex_char)); } break; } if ((n_prefix > 0) && (prefix[0] == '0')) { n_prefix = 0; buf[n_buf++] = '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, ' ', width); while (n_prefix > 0) string_put_char(&str, prefix[--n_prefix]); string_fill_char(&str, '0', n_pad); while (n_buf > 0) string_put_char(&str, buf[--n_buf]); if (flag & flag_minus) string_fill_char(&str, ' ', width); ++s; } break; } } } if (str.len > 0) *str.cur = '\0'; else if (len > 0) str.base[len - 1] = '\0'; return str.cur - str.base; } #if defined(SDK_CW_WARNOFF_SAFESTRB) #include #endif //================================================================================ // DUMMY PRINT (stub for FINALROM) //================================================================================ #ifdef SDK_FINALROM #ifdef OS_Printf #undef OS_Printf #endif void OS_Printf(const char *fmt, ...); void OS_Printf(const char *fmt, ...) { #pragma unused( fmt ) } #endif