Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15529364
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2008-05-30 14:30:53

#include "sprintf.h"
#include "stdio.h"
int main(int argc, char *argv[])
{
    char tmp_buf[500];
    sprintf2(tmp_buf, "%s : gliethttp %x, %d, %s, %c, %s, %s\n", __func__, 0x89, 100, "abc", 'D', __DATE__, __TIME__);
    printf(tmp_buf);
    return 0;
}


//摘自linux2.6.24 gliethttp_20080530

#include "sprintf.h"

typedef unsigned long size_t;
typedef int ptrdiff_t;

#define noinline __attribute__((noinline))
#define unlikely(x) ( (!!(x)) == 1 )
#define WARN_ON(x)
#define do_div(a,b) (a / b)
#define INT_MAX        ((int)(~0U>>1))
#define PAGE_SIZE (1024*8)
#ifndef NULL
#define NULL 0
#endif


#define _U    0x01    /* upper */
#define _L    0x02    /* lower */
#define _D    0x04    /* digit */
#define _C    0x08    /* cntrl */
#define _P    0x10    /* punct */
#define _S    0x20    /* white space (space/lf/tab) */
#define _X    0x40    /* hex digit */
#define _SP    0x80    /* hard space (0x20) */

extern unsigned char _ctype[];

#define __ismask(x) (_ctype[(int)(unsigned char)(x)])

#define isalnum(c)    ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c)    ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c)    ((__ismask(c)&(_C)) != 0)
#define isdigit(c)    ((__ismask(c)&(_D)) != 0)
#define isgraph(c)    ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c)    ((__ismask(c)&(_L)) != 0)
#define isprint(c)    ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c)    ((__ismask(c)&(_P)) != 0)
#define isspace(c)    ((__ismask(c)&(_S)) != 0)
#define isupper(c)    ((__ismask(c)&(_U)) != 0)
#define isxdigit(c)    ((__ismask(c)&(_D|_X)) != 0)

#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)

#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' */
static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type);
static noinline char* put_dec(char *buf, unsigned long long num);
static int skip_atoi(const char **s);
size_t strnlen(const char *s, size_t count);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);

int sprintf2(char * buf, const char *fmt, ...)
{
    va_list args;
    int i;

    va_start(args, fmt);
    i=vsnprintf(buf, INT_MAX, fmt, args);
    va_end(args);
    return i;
}

int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
    int len;
    unsigned long long num;
    int i, base;
    char *str, *end, c;
    const char *s;

    int flags;        /* flags to number() */

    int field_width;    /* width of output field */
    int precision;        /* min. # of digits for integers; max
                 number of chars for from string */

    int qualifier;        /* 'h', 'l', or 'L' for integer fields */
                /* 'z' support added 23/7/1999 S.H. */
                /* 'z' changed to 'Z' --davidm 1/25/99 */
                /* 't' added for ptrdiff_t */

    /* Reject out-of-range values early. Large positive sizes are
     used for unknown buffer sizes. */

    if (unlikely((int) size < 0)) {
        /* There can be only one.. */
        static char warn = 1;
        WARN_ON(warn);
        warn = 0;
        return 0;
    }

    str = buf;
    end = buf + size;

    /* Make sure end is always >= buf */
    if (end < buf) {
        end = ((void *)-1);
        size = end - buf;
    }

    for (; *fmt ; ++fmt) {
        if (*fmt != '%') {
            if (str < end)
                *str = *fmt;
            ++str;
            continue;
        }

        /* process flags */
        flags = 0;
        repeat:
            ++fmt;        /* this also skips first '%' */
            switch (*fmt) {
                case '-': flags |= LEFT; goto repeat;
                case '+': flags |= PLUS; goto repeat;
                case ' ': flags |= SPACE; goto repeat;
                case '#': flags |= SPECIAL; goto repeat;
                case '0': flags |= ZEROPAD; goto repeat;
            }

        /* get field width */
        field_width = -1;
        if (isdigit(*fmt))
            field_width = skip_atoi(&fmt);
        else if (*fmt == '*') {
            ++fmt;
            /* it's the next argument */
            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 (isdigit(*fmt))
                precision = skip_atoi(&fmt);
            else if (*fmt == '*') {
                ++fmt;
                /* it's the next argument */
                precision = va_arg(args, int);
            }
            if (precision < 0)
                precision = 0;
        }

        /* get the conversion qualifier */
        qualifier = -1;
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
         *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
            qualifier = *fmt;
            ++fmt;
            if (qualifier == 'l' && *fmt == 'l') {
                qualifier = 'L';
                ++fmt;
            }
        }

        /* default base */
        base = 10;

        switch (*fmt) {
            case 'c':
                if (!(flags & LEFT)) {
                    while (--field_width > 0) {
                        if (str < end)
                            *str = ' ';
                        ++str;
                    }
                }
                c = (unsigned char) va_arg(args, int);
                if (str < end)
                    *str = c;
                ++str;
                while (--field_width > 0) {
                    if (str < end)
                        *str = ' ';
                    ++str;
                }
                continue;

            case 's':
                s = va_arg(args, char *);
                if ((unsigned long)s < PAGE_SIZE)
                    s = "";

                len = strnlen(s, precision);

                if (!(flags & LEFT)) {
                    while (len < field_width--) {
                        if (str < end)
                            *str = ' ';
                        ++str;
                    }
                }
                for (i = 0; i < len; ++i) {
                    if (str < end)
                        *str = *s;
                    ++str; ++s;
                }
                while (len < field_width--) {
                    if (str < end)
                        *str = ' ';
                    ++str;
                }
                continue;

            case 'p':
                if (field_width == -1) {
                    field_width = 2*sizeof(void *);
                    flags |= ZEROPAD;
                }
                str = number(str, end,
                        (unsigned long) va_arg(args, void *),
                        16, field_width, precision, flags);
                continue;


            case 'n':
                /* FIXME:
                * What does C99 say about the overflow case here? */

                if (qualifier == 'l') {
                    long * ip = va_arg(args, long *);
                    *ip = (str - buf);
                } else if (qualifier == 'Z' || qualifier == 'z') {
                    size_t * ip = va_arg(args, size_t *);
                    *ip = (str - buf);
                } else {
                    int * ip = va_arg(args, int *);
                    *ip = (str - buf);
                }
                continue;

            case '%':
                if (str < end)
                    *str = '%';
                ++str;
                continue;

                /* integer number formats - set up the flags and "break" */
            case 'o':
                base = 8;
                break;

            case 'X':
                flags |= LARGE;
            case 'x':
                base = 16;
                break;

            case 'd':
            case 'i':
                flags |= SIGN;
            case 'u':
                break;

            default:
                if (str < end)
                    *str = '%';
                ++str;
                if (*fmt) {
                    if (str < end)
                        *str = *fmt;
                    ++str;
                } else {
                    --fmt;
                }
                continue;
        }
        if (qualifier == 'L')
            num = va_arg(args, long long);
        else if (qualifier == 'l') {
            num = va_arg(args, unsigned long);
            if (flags & SIGN)
                num = (signed long) num;
        } else if (qualifier == 'Z' || qualifier == 'z') {
            num = va_arg(args, size_t);
        } else if (qualifier == 't') {
            num = va_arg(args, ptrdiff_t);
        } else if (qualifier == 'h') {
            num = (unsigned short) va_arg(args, int);
            if (flags & SIGN)
                num = (signed short) num;
        } else {
            num = va_arg(args, unsigned int);
            if (flags & SIGN)
                num = (signed int) num;
        }
        str = number(str, end, num, base,
                field_width, precision, flags);
    }
    if (size > 0) {
        if (str < end)
            *str = '\0';
        else
            end[-1] = '\0';
    }
    /* the trailing null byte doesn't count towards the total */
    return str-buf;
}

static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
{
    char sign,tmp[66];
    const char *digits;
    /* we are called with base 8, 10 or 16, only, thus don't need "g..." */
    static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */
    static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
    int need_pfx = ((type & SPECIAL) && base != 10);
    int i;

    digits = (type & LARGE) ? large_digits : small_digits;
    if (type & LEFT)
        type &= ~ZEROPAD;
    if (base < 2 || base > 36)
        return NULL;
    sign = 0;
    if (type & SIGN) {
        if ((signed long long) num < 0) {
            sign = '-';
            num = - (signed long long) num;
            size--;
        } else if (type & PLUS) {
            sign = '+';
            size--;
        } else if (type & SPACE) {
            sign = ' ';
            size--;
        }
    }
    if (need_pfx) {
        size--;
        if (base == 16)
            size--;
    }

    /* generate full string in tmp[], in reverse order */
    i = 0;
    if (num == 0)
        tmp[i++] = '0';
    /* Generic code, for any base:
    else do {
        tmp[i++] = digits[do_div(num,base)];
    } while (num != 0);
    */

    else if (base != 10) { /* 8 or 16 */
        int mask = base - 1;
        int shift = 3;
        if (base == 16) shift = 4;
        do {
            tmp[i++] = digits[((unsigned char)num) & mask];
            num >>= shift;
        } while (num);
    } else { /* base 10 */
        i = put_dec(tmp, num) - tmp;
    }

    /* printing 100 using %2d gives "100", not "00" */
    if (i > precision)
        precision = i;
    /* leading space padding */
    size -= precision;
    if (!(type & (ZEROPAD+LEFT))) {
        while(--size >= 0) {
            if (buf < end)
                *buf = ' ';
            ++buf;
        }
    }
    /* sign */
    if (sign) {
        if (buf < end)
            *buf = sign;
        ++buf;
    }
    /* "0x" / "0" prefix */
    if (need_pfx) {
        if (buf < end)
            *buf = '0';
        ++buf;
        if (base == 16) {
            if (buf < end)
                *buf = digits[16]; /* for arbitrary base: digits[33]; */
            ++buf;
        }
    }
    /* zero or space padding */
    if (!(type & LEFT)) {
        char c = (type & ZEROPAD) ? '0' : ' ';
        while (--size >= 0) {
            if (buf < end)
                *buf = c;
            ++buf;
        }
    }
    /* hmm even more zero padding? */
    while (i <= --precision) {
        if (buf < end)
            *buf = '0';
        ++buf;
    }
    /* actual digits of result */
    while (--i >= 0) {
        if (buf < end)
            *buf = tmp[i];
        ++buf;
    }
    /* trailing space padding */
    while (--size >= 0) {
        if (buf < end)
            *buf = ' ';
        ++buf;
    }
    return buf;
}

static char* put_dec_trunc(char *buf, unsigned q)
{
    unsigned d3, d2, d1, d0;
    d1 = (q>>4) & 0xf;
    d2 = (q>>8) & 0xf;
    d3 = (q>>12);

    d0 = 6*(d3 + d2 + d1) + (q & 0xf);
    q = (d0 * 0xcd) >> 11;
    d0 = d0 - 10*q;
    *buf++ = d0 + '0'; /* least significant digit */
    d1 = q + 9*d3 + 5*d2 + d1;
    if (d1 != 0) {
        q = (d1 * 0xcd) >> 11;
        d1 = d1 - 10*q;
        *buf++ = d1 + '0'; /* next digit */

        d2 = q + 2*d2;
        if ((d2 != 0) || (d3 != 0)) {
            q = (d2 * 0xd) >> 7;
            d2 = d2 - 10*q;
            *buf++ = d2 + '0'; /* next digit */

            d3 = q + 4*d3;
            if (d3 != 0) {
                q = (d3 * 0xcd) >> 11;
                d3 = d3 - 10*q;
                *buf++ = d3 + '0'; /* next digit */
                if (q != 0)
                    *buf++ = q + '0'; /* most sign. digit */
            }
        }
    }
    return buf;
}
/* Same with if's removed. Always emits five digits */
static char* put_dec_full(char *buf, unsigned q)
{
    /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
    /* but anyway, gcc produces better code with full-sized ints */
    unsigned d3, d2, d1, d0;
    d1 = (q>>4) & 0xf;
    d2 = (q>>8) & 0xf;
    d3 = (q>>12);

    /* Possible ways to approx. divide by 10 */
    /* gcc -O2 replaces multiply with shifts and adds */
    // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)

    // (x * 0x67) >> 10: 1100111

    // (x * 0x34) >> 9: 110100 - same

    // (x * 0x1a) >> 8: 11010 - same

    // (x * 0x0d) >> 7: 1101 - same, shortest code (on i386)


    d0 = 6*(d3 + d2 + d1) + (q & 0xf);
    q = (d0 * 0xcd) >> 11;
    d0 = d0 - 10*q;
    *buf++ = d0 + '0';
    d1 = q + 9*d3 + 5*d2 + d1;
        q = (d1 * 0xcd) >> 11;
        d1 = d1 - 10*q;
        *buf++ = d1 + '0';

        d2 = q + 2*d2;
            q = (d2 * 0xd) >> 7;
            d2 = d2 - 10*q;
            *buf++ = d2 + '0';

            d3 = q + 4*d3;
                q = (d3 * 0xcd) >> 11; /* - shorter code */
                /* q = (d3 * 0x67) >> 10; - would also work */
                d3 = d3 - 10*q;
                *buf++ = d3 + '0';
                    *buf++ = q + '0';
    return buf;
}
/* No inlining helps gcc to use registers better */

#ifndef __gliethttp_sprintf_h
#define __gliethttp_sprintf_h

typedef char * va_list;

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

int sprintf2(char * buf, const char *fmt, ...);

#endif


static noinline char* put_dec(char *buf, unsigned long long num)
{
    while (1) {
        unsigned rem;
        if (num < 100000)
            return put_dec_trunc(buf, num);
        rem = do_div(num, 100000);
        buf = put_dec_full(buf, rem);
    }
}


static int skip_atoi(const char **s)
{
    int i=0;

    while (isdigit(**s))
        i = i*10 + *((*s)++) - '0';
    return i;
}

size_t strnlen(const char *s, size_t count)
{
    const char *sc;

    for (sc = s; count-- && *sc != '\0'; ++sc)
        /* nothing */;
    return sc - s;
}

unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C,            /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,        /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C,            /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C,            /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,            /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P,            /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D,            /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P,            /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,    /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U,            /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U,            /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P,            /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,    /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L,            /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L,            /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C,            /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */


文件:sprintf_va_list.tar.gz
大小:4KB
下载:下载

#ifndef __gliethttp_sprintf_h
#define __gliethttp_sprintf_h

typedef char * va_list;

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

int sprintf2(char * buf, const char *fmt, ...);

#endif

阅读(3406) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

dongliqiang19852010-06-01 08:26:22

呵呵,查资料又跑到哥的空间了!呵呵。