ameba-sdk-gcc-make/component/common/api/platform/stdlib_patch.c
2016-06-04 19:09:35 +08:00

919 lines
17 KiB
C
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
this is the c lib patch, It can help when the clib provided by IAR
does not work well.
How to use this:
1.You must include platform_stdlib.h in you source file。
2.There is a macro USE_CLIB_PATCH in platform_stdlib.h should be opened.
If there is some problems using this patch,
You'd better check if you code runs into these functions:
DiagSscanfPatch
DiagStrtokPatch
DiagStrstrPatch
DiagSnPrintfPatch
DiagPrintfPatch
DiagSPrintfPatch
DiagPrintfPatch
DiagSPrintfPatch
DiagSnPrintfPatch
DiagStrstrPatch
DiagStrtokPatch
*/
#include <stdarg.h>
#define DiagPutChar HalSerialPutcRtl8195a
#define IN
#define NULL 0
typedef unsigned int size_t;
typedef unsigned int SIZE_T;
typedef unsigned long long u64;
typedef unsigned int u32;
typedef unsigned short int u16;
typedef unsigned char u8;
typedef signed long long s64;
typedef signed int s32;
typedef signed short int s16;
typedef unsigned char bool;
#define in_range(c, lo, up) ((u8)c >= lo && (u8)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == ',')
#define ULLONG_MAX (~0ULL)
#define USHRT_MAX ((u16)(~0U))
#define KSTRTOX_OVERFLOW (1U << 31)
#define SHRT_MAX ((s16)(USHRT_MAX>>1))
static inline char _tolower(const char c)
{
return c | 0x20;
}
extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
extern s64 div_s64(s64 dividend, s32 divisor);
extern inline char _tolower(const char c);
extern u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder);
extern u64 div_u64(u64 dividend, u32 divisor);
extern unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p);
extern const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
extern char *skip_spaces(const char *str);
extern int skip_atoi(const char **s);
extern void HalSerialPutcRtl8195a(u8 c);
static unsigned long long simple_strtoull_patch(const char *cp, char **endp, unsigned int base)
{
unsigned long long result;
unsigned int rv;
cp = _parse_integer_fixup_radix(cp, &base);
rv = _parse_integer(cp, base, &result);
return result;
}
static long long simple_strtoll_patch(const char *cp, char **endp, unsigned int base)
{
if(*cp == '-')
return -simple_strtoull_patch(cp + 1, endp, base);
return simple_strtoull_patch(cp, endp, base);
}
static unsigned long simple_strtoul_patch(const char *cp, char **endp, unsigned int base)
{
return simple_strtoull_patch(cp, endp, base);
}
static long simple_strtol_patch(const char *cp, char **endp, unsigned int base)
{
if(*cp == '-')
return -simple_strtoul_patch(cp + 1, endp, base);
return simple_strtoul_patch(cp, endp, base);
}
static int judge_digit_width(const char *str)
{
int width = 0;
while(isdigit(*str)) {
width++;
str++;
}
return width;
}
static int _vsscanf_patch(const char *buf, const char *fmt, va_list args)
{
const char *str = buf;
char *next;
char digit;
int num = 0;
int i =0;
u8 qualifier;
unsigned int base;
union {
long long s;
unsigned long long u;
} val;
s16 field_width;
bool is_sign;
char str_store[20] = {0};
while(*fmt) {
/* skip any white space in format */
/* white space in format matchs any amount of
* white space, including none, in the input.
*/
if(isspace(*fmt)) {
fmt = skip_spaces(++fmt);
str = skip_spaces(str);
}
/* anything that is not a conversion must match exactly */
if(*fmt != '%' && *fmt) {
if(*fmt++ != *str++) {
break;
}
continue;
}
if(!*fmt) {
break;
}
++fmt;
/* skip this conversion.
* advance both strings to next white space
*/
if(*fmt == '*') {
if(!*str) {
break;
}
while(!isspace(*fmt) && *fmt != '%' && *fmt)
fmt++;
while(!isspace(*str) && *str)
str++;
continue;
}
/* get field width */
field_width = -1;
if(isdigit(*fmt)) {
field_width = skip_atoi(&fmt);
if(field_width <= 0) {
break;
}
}
/* get conversion qualifier */
qualifier = -1;
if(*fmt == 'h' || _tolower(*fmt) == 'l' ||
_tolower(*fmt) == 'z') {
qualifier = *fmt++;
if(qualifier == *fmt) {
if(qualifier == 'h') {
qualifier = 'H';
fmt++;
} else if(qualifier == 'l') {
qualifier = 'L';
fmt++;
}
}
}
if(!*fmt) {
break;
}
if(*fmt == 'n') {
/* return number of characters read so far */
*va_arg(args, int *) = str - buf;
++fmt;
continue;
}
if(!*str) {
break;
}
base = 10;
is_sign = 0;
switch(*fmt++) {
case 'c': {
char *s = (char *)va_arg(args, char*);
if(field_width == -1)
field_width = 1;
do {
*s++ = *str++;
} while(--field_width > 0 && *str);
num++;
}
continue;
case 's': {
char *s = (char *)va_arg(args, char *);
if(field_width == -1)
field_width = SHRT_MAX;
/* first, skip leading white space in buffer */
str = skip_spaces(str);
/* now copy until next white space */
while(*str && !isspace(*str) && field_width--) {
*s++ = *str++;
}
*s = '\0';
num++;
}
continue;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
case 'i':
base = 0;
case 'd':
is_sign = 1;
case 'u':
break;
case '%':
/* looking for '%' in str */
if(*str++ != '%') {
return num;
}
continue;
default:
/* invalid format; stop here */
return num;
}
/* have some sort of integer conversion.
* first, skip white space in buffer.
*/
str = skip_spaces(str);
digit = *str;
if(is_sign && digit == '-')
digit = *(str + 1);
if(!digit
|| (base == 16 && !isxdigit(digit))
|| (base == 10 && !isdigit(digit))
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|| (base == 0 && !isdigit(digit))) {
break;
}
//here problem *******************************************
//troy add ,fix support %2d, but not support %d
if(field_width <= 0) {
field_width = judge_digit_width(str);
}
/////troy add, fix str passed inwidth wrong
for(i = 0; i<field_width ; i++)
str_store[i] = str[i];
next = (char*)str + field_width;
if(is_sign) {
val.s = qualifier != 'L' ?
simple_strtol_patch(str_store, &next, base) :
simple_strtoll_patch(str_store, &next, base);
} else {
val.u = qualifier != 'L' ?
simple_strtoul_patch(str_store, &next, base) :
simple_strtoull_patch(str_store, &next, base);
}
////troy add
for(i = 0; i<20 ; i++)
str_store[i] = 0;
//判断转换的字符串的宽度是否大于 %2d
if(field_width > 0 && next - str > field_width) {
if(base == 0)
_parse_integer_fixup_radix(str, &base);
while(next - str > field_width) {
if(is_sign) {
val.s = div_s64(val.s, base);
} else {
val.u = div_u64(val.u, base);
}
--next;
}
}
switch(qualifier) {
case 'H': /* that's 'hh' in format */
if(is_sign)
*va_arg(args, signed char *) = val.s;
else
*va_arg(args, unsigned char *) = val.u;
break;
case 'h':
if(is_sign)
*va_arg(args, short *) = val.s;
else
*va_arg(args, unsigned short *) = val.u;
break;
case 'l':
if(is_sign)
*va_arg(args, long *) = val.s;
else
*va_arg(args, unsigned long *) = val.u;
break;
case 'L':
if(is_sign)
*va_arg(args, long long *) = val.s;
else
*va_arg(args, unsigned long long *) = val.u;
break;
case 'Z':
case 'z':
*va_arg(args, size_t *) = val.u;
break;
default:
if(is_sign)
*va_arg(args, int *) = val.s;
else
*va_arg(args, unsigned int *) = val.u;
break;
}
num++;
if(!next) {
break;
}
str = next;
}
return num;
}
int DiagSscanfPatch(const char *buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = _vsscanf_patch(buf, fmt, args);
va_end(args);
return i;
}
/*********************************************************/
char* DiagStrtokPatch(char *str, const char* delim) {
static char* _buffer;
if(str != NULL) _buffer = str;
if(_buffer[0] == '\0') return NULL;
char *ret = _buffer, *b;
const char *d;
for(b = _buffer; *b !='\0'; b++) {
for(d = delim; *d != '\0'; d++) {
if(*b == *d) {
*b = '\0';
_buffer = b+1;
// skip the beginning delimiters
if(b == ret) {
ret++;
continue;
}
return ret;
}
}
}
return ret;
}
/*********************************************************/
char *DiagStrstrPatch(char *string, char *substring)
{
register char *a, *b;
/* First scan quickly through the two strings looking for a
* single-character match. When it's found, then compare the
* rest of the substring.
*/
b = substring;
if(*b == 0) {
return string;
}
for(; *string != 0; string += 1) {
if(*string != *b) {
continue;
}
a = string;
while(1) {
if(*b == 0) {
return string;
}
if(*a++ != *b++) {
break;
}
}
b = substring;
}
return (char *) 0;
}
/*********************************************************/
int DiagSnPrintfPatch(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
char *p, *s, *buf_end = NULL;
const int *dp = ((const int *)&fmt)+1;
if(buf == NULL)
return 0;
va_start(ap, fmt);
s = buf;
buf_end = size? (buf + size):(char*)~0;
for(; *fmt != '\0'; ++fmt) {
if(*fmt != '%') {
*s++ = *fmt;
if(s >= buf_end) {
goto Exit;
}
continue;
}
if(*++fmt == 's') {
for(p = (char *)*dp++; *p != '\0'; p++) {
*s++ = *p;
if(s >= buf_end) {
goto Exit;
}
}
}
else { /* Length of item is bounded */
char tmp[20], *q = tmp;
int alt = 0;
int shift = 0;// = 12;
const long *lpforchk = (const long *)dp;
if((*lpforchk) < 0x10) {
shift = 0;
}
else if(((*lpforchk) >= 0x10) && ((*lpforchk) < 0x100)) {
shift = 4;
}
else if(((*lpforchk) >= 0x100) && ((*lpforchk) < 0x1000)) {
shift = 8;
}
else if(((*lpforchk) >= 0x1000) && ((*lpforchk) < 0x10000)) {
shift = 12;
}
else if(((*lpforchk) >= 0x10000) && ((*lpforchk) < 0x100000)) {
shift = 16;
}
else if(((*lpforchk) >= 0x100000) && ((*lpforchk) < 0x1000000)) {
shift = 20;
}
else if(((*lpforchk) >= 0x1000000) && ((*lpforchk) < 0x10000000)) {
shift = 24;
}
else if((*lpforchk) >= 0x10000000) {
shift = 28;
}
else {
shift = 28;
}
if((*fmt >= '0') && (*fmt <= '9'))
{
int width;
unsigned char fch = *fmt;
for(width=0; (fch>='0') && (fch<='9'); fch=*++fmt)
{ width = width * 10 + fch - '0';
}
shift=(width-1)*4;
}
/*
* Before each format q points to tmp buffer
* After each format q points past end of item
*/
if((*fmt == 'x')||(*fmt == 'X') || (*fmt == 'p') || (*fmt == 'P')) {
/* With x86 gcc, sizeof(long) == sizeof(int) */
const long *lp = (const long *)dp;
long h = *lp++;
int hex_count = 0;
unsigned long h_back = h;
int ncase = (*fmt & 0x20);
dp = (const int *)lp;
if((*fmt == 'p') || (*fmt == 'P'))
alt=1;
if(alt) {
*q++ = '0';
*q++ = 'X' | ncase;
}
while(h_back) {
hex_count += (h_back & 0xF) ? 1 : 0;
h_back = h_back >> 4;
}
if(shift < (hex_count - 1)*4)
shift = (hex_count - 1)*4;
for(; shift >= 0; shift -= 4)
*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
}
else if(*fmt == 'd') {
int i = *dp++;
char *r;
int digit_space = 0;
if(i < 0) {
*q++ = '-';
i = -i;
digit_space++;
}
p = q; /* save beginning of digits */
do {
*q++ = '0' + (i % 10);
i /= 10;
digit_space++;
} while(i);
for(; shift >= 0; shift -= 4) {
if(digit_space-- > 0) {
; //do nothing
} else {
*q++ = '0';
}
}
/* reverse digits, stop in middle */
r = q; /* don't alter q */
while(--r > p) {
i = *r;
*r = *p;
*p++ = i;
}
}
else if(*fmt == 'c')
*q++ = *dp++;
else
*q++ = *fmt;
/* now output the saved string */
for(p = tmp; p < q; ++p) {
*s++ = *p;
if(s >= buf_end) {
goto Exit;
}
}
}
}
Exit:
if(buf)
*s = '\0';
va_end(ap);
return(s-buf);
}
/*********************************************************/
static int VSprintfPatch(char *buf, const char *fmt, const int *dp)
{
char *p, *s;
s = buf;
for(; *fmt != '\0'; ++fmt) {
if(*fmt != '%') {
if(buf) {
*s++ = *fmt;
} else {
DiagPutChar(*fmt);
}
continue;
}
if(*++fmt == 's') {
for(p = (char *)*dp++; *p != '\0'; p++) {
if(buf) {
*s++ = *p;
} else {
DiagPutChar(*p);
}
}
}
else { /* Length of item is bounded */
char tmp[20], *q = tmp;
int alt = 0;
int shift = 0;// = 12;
const long *lpforchk = (const long *)dp;
if((*lpforchk) < 0x10) {
shift = 0;
}
else if(((*lpforchk) >= 0x10) && ((*lpforchk) < 0x100)) {
shift = 4;
}
else if(((*lpforchk) >= 0x100) && ((*lpforchk) < 0x1000)) {
shift = 8;
}
else if(((*lpforchk) >= 0x1000) && ((*lpforchk) < 0x10000)) {
shift = 12;
}
else if(((*lpforchk) >= 0x10000) && ((*lpforchk) < 0x100000)) {
shift = 16;
}
else if(((*lpforchk) >= 0x100000) && ((*lpforchk) < 0x1000000)) {
shift = 20;
}
else if(((*lpforchk) >= 0x1000000) && ((*lpforchk) < 0x10000000)) {
shift = 24;
}
else if((*lpforchk) >= 0x10000000) {
shift = 28;
}
else {
shift = 28;
}
#if 1 //wei patch for %02x
if((*fmt >= '0') && (*fmt <= '9'))
{
int width;
unsigned char fch = *fmt;
for(width=0; (fch>='0') && (fch<='9'); fch=*++fmt)
{ width = width * 10 + fch - '0';
}
shift=(width-1)*4;
}
#endif
/*
* Before each format q points to tmp buffer
* After each format q points past end of item
*/
if((*fmt == 'x')||(*fmt == 'X') || (*fmt == 'p') || (*fmt == 'P')) {
/* With x86 gcc, sizeof(long) == sizeof(int) */
const long *lp = (const long *)dp;
long h = *lp++;
int hex_count = 0;
unsigned long h_back = h;
int ncase = (*fmt & 0x20);
dp = (const int *)lp;
if((*fmt == 'p') || (*fmt == 'P'))
alt=1;
if(alt) {
*q++ = '0';
*q++ = 'X' | ncase;
}
//hback 是实际得到的数据hex_count是统计数据的HEX字符个数
while(h_back) {
hex_count += (h_back & 0xF) ? 1 : 0;
h_back = h_back >> 4;
}
//这里修复 example 字符有4个但是用了%02x导致字符被截断的情况
if(shift < (hex_count - 1)*4)
shift = (hex_count - 1)*4;
//printf("(%d,%d)", hex_count, shift);
for(; shift >= 0; shift -= 4) {
*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
}
}
else if(*fmt == 'd') {
int i = *dp++;
char *r;
int digit_space = 0;
if(i < 0) {
*q++ = '-';
i = -i;
digit_space++;
}
p = q; /* save beginning of digits */
do {
*q++ = '0' + (i % 10);
i /= 10;
digit_space++;
} while(i);
//这里修复 example用了%08d后在数字前面没有0的情况
for(; shift >= 0; shift -= 4) {
if(digit_space-- > 0) {
; //do nothing
} else {
*q++ = '0';
}
}
/* reverse digits, stop in middle */
r = q; /* don't alter q */
while(--r > p) {
i = *r;
*r = *p;
*p++ = i;
}
}
else if(*fmt == 'c')
*q++ = *dp++;
else
*q++ = *fmt;
/* now output the saved string */
for(p = tmp; p < q; ++p) {
if(buf) {
*s++ = *p;
} else {
DiagPutChar(*p);
}
if((*p) == '\n') {
DiagPutChar('\r');
}
}
}
}
if(buf)
*s = '\0';
return (s - buf);
}
u32 DiagPrintfPatch(
IN const char *fmt, ...
)
{
(void)VSprintfPatch(0, fmt, ((const int *)&fmt)+1);
return 1;
}
u32 DiagSPrintfPatch(
IN u8 *buf,
IN const char *fmt, ...
)
{
(void)VSprintfPatch((char*)buf, fmt, ((const int *)&fmt)+1);
return 1;
}