sdk-ameba-v4.0c_180328/component/common/api/platform/stdlib_patch.c

919 lines
17 KiB
C
Raw Permalink Normal View History

2019-04-02 08:34:25 +00:00
/*
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
*/
#ifndef CONFIG_PLATFORM_8711B
#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;
}
#endif