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