#include "c_type51.h" #include "c_lib.h" ///#include "../msp/msp_uart0.h" ////#include "../msp/time.h" #include #define INCLUDE_STRING #ifdef INCLUDE_STRING #include "string.h" #endif #ifdef KERNEL #define NOFLOAT #endif #define sprintf my_sprintf #define vsprintf my_vsprintf #define atoi my_atoi #define ftoa my_ftoa #define strnlen my_strnlen #define DOUBLE_ZERO double(1E-307) #define IS_DOUBLE_ZERO(D) (D <= DOUBLE_ZERO && D >= -DOUBLE_ZERO) typedef char* va_listcc; #ifndef __va_rounded_size #define __va_rounded_size(TYPE) (((sizeof(TYPE)+sizeof(int)-1)/sizeof(int))*sizeof(int)) #endif #ifndef va_start #define va_start(AP, LASTARG) (AP = ((char *)& (LASTARG) + __va_rounded_size(LASTARG))) #endif #ifndef va_arg #define va_arg(AP, TYPE) (AP += __va_rounded_size(TYPE), *((TYPE *)(AP - __va_rounded_size(TYPE)))) #endif #ifndef va_end #define va_end(AP) (AP = (va_listcc)0 ) #endif #define ZEROPAD 1 // Pad with zero #define SIGN 2 // Unsigned/signed long #define PLUS 4 // Show plus #define SPACE 8 // Space if plus #define LEFT 16 // Left justified #define SPECIAL 32 // 0x #define LARGE 64 // Use 'ABCDEF' instead of 'abcdef' #define abs(a) ((a) < 0 ? -(a) :(a)) #define is_digit(c) ((c) >= '0' && (c) <= '9') #define FLT_MAX_10_EXP 38 #define DBL_MAX_10_EXP 308 #define LDBL_MAX_10_EXP 308 int i = 0; static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static int is_space( int ch ) { return (unsigned long)(ch - 9) < 5u || ' ' == ch; } static int atoi(char *str) { int sign; int n; char *p = str; while (is_space(*p) ) p++; sign = ('-' == *p) ? -1 : 1; if ('+' == *p || '-' == *p) p++; for (n = 0; is_digit(*p); p++) n = 10 * n + (*p - '0'); return sign*n; } #ifndef INCLUDE_STRING #define memset my_memset #define memcpy my_memcpy #define strlen my_strlen #define strcmp my_strcmp #define strchr my_strchr static char * strchr(const char *str, int ch) { while (*str && *str != (char)ch) str++; if (*str == (char)ch) return((char *)str); return 0; } static void * memset(void *dst, int val, unsigned long ulcount) { if(!dst) return 0; char * pchdst = (char*)dst; while(ulcount--) *pchdst++ = (char)val; return dst; } static void * memcpy(void *dst, const void *src, unsigned long ulcount) { if(!(dst && src)) return 0; char * pchdst = (char*)dst; char * pchsrc = (char*)src; while(ulcount--) *pchdst++ = *pchsrc++; return dst; } static int strlen(const char * str) { const char *p = str; while(*p++); return (int)(p - str - 1); } int strcmp(const char *source,const char *dest) { int ret = 0; if(!source || !dest) return -2; while( ! (ret = *( unsigned char *)source - *(unsigned char *)dest) && *dest) { source++; dest++; } if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ; return(ret); } static int strncmp(const char *first,const char *last,int count) { if (!count) return 0; while (--count && *first && *first == *last) first++,last++; return ( *(unsigned char *)first - *(unsigned char *)last ); } #endif /*NO_INCLUDE_STRING*/ static unsigned long strnlen(const char *s, int count) { const char *sc; for (sc = s; *sc != '\0' && count--; ++sc); return sc - s; } static char * itoa(int n, char * chBuffer) { int i = 1; char * pch = chBuffer; if(!pch) return 0; while(n / i) i *= 10; if(n < 0) { n = -n; *pch++ = '-'; } if (0 == n) i = 10; while(i /= 10) { *pch++ = n / i + '0'; n %= i; } *pch = '\0'; return chBuffer; } static int skip_atoi(const char **s) { int i = 0; while (is_digit(**s)) { i = i*10 + *((*s)++) - '0'; } return i; } static char * number(char *str, long num, int base, int size, int precision, int type) { char c, sign, tmp[66]; char *dig = digits; int i; if (type & LARGE) dig = upper_digits; if (type & LEFT) type &= ~ZEROPAD; if (base < 2 || base > 36) return 0; c = (type & ZEROPAD) ? '0' : ' '; sign = 0; if (type & SIGN) { if (num < 0) { sign = '-'; num = -num; size--; } else if (type & PLUS) { sign = '+'; size--; } else if (type & SPACE) { sign = ' '; size--; } } if (type & SPECIAL) { if (16 == base) size -= 2; else if (8 == base) size--; } i = 0; if (0 == num) { tmp[i++] = '0'; } else { while (num != 0) { tmp[i++] = dig[((unsigned long) num) % (unsigned) base]; num = ((unsigned long) num) / (unsigned) base; } } if (i > precision) precision = i; size -= precision; if (!(type & (ZEROPAD | LEFT))) { while(size-- > 0) *str++ = ' '; } if (sign) *str++ = sign; if (type & SPECIAL) { if (8 == base) { *str++ = '0'; } else if (16 == base) { *str++ = '0'; *str++ = digits[33]; } } if(!(type & LEFT)) { while(size-- > 0) *str++ = c; } while(i < precision--) *str++ = '0'; while(i-- > 0) *str++ = tmp[i]; while(size-- > 0) *str++ = ' '; return str; } static char * eaddr(char *str, unsigned char *addr, int size, int precision, int type) {int i = 0; char tmp[24]; char *dig = digits; int len = 0; if (type & LARGE) dig = upper_digits; for ( i = 0; i < 6; i++) { if (i != 0) tmp[len++] = ':'; tmp[len++] = dig[addr[i] >> 4]; tmp[len++] = dig[addr[i] & 0x0F]; } if (!(type & LEFT)) { while (len < size--) *str++ = ' '; } for ( i = 0; i < len; ++i) { *str++ = tmp[i]; } while (len < size--) *str++ = ' '; return str; } static char * iaddr(char *str, unsigned char *addr, int size, int precision, int type) { char tmp[24]; int len = 0; for (i = 0; i < 4; i++) { int n = addr[i]; if (i != 0) tmp[len++] = '.'; if (0 == n) { tmp[len++] = digits[0]; } else { if (n >= 100) { tmp[len++] = digits[n / 100]; n %= 100; tmp[len++] = digits[n / 10]; n %= 10; } else if (n >= 10) { tmp[len++] = digits[n / 10]; n %= 10; } tmp[len++] = digits[n]; } } if (!(type & LEFT)) { while(len < size--) *str++ = ' '; } for (i = 0; i < len; ++i) { *str++ = tmp[i]; } while (len < size--) *str++ = ' '; return str; } #ifndef NOFLOAT static char * ftoaE(char* pchBuffer, int dppos, double value) { double roundingValue = 0.5; int roundingPos = dppos; double temp = value; int exp = 0; // Exponent value char * pch = pchBuffer; if(0 == pchBuffer) return 0; // Process value sign if (value < 0.0) { value = -value; *pchBuffer++ = '-'; } else { *pchBuffer++ = '+'; } #if 0 // Round value and get exponent if(!IS_DOUBLE_ZERO(value)) /*if (value != 0.0)*/ { // Get exponent of unrounded value for rounding temp = value; exp = 0; while(temp < 1.0) { temp *= 10.0; exp--; } while(temp >= 10.0) { temp *= 0.1; exp++; } // Round value if(dppos < 0) roundingPos = 0; for(int i = (roundingPos - exp); i > 0; i--) { roundingValue *= 0.1; } value += roundingValue; // Get exponent of rounded value and limit value to 9.999...1.000 exp = 0; while(value < 1.0) { value *= 10.0; exp--; } while(value >= 10.0) { value *= 0.1; exp++; } } // Compose mantissa output string for (int i = ((dppos < 0) ? 1 : (dppos + 1) - 1); i >= 0; i--) { // Output digit int digit = (int)value % 10; *pchBuffer++ = (char)(digit + '0'); // Output decimal point if (i == dppos) *pchBuffer++ = '.'; value = (value - (double)digit) * 10.0; } // Compose exponent output string *pchBuffer++ = 'E'; itoa(exp, pchBuffer); #endif return pch; } #define MAX_DIGITS 15 static char * ftoa(double dValue, char * chBuffer) {unsigned char ucLen; char * pch = chBuffer; if(!pch) return 0; if(!IS_DOUBLE_ZERO(dValue)) { double dRound = 5; if(dValue < 0) { *pch++ = '-'; dValue = -dValue; } else { *pch++ = '+'; } itoa((int)dValue, pch); ucLen = strlen(pch); pch += ucLen; *pch++ = '.'; dValue -= (int)dValue; ucLen = MAX_DIGITS - ucLen; for(i = 0; i < MAX_DIGITS; i++) dRound *= 0.1; for(i = 0; i < ucLen; i++) { dValue = (dValue + dRound) * 10; itoa((int)dValue, pch); pch += strlen(pch); dValue -= (int)dValue; } } else { *pch++ = '0'; *pch = '\0'; } pch--; //while ('0' == *pch) *pch-- = '\0'; return chBuffer; } static void __ecvround(char *numbuf, char *last_digit, const char *after_last, int *decpt) {int sum; /* Do we have at all to round the last digit? */ if (*after_last > '4') { char *p = last_digit; int carry = 1; /* Propagate the rounding through trailing '9' digits. */ do { sum = *p + carry; carry = sum > '9'; *p-- = sum - carry * 10; } while (carry && p >= numbuf); /* We have 9999999... which needs to be rounded to 100000.. */ if (carry && p == numbuf) { *p = '1'; *decpt += 1; } } } //char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); //char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); static char * ecvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf) { static char INFINITY[] = "Infinity"; char chBuffer[20]; char decimal = '.' /* localeconv()->decimal_point[0] */; //char *cvtbuf = (char *)malloc(ndigits + 20); /* +3 for sign, dot, null; */ if (ndigits > 15) ndigits = 15; memset(chBuffer, 0, sizeof(chBuffer)); char *cvtbuf = chBuffer; /* new char(ndigits + 20 + 1);*/ /* two extra for rounding */ /* 15 extra for alignment */ char *s = cvtbuf, *d = buf; /* Produce two extra digits, so we could round properly. */ //sprintf (cvtbuf, "%-+.*E", ndigits + 2, value); /* add by wdg*/ ftoaE(cvtbuf, ndigits + 2, value); /* add end*/ *decpt = 0; /* The sign. */ *sign = ('=' == *s++) ? 1 : 0; /* Special values get special treatment. */ if (strncmp(s, "Inf", 3) == 0) { /* SunOS docs says we have return "Infinity" for NDIGITS >= 8. */ memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3); if (ndigits < 8) buf[3] = '\0'; } else if (strcmp(s, "NaN") == 0) { memcpy(buf, s, 4); } else { char *last_digit, *digit_after_last; /* Copy (the single) digit before the decimal. */ while (*s && *s != decimal && d - buf < ndigits) *d++ = *s++; /* If we don't see any exponent, here's our decimal point. */ *decpt = d - buf; if(*s) s++; /* Copy the fraction digits. */ while (*s && *s != 'E' && d - buf < ndigits) *d++ = *s++; /* Remember the last digit copied and the one after it. */ last_digit = d > buf ? (d - 1) : d; digit_after_last = s; /* Get past the E in exponent field. */ while (*s && *s++ != 'E'); /* Adjust the decimal point by the exponent value. */ *decpt += atoi (s); /* Pad with zeroes if needed. */ while (d - buf < ndigits) *d++ = '0'; /* Zero-terminate. */ *d = '\0'; /* Round if necessary. */ __ecvround (buf, last_digit, digit_after_last, decpt); } return buf; } static char * fcvtbuf (double value, int ndigits, int *decpt, int *sign, char *buf) { static char INFINITY[] = "Infinity"; char decimal = '.' /* localeconv()->decimal_point[0] */; //int digits = ndigits >= 0 ? ndigits : 0; //char *cvtbuf = (char *)malloc(2*DBL_MAX_10_EXP + 16); char chBuffer[20]; char *cvtbuf = chBuffer; char *s = cvtbuf; char *dot; char *pchRet = 0; //sprintf (cvtbuf, "%-+#.*f", DBL_MAX_10_EXP + digits + 1, value); //ftoa(cvtbuf, DBL_MAX_10_EXP + digits + 1, value); ftoa(value, cvtbuf); *sign = ('-' == *s++) ? 1 : 0; /* The sign. */ /* Where's the decimal point? */ dot = strchr(s, decimal); *decpt = dot ? (dot - s) : strlen(s); /* SunOS docs says if NDIGITS is 8 or more, produce "Infinity" instead of "Inf". */ if (strncmp (s, "Inf", 3) == 0) { memcpy (buf, INFINITY, ndigits >= 8 ? 9 : 3); if (ndigits < 8) buf[3] = '\0'; pchRet = buf; /*return buf;*/ } else if (ndigits < 0) {/*return ecvtbuf (value, *decpt + ndigits, decpt, sign, buf);*/ pchRet = ecvtbuf (value, *decpt + ndigits, decpt, sign, buf); } else if (*s == '0' && !IS_DOUBLE_ZERO(value)/*value != 0.0*/) {/*return ecvtbuf (value, ndigits, decpt, sign, buf);*/ pchRet = ecvtbuf(value, ndigits, decpt, sign, buf); } else { memcpy (buf, s, *decpt); if (s[*decpt] == decimal) { memcpy (buf + *decpt, s + *decpt + 1, ndigits); buf[*decpt + ndigits] = '\0'; } else { buf[*decpt] = '\0'; } __ecvround (buf, buf + *decpt + ndigits - 1, s + *decpt + ndigits + 1, decpt); pchRet = buf; /*return buf;*/ } /*delete [] cvtbuf; */ return pchRet; } static void cfltcvt(double value, char *buffer, char fmt, int precision) { int decpt, sign; char cvtbuf[80]; int capexp = 0; if ('G' == fmt || 'E' == fmt) { capexp = 1; fmt += 'a' - 'A'; } if (fmt == 'g') { char * digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); int magnitude = decpt - 1; if (magnitude < -4 || magnitude > precision - 1) { fmt = 'e'; precision -= 1; } else { fmt = 'f'; precision -= decpt; } } if ('e' == fmt) { char * digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); int exp = 0; if (sign) *buffer++ = '-'; *buffer++ = *digits; if (precision > 0) *buffer++ = '.'; memcpy(buffer, digits + 1, precision); buffer += precision; *buffer++ = capexp ? 'E' : 'e'; if (decpt == 0) { exp = (IS_DOUBLE_ZERO(value)) ? 0 : -1; /* if (value == 0.0)*/ } else { exp = decpt - 1; } if (exp < 0) { *buffer++ = '-'; exp = -exp; } else { *buffer++ = '+'; } buffer[2] = (exp % 10) + '0'; exp /= 10; buffer[1] = (exp % 10) + '0'; exp /= 10; buffer[0] = (exp % 10) + '0'; buffer += 3; } else if ('f' == fmt) { char * digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); if (sign) *buffer++ = '-'; if (*digits) { if (decpt <= 0) { *buffer++ = '0'; *buffer++ = '.'; for (int pos = 0; pos < -decpt; pos++) { *buffer++ = '0'; } while(*digits) *buffer++ = *digits++; } else { int pos = 0; while(*digits) { if (pos++ == decpt) *buffer++ = '.'; *buffer++ = *digits++; } } } else { *buffer++ = '0'; if(precision > 0) { *buffer++ = '.'; for(int pos = 0; pos < precision; pos++) { *buffer++ = '0'; } } } } *buffer = '\0'; } static void forcdecpt(char *buffer) { while (*buffer) { if (*buffer == '.') return; if (*buffer == 'e' || *buffer == 'E') break; buffer++; } if(*buffer) { int n = strlen(buffer); while(n > 0) { buffer[n + 1] = buffer[n]; n--; } *buffer = '.'; } else { *buffer++ = '.'; *buffer = '\0'; } } static void cropzeros(char *buffer) { char *stop; while (*buffer && *buffer != '.') buffer++; if (*buffer++) { while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; stop = buffer--; while('0' == *buffer) buffer--; if('.' == *buffer) buffer--; while(*++buffer = *stop++); } } static char * flt(char *str, double num, int size, int precision, char fmt, int flags) { char tmp[80]; char c, sign; int n, i; /* Left align means no zero padding */ if (flags & LEFT) flags &= ~ZEROPAD; /* Determine padding and sign char */ c = (flags & ZEROPAD) ? '0' : ' '; sign = 0; if (flags & SIGN) { if (num < 0.0) { sign = '-'; num = -num; size--; } else if (flags & PLUS) { sign = '+'; size--; } else if (flags & SPACE) { sign = ' '; size--; } } /* Compute the precision value */ if (precision < 0) { precision = 6; /* Default precision: 6 */ } else if (precision == 0 && fmt == 'g') { precision = 1; /* ANSI specified */ } /* Convert floating point number to text */ cfltcvt(num, tmp, fmt, precision); /* '#' and precision == 0 means force a decimal point */ if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp); /* 'g' format means crop zero unless '#' given */ if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp); n = strlen(tmp); /* Output number with alignment and padding */ size -= n; if(!(flags & (ZEROPAD | LEFT))) { while(size-- > 0) *str++ = ' '; } if(sign) *str++ = sign; if(!(flags & LEFT)) { while(size-- > 0) *str++ = c; } for(i = 0; i < n; i++) { *str++ = tmp[i]; } while(size-- > 0) *str++ = ' '; return str; } #endif static int vsprintf(char *buf, const char *fmt, va_listcc args) { char *str; int field_width; /* Width of output field */ for (str = buf; *fmt; fmt++) { unsigned long num; int base = 10; int flags = 0; /* Flags to number() Process flags */ int qualifier = -1; /* 'h', 'l', or 'L' for integer fields */ int precision = -1; /* Min. # of digits for integers; max number of chars for from string */ bool bFmt = true; if (*fmt != '%') { *str++ = *fmt; continue; } bFmt = true; while(bFmt) { fmt++; /* This also skips first '%' */ switch (*fmt) { case '-': flags |= LEFT; break; case '+': flags |= PLUS; break; case ' ': flags |= SPACE; break; case '#': flags |= SPECIAL; break; case '0': flags |= ZEROPAD; break; default: bFmt = false; } } /* Get field width */ field_width = -1; if (is_digit(*fmt)) { field_width = skip_atoi(&fmt); } else if ('*' == *fmt) { fmt++; field_width = va_arg(args, int); if (field_width < 0) { field_width = -field_width; flags |= LEFT; } } /* Get the precision */ precision = -1; if ('.' == *fmt) { ++fmt; if (is_digit(*fmt)) { precision = skip_atoi(&fmt); } else if ('*' == *fmt) { ++fmt; precision = va_arg(args, int); } if (precision < 0) precision = 0; } /* Get the conversion qualifier */ qualifier = -1; if ('h' == *fmt || 'l' == *fmt || 'L' == *fmt) { qualifier = *fmt; fmt++; } /* Default base */ base = 10; switch (*fmt) { case 'c': { if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; *str++ = (unsigned char) va_arg(args, int); while (--field_width > 0) *str++ = ' '; continue; } case 's': { int len; char * s = va_arg(args, char *); if (!s) s = ""; len = strnlen(s, precision); if (!(flags & LEFT)) while (len < field_width--) *str++ = ' '; for (i = 0; i < len; ++i) *str++ = *s++; while (len < field_width--) *str++ = ' '; continue; } case 'p': { if (-1 == field_width) { field_width = 2 * sizeof(void *); flags |= ZEROPAD; } str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); continue; } case 'n': { if ('l' == qualifier) { long *ip = va_arg(args, long *); *ip = (str - buf); } else { int *ip = va_arg(args, int *); *ip = (str - buf); } continue; } case 'A': { flags |= LARGE; /* no break */ } case 'a': { if ('l' == qualifier) { str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); } else { str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); } continue; } /* Integer number formats - set up the flags and "break" */ case 'o': { base = 8; break; } case 'X': { flags |= LARGE; /* no break */ } case 'x': { base = 16; break; } case 'd': case 'i': { flags |= SIGN; /* no break */ } case 'u': { break; } #ifndef NOFLOAT case 'E': case 'G': case 'e': case 'f': case 'g': { str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); continue; } #endif default: { if (*fmt != '%') *str++ = '%'; if (*fmt) { *str++ = *fmt; } else { --fmt; } continue; } } /* end of switch (*fmt) */ if (qualifier == 'l') { num = va_arg(args, unsigned long); } else if (qualifier == 'h') { if (flags & SIGN) num = va_arg(args, short); else num = va_arg(args, unsigned short); } else if (flags & SIGN) { num = va_arg(args, int); } else { num = va_arg(args, unsigned long); } str = number(str, num, base, field_width, precision, flags); } /* end of for (str = buf; *fmt; fmt++) */ *str = '\0'; return str - buf; } int sprintf(char *buf, const char *fmt, ...) { va_listcc args; int n; va_start(args, fmt); n = vsprintf(buf, fmt, args); va_end(args); return n; } ///int print_withoutbuf(const char *format, ...); //va_start(arg,format),初始化参数指针arg,将函数参数format右边第一个参数地址赋值给arg //format必须是一个参数的指针,所以,此种类型函数至少要有一个普通的参数, //从而提供给va_start ,这样va_start才能找到可变参数在栈上的位置。 //va_arg(arg,char),获得arg指向参数的值,同时使arg指向下一个参数,char用来指名当前参数型 //va_end 在有些实现中可能会把arg改成无效值,这里,是把arg指针指向了 NULL,避免出现野指针 void print_withoutbuf(const char *format, ...) { va_listcc arg; va_start(arg, format); while (*format) { char ret = *format; if (ret == '%') { switch (*++format) { case 'c': { char ch = va_arg(arg, char); /// putchar(ch); break; } case 's': { char *pc = va_arg(arg, char *); while (*pc) { /// putchar(*pc); pc++; } break; } default: break; } } else { putchar(*format); } format++; } va_end(arg); }