1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - libraries - STD
3 File: std_string.c
4
5 Copyright 2005-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2009-01-26#$
14 $Rev: 9918 $
15 $Author: matsuoka_masayoshi $
16 *---------------------------------------------------------------------------*/
17 #include <nitro.h>
18
19 // Speed optimization macros for string operation functions
20 // (Although these are platform-independent, components will overflow if they are enabled on ARM7, so they are enabled only on ARM9.)
21 //
22 #if defined(SDK_ARM9)
23 // Because at least the high-speed version of GetStringLength does not consider big endians, just in case, implementation of all functions will be limited to little endians until their operation can be confirmed.
24 //
25 #if (PLATFORM_BYTES_ENDIAN == PLATFORM_ENDIAN_LITTLE)
26 #define STRLEN_4BYTE_SKIP // 4-byte evaluation is for non-zero checks only
27 #define STRLCPY_4BYTE // A copy evaluation every 4 bytes
28 #define STRNLEN_4BYTE_SKIP // Measurement every 4 bytes
29 #define STRCMP_4BYTE // Comparison every 4 bytes
30 #define STRNCMP_4BYTE // Comparison every 4 bytes <- Disabled because of a bug
31 //#define STRNICMP_DIFF // Improve the comparison
32 #endif
33 #endif
34
35 /*---------------------------------------------------------------------------*
36 Name: STD_CopyString
37
38 Description: same to strcpy
39
40 Arguments: destp : destination pointer
41 srcp : src pointer
42
43 Returns: pointer to destination
44 *---------------------------------------------------------------------------*/
STD_CopyString(char * destp,const char * srcp)45 char *STD_CopyString(char *destp, const char *srcp)
46 {
47 char *retval = destp;
48
49 SDK_ASSERT(destp && srcp);
50
51 while (*srcp)
52 {
53 *destp++ = (char)*srcp++;
54 }
55 *destp = '\0';
56
57 return retval;
58 }
59
60 /*---------------------------------------------------------------------------*
61 Name: STD_CopyLStringZeroFill
62
63 Description: do not correspond with strlcpy
64
65 Arguments: destp : destination pointer
66 srcp : src pointer
67 n: copy size + 1
68
69 Returns: size of src
70 *---------------------------------------------------------------------------*/
STD_CopyLStringZeroFill(char * destp,const char * srcp,int n)71 int STD_CopyLStringZeroFill(char *destp, const char *srcp, int n)
72 {
73 int i;
74 const char *s = srcp;
75
76 SDK_ASSERT(destp && srcp && n >= 0);
77
78 for (i = 0; i < n - 1; i++)
79 {
80 destp[i] = (char)*s;
81 if (*s)
82 {
83 s++;
84 }
85 }
86 if( i < n )
87 {
88 destp[i] = '\0';
89 }
90
91 return STD_GetStringLength(srcp);
92 }
93
94 /*---------------------------------------------------------------------------*
95 Name: STD_CopyLString
96
97 Description: same to strlcpy
98
99 Arguments: destp : destination pointer
100 srcp : src pointer
101 siz : copy size + 1
102
103 Returns: size of src
104 *---------------------------------------------------------------------------*/
STD_CopyLString(char * destp,const char * srcp,int siz)105 int STD_CopyLString(char *destp, const char *srcp, int siz)
106 {
107 #if defined(STRLCPY_4BYTE)
108 unsigned long dstalign, srcalign;
109 int i;
110 unsigned long val32, y;
111 const char *s = srcp;
112
113 SDK_ASSERT(destp && srcp && siz >= 0);
114
115 // 4-byte alignment check
116 dstalign = (unsigned long)destp & 0x3;
117 srcalign = (unsigned long)srcp & 0x3;
118
119 i = 0;
120 // If it does not match, copy normally
121 if( dstalign ^ srcalign )
122 {
123 goto strlcpy_normal;
124 }
125
126 // Check copy of the leading 4 bytes
127 if( dstalign )
128 {
129 for( ; (i + dstalign < 4) && (i < siz - 1); i++ )
130 {
131 *(destp + i) = (char)*s;
132 if (*s)
133 {
134 s++;
135 }
136 else
137 {
138 goto terminate;
139 }
140 }
141 }
142
143 // Copy 4 bytes
144 for( ; i < siz - 1 - 4 + 1; i += 4 )
145 {
146 val32 = *(unsigned long*)(srcp + i);
147 y = (val32 & 0x7F7F7F7F) + 0x7F7F7F7F;
148 y = ~(y | val32 | 0x7F7F7F7F);
149
150 if( y != 0 )
151 break;
152
153 *(unsigned long*)(destp + i) = val32;
154 }
155
156 // Copy remaining bytes
157 s = srcp + i;
158
159 strlcpy_normal:
160 // Copy byte
161 for ( ; i < siz - 1; i++ )
162 {
163 destp[i] = (char)*s;
164 if (*s)
165 {
166 s++;
167 }
168 else
169 {
170 break;
171 }
172 }
173
174 terminate:
175 // Add terminating NULL
176 if ((i >= siz - 1) && (siz > 0))
177 {
178 destp[i] = '\0';
179 }
180
181 if( !*s )
182 return (int)i;
183 else
184 return (int)i + STD_GetStringLength( s );
185 #else // original
186 int i;
187 const char *s = srcp;
188
189 SDK_ASSERT(destp && srcp && siz >= 0);
190
191 for (i = 0; i < siz - 1; i++)
192 {
193 destp[i] = (char)*s;
194 if (*s)
195 {
196 s++;
197 }
198 else
199 {
200 break;
201 }
202 }
203
204 if ((i >= siz - 1) && (siz > 0))
205 {
206 destp[i] = '\0';
207 }
208
209 return STD_GetStringLength(srcp);
210 #endif
211 }
212
213 /*---------------------------------------------------------------------------*
214 Name: STD_SearchChar
215
216 Description: Same as strchr.
217
218 Arguments: srcp : src string
219 c: character to search from src pointer
220
221 Returns: pointer to destination
222 *---------------------------------------------------------------------------*/
STD_SearchChar(const char * srcp,int c)223 char *STD_SearchChar(const char *srcp, int c)
224 {
225 SDK_POINTER_ASSERT(srcp);
226
227 for (;;srcp++)
228 {
229 if (c == *srcp)
230 {
231 return (char*)srcp;
232 }
233 if ('\0' == *srcp)
234 {
235 return NULL;
236 }
237 }
238 // not reach here.
239 }
240
241 /*---------------------------------------------------------------------------*
242 Name: STD_SearchCharReverse
243
244 Description: Same as strrchr.
245
246 Arguments: srcp : src string
247 c: character to search from src pointer
248
249 Returns: pointer to destination
250 *---------------------------------------------------------------------------*/
STD_SearchCharReverse(const char * srcp,int c)251 char *STD_SearchCharReverse(const char *srcp, int c)
252 {
253 const char* found = NULL;
254
255 SDK_POINTER_ASSERT(srcp);
256
257 for (;;srcp++)
258 {
259 if( c == *srcp )
260 {
261 found = srcp;
262 }
263
264 if( '\0' == *srcp)
265 {
266 return (char*)found;
267 }
268 }
269 // not reach here.
270 }
271
272 /*---------------------------------------------------------------------------*
273 Name: STD_SearchString
274
275 Description: same to strstr
276
277 Arguments: srcp : src string
278 str : string to search from src pointer
279
280 Returns: pointer to destination
281 *---------------------------------------------------------------------------*/
STD_SearchString(const char * srcp,const char * str)282 char *STD_SearchString(const char *srcp, const char *str)
283 {
284 int i;
285 int n;
286
287 SDK_ASSERT(srcp && str);
288
289 for (i = 0; srcp[i]; i++)
290 {
291 n = 0;
292 while (str[n] && srcp[i + n] == str[n])
293 {
294 n++;
295 }
296
297 if (str[n] == '\0')
298 {
299 return (char *)&srcp[i];
300 }
301 }
302
303 return NULL;
304 }
305
306 /*---------------------------------------------------------------------------*
307 Name: STD_GetStringLength
308
309 Description: get string length. same to strlen
310
311 Arguments: str : string
312
313 Returns: string length
314 *---------------------------------------------------------------------------*/
STD_GetStringLength(const char * str)315 int STD_GetStringLength(const char *str)
316 {
317 #if defined(STRLEN_4BYTE_SKIP)
318 int n;
319 unsigned long *p32, y;
320
321 for( n=0; ((unsigned long)(str + n) & 3) != 0; n++ )
322 {
323 if(!str[n])
324 return n;
325 }
326
327 p32 = (unsigned long*)(str + n);
328 for( ; ; n+=4 )
329 {
330 y = (*p32 & 0x7F7F7F7F) + 0x7F7F7F7F;
331 y = ~(y | *p32 | 0x7F7F7F7F);
332
333 if( y != 0 )
334 break;
335
336 p32++;
337 }
338
339 #if 1
340 while (str[n])
341 {
342 n++;
343 }
344 return n;
345 #else
346 if( y & 0x000000FF )
347 return n;
348 else if( y & 0x0000FF00 )
349 return n + 1;
350 else if( y & 0x00FF0000 )
351 return n + 2;
352 else
353 return n + 3;
354 // It is not possible to reach here
355 return -1;
356 #endif
357
358 #else // original
359 int n = 0;
360 while (str[n])
361 {
362 n++;
363 }
364 return n;
365 #endif
366 }
367
368 /*---------------------------------------------------------------------------*
369 Name: STD_GetStringNLength
370
371 Description: Gets string length below len. Same as strnlen.
372
373 Arguments: str : string
374 len: max length
375
376 Returns: string length
377 *---------------------------------------------------------------------------*/
STD_GetStringNLength(const char * str,int len)378 int STD_GetStringNLength(const char *str, int len)
379 {
380 #if defined(STRNLEN_4BYTE_SKIP)
381 int n;
382 unsigned long *p32, y;
383
384 for( n=0; (((unsigned long)(str + n) & 3) != 0) && (n < len); n++ )
385 {
386 if(!str[n])
387 return n;
388 }
389
390 p32 = (unsigned long*)(str + n);
391 for( ; n < len - 4; n+=4 )
392 {
393 y = (*p32 & 0x7F7F7F7F) + 0x7F7F7F7F;
394 y = ~(y | *p32 | 0x7F7F7F7F);
395
396 if( y != 0 )
397 break;
398
399 p32++;
400 }
401
402 while( str[n] && (n < len) )
403 {
404 n++;
405 }
406
407 return n;
408
409 #else // original
410 int n = 0;
411
412 while( str[n] && (n < len) )
413 {
414 n++;
415 }
416
417 return n;
418 #endif
419 }
420
421
422 /*---------------------------------------------------------------------------*
423 Name: STD_ConcatenateString
424
425 Description: concatenate strings. same to strcat
426
427 Arguments: str1 : original string
428 str2 : string to concatenate
429
430 Returns: concatenated string
431 *---------------------------------------------------------------------------*/
STD_ConcatenateString(char * str1,const char * str2)432 char *STD_ConcatenateString(char *str1, const char *str2)
433 {
434 int n = STD_GetStringLength(str1);
435 (void)STD_CopyString(&str1[n], str2);
436 return str1;
437 }
438
439 /*---------------------------------------------------------------------------*
440 Name: STD_ConcatenateLString
441
442 Description: Concatenates strings. Same as strlcat.
443
444 Arguments: str1 : original string
445 str2 : string to concatenate
446 size: buffer size of str1
447
448 Returns: length of str1 + length of str2
449 *---------------------------------------------------------------------------*/
STD_ConcatenateLString(char * str1,const char * str2,int size)450 int STD_ConcatenateLString(char *str1, const char *str2, int size)
451 {
452 int n;
453 int str2_len;
454
455 // If 'str1' is the length of 'size' or smaller and not terminated by NULL, [size + strlen(str2)] must be returned.
456 for( n = 0; n < size; ++n )
457 {
458 if( str1[n] == '\0' )
459 {
460 break;
461 }
462 }
463
464 if( n >= size )
465 {
466 return n + STD_GetStringLength(str2);
467 }
468
469 str2_len = STD_CopyLString(&str1[n], str2, size - n);
470
471 return n + str2_len;
472 }
473
474 /*---------------------------------------------------------------------------*
475 Name: STD_CompareString
476
477 Description: compare strings. same to strcmp
478
479 Arguments: str1, str2 : strings
480
481 Returns: 0 if same
482 *---------------------------------------------------------------------------*/
STD_CompareString(const char * str1,const char * str2)483 int STD_CompareString(const char *str1, const char *str2)
484 {
485 #if defined(STRCMP_4BYTE)
486 unsigned long dstalign, srcalign;
487 unsigned char chr1, chr2;
488 unsigned long lng1, lng2, y;
489 int i;
490
491 // 4-byte alignment check
492 dstalign = (unsigned long)str1 & 0x3;
493 srcalign = (unsigned long)str2 & 0x3;
494
495 i = 0;
496 // If it does not match, compare normally
497 if( dstalign ^ srcalign )
498 {
499 goto strcmp_normal;
500 }
501
502 // Compare the leading 4 bytes
503 if( dstalign )
504 {
505 for( ; i + dstalign < 4; i++ )
506 {
507 chr1 = (unsigned char)*(str1 + i);
508 chr2 = (unsigned char)*(str2 + i);
509 if(chr1 != chr2 || !chr1)
510 {
511 return (int)(chr1 - chr2);
512 }
513 }
514 }
515 // Compare 4 bytes
516 for( ; ; i += 4 )
517 {
518 lng1 = *(unsigned long*)(str1 + i);
519 lng2 = *(unsigned long*)(str2 + i);
520
521 if( lng1 != lng2 )
522 break;
523
524 y = (lng1 & 0x7F7F7F7F) + 0x7F7F7F7F;
525 y = ~(y | lng1 | 0x7F7F7F7F);
526
527 if( y != 0 )
528 break;
529 }
530
531 strcmp_normal:
532 // Compare normally
533 for(;;i++)
534 {
535 chr1 = (unsigned char)*(str1 + i);
536 chr2 = (unsigned char)*(str2 + i);
537 if(chr1 != chr2 || !chr1)
538 {
539 return (int)(chr1 - chr2);
540 }
541 }
542
543 // This will not be reached
544 return -1;
545
546 #else // original
547 while (*str1 == *str2 && *str1)
548 {
549 str1++;
550 str2++;
551 }
552 return (*str1 - *str2);
553 #endif
554 }
555
556 /*---------------------------------------------------------------------------*
557 Name: STD_CompareNString
558
559 Description: same to strncmp
560
561 Arguments: str1, str2 : strings
562 len: max length
563
564 Returns: 0 if same
565 *---------------------------------------------------------------------------*/
STD_CompareNString(const char * str1,const char * str2,int len)566 int STD_CompareNString(const char *str1, const char *str2, int len)
567 {
568 #if defined(STRNCMP_4BYTE)
569 unsigned long dstalign, srcalign;
570 unsigned char chr1, chr2;
571 unsigned long lng1, lng2;
572 unsigned long y;
573 int i;
574
575 if( len == 0 )
576 goto end;
577
578 // 4-byte alignment check
579 dstalign = (unsigned long)str1 & 0x3;
580 srcalign = (unsigned long)str2 & 0x3;
581
582 i = 0;
583 // If it does not match, compare normally
584 if( dstalign ^ srcalign )
585 {
586 goto strncmp_normal;
587 }
588
589 // Compare the leading 4 bytes
590 if( dstalign )
591 {
592 for( ; (i + dstalign < 4) && (i < len); i++ )
593 {
594 chr1 = (unsigned char)*(str1 + i);
595 chr2 = (unsigned char)*(str2 + i);
596 if(chr1 != chr2 || !chr1)
597 {
598 return (int)(chr1 - chr2);
599 }
600 }
601 }
602 // Compare 4 bytes
603 for( ; i <= len - 4; i += 4 )
604 {
605 lng1 = *(unsigned long*)(str1 + i);
606 lng2 = *(unsigned long*)(str2 + i);
607
608 // Check comparison
609 if( lng1 != lng2 )
610 break;
611
612 // NULL check
613 y = (lng1 & 0x7F7F7F7F) + 0x7F7F7F7F;
614 y = ~(y | lng1 | 0x7F7F7F7F);
615
616 if( y != 0 )
617 break;
618 }
619
620 strncmp_normal:
621 // Compare normally
622 for (; i < len; ++i)
623 {
624 chr1 = (unsigned char)*(str1 + i);
625 chr2 = (unsigned char)*(str2 + i);
626 if(chr1 != chr2 || !chr1)
627 {
628 return (int)(chr1 - chr2);
629 }
630 }
631
632 end:
633 // Return value
634 return 0;
635 #else
636 if (len)
637 {
638 int i;
639 for (i = 0; i < len; ++i)
640 {
641 int c = (int)(MI_ReadByte(str1 + i));
642 int d = (int)(MI_ReadByte(str2 + i));
643 if (c != d || !c)
644 {
645 return (int)(c - d);
646 }
647 }
648 }
649 return 0;
650 #endif
651 }
652
653 /*---------------------------------------------------------------------------*
654 Name: STD_CompareLString
655
656 Description: same to strlcmp
657
658 Arguments: str1, str2 : strings
659 len: max length
660
661 Returns: 0 if same
662 *---------------------------------------------------------------------------*/
STD_CompareLString(const char * str1,const char * str2,int len)663 int STD_CompareLString(const char *str1, const char *str2, int len)
664 {
665 int c, d;
666
667 while(len-- && *str2 != '\0')
668 {
669 c = (int)(MI_ReadByte(str1));
670 d = (int)(MI_ReadByte(str2));
671 if( c != d )
672 {
673 return c - d;
674 }
675 str1++;
676 str2++;
677 }
678 return (int)(MI_ReadByte(str1));
679 }
680
681 /*---------------------------------------------------------------------------*
682 Name: STD_CompareNString
683
684 Description: Same as strncasecmp.
685
686 Arguments: str1, str2 : strings
687 len: max length
688
689 Returns: 0 if same
690 *---------------------------------------------------------------------------*/
STD_CompareNIString(const char * str1,const char * str2,int len)691 int STD_CompareNIString(const char *str1, const char *str2, int len)
692 {
693 #if defined(STRNICMP_DIFF)
694 int i;
695 char c, d, diff;
696 int retval = 0;
697 #define TO_UPPER(x) ( ((x >= 'a') && (x <= 'z')) ? (x - 0x20) : x )
698
699 if( (str1 == str2) || (len == 0) )
700 {
701 return 0;
702 }
703
704 for( i = 0; ; i++ )
705 {
706 c = *(str1 + i);
707 d = *(str2 + i);
708 diff = (char)(c - d);
709
710 if( diff == 0 )
711 {
712 goto check_end;
713 }
714 else
715 {
716 if( diff == 'a' - 'A' )
717 {
718 if( (d >= 'A') && (d <= 'Z') )
719 {
720 goto check_end;
721 }
722 }
723 else if( diff == 'A' - 'a' )
724 {
725 if( (c >= 'A') && (c <= 'Z') )
726 {
727 goto check_end;
728 }
729 }
730 retval = TO_UPPER(c) - TO_UPPER(d);
731 break;
732 }
733 check_end:
734 if( c == '\0' )
735 break;
736 if( i >= len - 1 )
737 break;
738 }
739
740 return retval;
741 #else
742 int retval = 0;
743 #define TO_UPPER(x) ( ((x >= 'a') && (x <= 'z')) ? (x - 0x20) : x )
744
745 if( (str1 == str2) || (len == 0) )
746 {
747 return 0;
748 }
749
750 while( !(retval = TO_UPPER(*str1) - TO_UPPER(*str2)) )
751 {
752 if( (*str1 == '\0') || (--len == 0) )
753 {
754 break;
755 }
756 str1++;
757 str2++;
758 }
759
760 return retval;
761 #endif
762 }
763
764 /*---------------------------------------------------------------------------*
765 Name: STD_TSScanf
766
767 Description: This is sscanf with size reduced.
768 Supports basic format specifications "%(*?)([lh]{,2})([diouxXpn])".
769
770 Arguments: src: Input string
771 fmt: Format control string
772
773 Returns: Total number of substituted values.
774 Returns -1 if the function ends without a substitution or an error is detected.
775 *---------------------------------------------------------------------------*/
STD_TSScanf(const char * src,const char * fmt,...)776 SDK_WEAK_SYMBOL int STD_TSScanf(const char *src, const char *fmt, ...)
777 {
778 int ret;
779 va_list va;
780 va_start(va, fmt);
781 ret = STD_TVSScanf(src, fmt, va);
782 va_end(va);
783 return ret;
784 }
785
786 /*---------------------------------------------------------------------------*
787 Name: STDi_IsSpace
788
789 Description: Determines if the specified character is a whitespace character.
790
791 Arguments: c: Character to evaluate.
792
793 Returns: TRUE if whitespace.
794 *---------------------------------------------------------------------------*/
STDi_IsSpace(int c)795 static BOOL STDi_IsSpace(int c)
796 {
797 return (c == '\f') || (c == '\n') || (c == '\r') || (c == '\t') || (c == '\v') || (c == ' ');
798 }
799
800 /*---------------------------------------------------------------------------*
801 Name: STDi_GetBitset
802
803 Description: Gets the contents of the specified position of the bit set
804
805 Arguments: bitet: Bitset array.
806 i: Position of the information to be gotten.
807
808 Returns: TRUE if ON, FALSE if OFF
809 *---------------------------------------------------------------------------*/
STDi_GetBitset(const u32 * bitset,u32 i)810 inline static u32 STDi_GetBitset(const u32 *bitset, u32 i)
811 {
812 const u32 pos = (u32)(i >> 5UL);
813 const u32 bit = (u32)(i & 31UL);
814 return ((bitset[pos] >> bit) & 1UL);
815 }
816
817 /*---------------------------------------------------------------------------*
818 Name: STDi_SetBitset
819
820 Description: Sets the specified position of the bitset to ON.
821
822 Arguments: bitet: Bitset array.
823 i: Position to be turned ON
824
825 Returns: None.
826 *---------------------------------------------------------------------------*/
STDi_SetBitset(u32 * bitset,u32 i)827 inline static void STDi_SetBitset(u32 *bitset, u32 i)
828 {
829 const u32 pos = (i >> 5UL);
830 const u32 bit = (i & 31UL);
831 bitset[pos] |= (1UL << bit);
832 }
833
834 /*---------------------------------------------------------------------------*
835 Name: STDi_FillBitset
836
837 Description: Sets the specified range [a,b) of the bitset to ON.
838
839 Arguments: bitet: Bitset array.
840 a: Start position
841 b: End position
842
843 Returns: None.
844 *---------------------------------------------------------------------------*/
STDi_FillBitset(u32 * bitset,u32 a,u32 b)845 static void STDi_FillBitset(u32 *bitset, u32 a, u32 b)
846 {
847 while (a < b)
848 {
849 const u32 pos = (u32)(a >> 5UL);
850 const u32 bit = (u32)(a & 31UL);
851 u32 mask = (~0UL << bit);
852 a = (pos + 1UL) * 32UL;
853 if (a > b)
854 {
855 mask &= (u32)((1UL << (b & 31UL)) - 1UL);
856 }
857 bitset[pos] |= mask;
858 }
859 }
860
861 /*---------------------------------------------------------------------------*
862 Name: STD_TVSScanf
863
864 Description: This version supports va_list used with STD_TSScanf.
865 Supports basic format specifications.
866
867 Arguments: src: Input string
868 fmt: Format control string
869 vlist: Parameters
870
871 Returns: Total number of substituted values.
872 Returns -1 if the function ends without a substitution or an error is detected.
873 *---------------------------------------------------------------------------*/
STD_TVSScanf(const char * src,const char * fmt,va_list vlist)874 SDK_WEAK_SYMBOL int STD_TVSScanf(const char *src, const char *fmt, va_list vlist)
875 {
876 /* Start of verification string (required for %n) */
877 const char *src_base = src;
878 /* Has the format been matched even once? (return -1 if not) */
879 BOOL matched = FALSE;
880 /* Number of substitutions made. (return >=0 in this case) */
881 int stored = 0;
882
883 /* Parse format string one character at a time */
884 while (*fmt)
885 {
886 char c = *fmt;
887 /* Skip both formatting/verification if whitespace */
888 if (STDi_IsSpace(c))
889 {
890 while (STDi_IsSpace(*fmt))
891 {
892 ++fmt;
893 }
894 while (STDi_IsSpace(*src))
895 {
896 ++src;
897 }
898 continue;
899 }
900 /* Conventional characters must match exactly */
901 else if (c != '%')
902 {
903 if (c != *src)
904 {
905 break;
906 }
907 /* Check next byte if SHIFT-JIS */
908 if ((unsigned int)(((unsigned char)c ^ 0x20) - 0xA1) < 0x3C)
909 {
910 if (c != *++src)
911 {
912 break;
913 }
914 }
915 ++src;
916 ++fmt;
917 }
918 /* Simply compare if the escape character '%' is detected */
919 else if (fmt[1] == '%')
920 {
921 if (c != *src)
922 {
923 break;
924 }
925 fmt += 2;
926 }
927 /* Start format analysis if this is a conversion specification */
928 else
929 {
930 enum
931 {
932 flag_plus = 000002, /* '+' */
933 flag_minus = 000010, /* '-' */
934 flag_l1 = 000040, /* "l" */
935 flag_h1 = 000100, /* "h" */
936 flag_l2 = 000200, /* "ll" */
937 flag_h2 = 000400, /* "hh" */
938 flag_unsigned = 010000, /* 'o', 'u', ... */
939 flag_ignored = 020000, /* '*' */
940 flag_end
941 };
942 u64 val = 0;
943 int flag = 0, width = 0, radix = 10;
944 int digit;
945
946 /* Prohibit substitution flag */
947 c = *++fmt;
948 if (c == '*')
949 {
950 flag |= flag_ignored;
951 c = *++fmt;
952 }
953 /* Specify width */
954 while ((c >= '0') && (c <= '9'))
955 {
956 width = (width * 10) + c - '0';
957 c = *++fmt;
958 }
959 /* Modify conversion */
960 switch (c)
961 {
962 case 'h':
963 c = *++fmt;
964 if (c != 'h')
965 {
966 flag |= flag_h1;
967 }
968 else
969 flag |= flag_h2, c = *++fmt;
970 break;
971 case 'l':
972 c = *++fmt;
973 if (c != 'l')
974 flag |= flag_l1;
975 else
976 flag |= flag_l2, c = *++fmt;
977 break;
978 }
979 /* Conversion type */
980 switch (c)
981 {
982 case 'd': /* Signed decimal number */
983 radix = 10;
984 goto get_integer;
985 case 'i': /* Signed base-8/10/16 number */
986 radix = -1;
987 goto get_integer;
988 case 'o': /* Signed octal number */
989 radix = 8;
990 goto get_integer;
991 case 'u': /* Unsigned decimal number */
992 radix = 10;
993 flag |= flag_unsigned;
994 goto get_integer;
995 case 'X': /* Unsigned hexadecimal number */
996 case 'x': /* Unsigned hexadecimal number */
997 case 'p': /* Pointer conversion (unsigned hexadecimal) */
998 radix = 16;
999 flag |= flag_unsigned;
1000 goto get_integer;
1001 case 's': /* Character string up to non-whitespace */
1002 case 'c': /* Character string of specified width only */
1003 goto store_string;
1004
1005 case '[': /* Character class */
1006 goto store_char_class;
1007
1008 case 'n': /* Store match location */
1009 /* Since this doesn't contribute to the substitution count, subtract it here. */
1010 if (!(flag & flag_ignored))
1011 {
1012 --stored;
1013 }
1014 val = src - src_base;
1015 c = *++fmt;
1016 goto store_integer;
1017 }
1018
1019 // invalid:
1020 /* Parsing ended in an unfortunate result */
1021 break;
1022
1023 get_integer:
1024 /* Integer input processing */
1025 ++fmt;
1026 c = *src;
1027 /* Skip whitespace */
1028 while (STDi_IsSpace(c))
1029 {
1030 c = *++src;
1031 }
1032 /* Get sign */
1033 for (;; c = *++src)
1034 {
1035 if (c == '+')
1036 {
1037 flag |= flag_plus;
1038 }
1039 else if (c == '-')
1040 {
1041 /* '-' in an unsigned type is an error */
1042 if ((flag & flag_unsigned) != 0)
1043 {
1044 /*
1045 * ...would be a good way to do things, but since this is ignored with gcc and CW, the SDK currently follows their lead.
1046
1047
1048 */
1049 //goto invalid;
1050 }
1051 flag |= flag_minus;
1052 }
1053 else
1054 {
1055 break;
1056 }
1057 }
1058 /* Automatic detection of integers (%i) */
1059 if (radix == -1)
1060 {
1061 if (c != '0')
1062 {
1063 radix = 10;
1064 }
1065 else if ((src[1] == 'x') || (src[1] == 'X'))
1066 {
1067 radix = 16;
1068 }
1069 else
1070 {
1071 radix = 8;
1072 }
1073 }
1074 /* If hexadecimal, skip "^(0[xX])?" */
1075 if ((radix == 16) && (c == '0') && ((src[1] == 'x') || (src[1] == 'X')))
1076 {
1077 src += 2;
1078 c = *src;
1079 }
1080 /* Get integer */
1081 if (width == 0)
1082 {
1083 width = 0x7FFFFFFF;
1084 }
1085 for (digit = 0; digit < width; ++digit)
1086 {
1087 u32 d = (u32)(c - '0');
1088 if (d >= 10)
1089 {
1090 d -= (u32)('a' - '0');
1091 if (d < 6)
1092 {
1093 d += 10;
1094 }
1095 else
1096 {
1097 d -= (u32)('A' - 'a');
1098 if (d < 6)
1099 {
1100 d += 10;
1101 }
1102 }
1103 }
1104 if (d >= radix)
1105 {
1106 break;
1107 }
1108 c = *++src;
1109 val = val * radix + d;
1110 }
1111 /* No input is an error */
1112 if (digit == 0)
1113 {
1114 break;
1115 }
1116 /* Adjust sign */
1117 if (flag & flag_minus)
1118 {
1119 val = (u64)(val * -1);
1120 }
1121 /* At least conversion succeeded */
1122 matched = TRUE;
1123 store_integer:
1124 /* Substitute */
1125 if (!(flag & flag_ignored))
1126 {
1127 ++stored;
1128 if (flag & flag_h2)
1129 {
1130 *va_arg(vlist, u8 *) = (u8)val;
1131 }
1132 else if (flag & flag_h1)
1133 {
1134 *va_arg(vlist, u16 *) = (u16)val;
1135 }
1136 else if (flag & flag_l2)
1137 {
1138 *va_arg(vlist, u64 *) = (u64)val;
1139 }
1140 else
1141 {
1142 *va_arg(vlist, u32 *) = (u32)val;
1143 }
1144 }
1145 continue;
1146
1147 store_string:
1148 /* Substitute character string */
1149 {
1150 char *dst = NULL, *dst_bak = NULL;
1151 ++fmt;
1152 if (!(flag & flag_ignored))
1153 {
1154 dst = va_arg(vlist, char *);
1155 dst_bak = dst;
1156 }
1157 /*
1158 * If s, search until you find whitespace and append '\0'
1159 * If c, search for the specified width
1160 */
1161 if (c == 's')
1162 {
1163 if (width == 0)
1164 {
1165 width = 0x7FFFFFFF;
1166 }
1167 for (c = *src; STDi_IsSpace(c); c = *++src)
1168 {
1169 }
1170 for (; c && !STDi_IsSpace(c) && (width > 0); --width, c = *++src)
1171 {
1172 if (dst)
1173 {
1174 *dst++ = c;
1175 }
1176 }
1177 /*
1178 * If [dst! = dst_bak], it is assumed that more than one character was substituted
1179 * Append NULL to the end, make [matched = TRUE], and ++ the substitute success number
1180 */
1181 if (dst != dst_bak)
1182 {
1183 *dst++ = '\0';
1184 ++stored;
1185 matched = TRUE;
1186 }
1187 }
1188 else
1189 {
1190 if (width == 0)
1191 {
1192 width = 1;
1193 }
1194 for (c = *src; c && (width > 0); --width, c = *++src)
1195 {
1196 if (dst)
1197 {
1198 *dst++ = c;
1199 }
1200 }
1201 /*
1202 * If [dst! = dst_bak], it is assumed that more than one character was substituted
1203 * Append NULL to the end, make [matched = TRUE], and ++ the substitute success number
1204 */
1205 if (dst != dst_bak)
1206 {
1207 ++stored;
1208 matched = TRUE;
1209 if(width > 0)
1210 {
1211 *dst++ = '\0';
1212 }
1213 }
1214 }
1215 }
1216 continue;
1217
1218 store_char_class:
1219 ++fmt;
1220 /* Character class substitution processing */
1221 {
1222 char *dst = NULL;
1223
1224 u32 bitset[256 / (8 * sizeof(u32))];
1225 u32 matchcond = 1;
1226 u32 from = 0;
1227 BOOL in_range = FALSE;
1228 MI_CpuFill32(bitset, 0x00000000UL, sizeof(bitset));
1229 if (*fmt == '^')
1230 {
1231 matchcond = 0;
1232 ++fmt;
1233 }
1234 /* Start-of-line escape */
1235 if (*fmt == ']')
1236 {
1237 STDi_SetBitset(bitset, (u8)*fmt);
1238 ++fmt;
1239 }
1240 /* Character class analysis */
1241 for (;; ++fmt)
1242 {
1243 /* Terminus detection */
1244 if (!*fmt || (*fmt == ']'))
1245 {
1246 /* A terminus whose range is being specified is treated as a simple character */
1247 if (in_range)
1248 {
1249 STDi_SetBitset(bitset, from);
1250 STDi_SetBitset(bitset, (u32)'-');
1251 }
1252 if (*fmt == ']')
1253 {
1254 ++fmt;
1255 }
1256 break;
1257 }
1258 /* Beginning of the simple character or specified range */
1259 else if (!in_range)
1260 {
1261 /* Begin range specification */
1262 if ((from != 0) && (*fmt == '-'))
1263 {
1264 in_range = TRUE;
1265 }
1266 else
1267 {
1268 STDi_SetBitset(bitset, (u8)*fmt);
1269 from = (u8)*fmt;
1270 }
1271 }
1272 /* End range specification */
1273 else
1274 {
1275 u32 to = (u8)*fmt;
1276 /* Illegal specified ranges are treated as separate specified characters */
1277 if (from > to)
1278 {
1279 STDi_SetBitset(bitset, from);
1280 STDi_SetBitset(bitset, (u32)'-');
1281 STDi_SetBitset(bitset, to);
1282 }
1283 /* Also includes and collectively sets terminal characters */
1284 else
1285 {
1286 STDi_FillBitset(bitset, from, to + 1UL);
1287 }
1288 in_range = FALSE;
1289 from = 0;
1290 }
1291 }
1292 /* Verification of character class and string */
1293 /* At least conversion has been successful to this point */
1294 matched = TRUE;
1295 if (!(flag & flag_ignored))
1296 {
1297 ++stored;
1298 dst = va_arg(vlist, char *);
1299 }
1300 if (width == 0)
1301 {
1302 width = 0x7FFFFFFF;
1303 }
1304 for (c = *src; c && (width > 0); --width, c = *++src)
1305 {
1306 if (STDi_GetBitset(bitset, (u8)c) != matchcond)
1307 {
1308 break;
1309 }
1310 if (dst)
1311 {
1312 *dst++ = c;
1313 }
1314 }
1315 if (dst)
1316 {
1317 *dst++ = '\0';
1318 }
1319 }
1320 continue;
1321
1322 }
1323 }
1324
1325 return (*src || matched) ? stored : -1;
1326
1327 }
1328