| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | #include <init.h> |
|---|
| 25 | #include <module.h> |
|---|
| 26 | #include <string.h> |
|---|
| 27 | #include <typedefs.h> |
|---|
| 28 | |
|---|
| 29 | #define SIGN 1 |
|---|
| 30 | #define ZEROPAD 2 |
|---|
| 31 | #define PLUS 4 |
|---|
| 32 | #define SPACE 8 |
|---|
| 33 | #define LEFT 16 |
|---|
| 34 | #define SPECIAL 32 |
|---|
| 35 | #define SMALL 64 |
|---|
| 36 | |
|---|
| 37 | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
|---|
| 38 | #define do_div(n,base) ({ \ |
|---|
| 39 | int __res; \ |
|---|
| 40 | __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ |
|---|
| 41 | __res; }) |
|---|
| 42 | |
|---|
| 43 | int skip_atoi(const char** s) |
|---|
| 44 | { |
|---|
| 45 | int i=0; |
|---|
| 46 | while (is_digit(**s)) |
|---|
| 47 | i=i*10+*((*s)++)-'0'; |
|---|
| 48 | return i; |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | char* number(char* str,int num,int base,int size,int precision,int type) |
|---|
| 52 | { |
|---|
| 53 | char c,sign,tmp[36]; |
|---|
| 54 | const char* digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
|---|
| 55 | int i=0; |
|---|
| 56 | |
|---|
| 57 | if (type & SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; |
|---|
| 58 | if (type & LEFT) type &= ~ZEROPAD; |
|---|
| 59 | if (base < 2 || base > 36) |
|---|
| 60 | return NULL; |
|---|
| 61 | c=(type & ZEROPAD) ? '0' : ' '; |
|---|
| 62 | if (type & SIGN && num < 0) |
|---|
| 63 | { |
|---|
| 64 | sign='-'; |
|---|
| 65 | num=-num; |
|---|
| 66 | }else |
|---|
| 67 | sign=(type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0); |
|---|
| 68 | if (sign) size--; |
|---|
| 69 | if (type & SPECIAL) |
|---|
| 70 | { |
|---|
| 71 | if (base == 16) size-=2; |
|---|
| 72 | else if (base == 8) size--; |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | if (num == 0) |
|---|
| 76 | tmp[i++]='0'; |
|---|
| 77 | else while (num != 0) |
|---|
| 78 | { |
|---|
| 79 | tmp[i++]=digits[do_div(num,base)]; |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | if (i>precision) precision=i; |
|---|
| 83 | size-=precision; |
|---|
| 84 | if (!(type & (ZEROPAD+LEFT))) |
|---|
| 85 | while (size-- > 0) |
|---|
| 86 | *str++=' '; |
|---|
| 87 | |
|---|
| 88 | if (sign) |
|---|
| 89 | *str++=sign; |
|---|
| 90 | |
|---|
| 91 | if (type & SPECIAL) |
|---|
| 92 | { |
|---|
| 93 | if (base == 8) |
|---|
| 94 | *str++='0'; |
|---|
| 95 | else if (base == 16) |
|---|
| 96 | { |
|---|
| 97 | *str++='0'; |
|---|
| 98 | *str++=digits[33]; |
|---|
| 99 | } |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | if (!(type & LEFT)) |
|---|
| 103 | while (size-- > 0) |
|---|
| 104 | *str++=c; |
|---|
| 105 | |
|---|
| 106 | while (i < precision--) |
|---|
| 107 | *str++='0'; |
|---|
| 108 | while (i-- > 0) |
|---|
| 109 | *str++=tmp[i]; |
|---|
| 110 | while (size-- > 0) |
|---|
| 111 | *str++=' '; |
|---|
| 112 | return str; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | int vsprintf(char* buf,const char* fmt,va_list args) |
|---|
| 116 | { |
|---|
| 117 | char* str=buf; |
|---|
| 118 | int fieldWidth,precision,qualifier,flags; |
|---|
| 119 | |
|---|
| 120 | for (; *fmt; fmt++) |
|---|
| 121 | { |
|---|
| 122 | fieldWidth=precision=qualifier=-1; |
|---|
| 123 | flags=0; |
|---|
| 124 | |
|---|
| 125 | if (LIKELY(*fmt != '%')) |
|---|
| 126 | { |
|---|
| 127 | *str++=*fmt; |
|---|
| 128 | continue; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | repeat: |
|---|
| 132 | ++fmt; |
|---|
| 133 | switch (*fmt) |
|---|
| 134 | { |
|---|
| 135 | case '-': flags |= LEFT; goto repeat; |
|---|
| 136 | case '+': flags |= PLUS; goto repeat; |
|---|
| 137 | case ' ': flags |= SPACE; goto repeat; |
|---|
| 138 | case '#': flags |= SPECIAL; goto repeat; |
|---|
| 139 | case '0': flags |= ZEROPAD; goto repeat; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | if (is_digit(*fmt)) |
|---|
| 144 | fieldWidth=skip_atoi(&fmt); |
|---|
| 145 | else if (*fmt == '*') |
|---|
| 146 | { |
|---|
| 147 | fieldWidth=va_arg(args,int); |
|---|
| 148 | if (fieldWidth < 0) |
|---|
| 149 | { |
|---|
| 150 | fieldWidth=-fieldWidth; |
|---|
| 151 | flags |= LEFT; |
|---|
| 152 | } |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | if (*fmt == '.') |
|---|
| 156 | { |
|---|
| 157 | ++fmt; |
|---|
| 158 | if (is_digit(*fmt)) |
|---|
| 159 | precision=skip_atoi(&fmt); |
|---|
| 160 | else if (*fmt == '*') |
|---|
| 161 | { |
|---|
| 162 | precision=va_arg(args,int); |
|---|
| 163 | } |
|---|
| 164 | if (precision < 0) |
|---|
| 165 | precision=0; |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | qualifier=-1; |
|---|
| 169 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') |
|---|
| 170 | { |
|---|
| 171 | qualifier=*fmt; |
|---|
| 172 | ++fmt; |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | switch (*fmt) |
|---|
| 176 | { |
|---|
| 177 | case 'c': |
|---|
| 178 | if (!(flags & LEFT)) |
|---|
| 179 | while (--fieldWidth > 0) |
|---|
| 180 | *str++=' '; |
|---|
| 181 | *str++=(unsigned char)va_arg(args,int); |
|---|
| 182 | while (--fieldWidth > 0) |
|---|
| 183 | *str++=' '; |
|---|
| 184 | break; |
|---|
| 185 | |
|---|
| 186 | case 's': |
|---|
| 187 | { |
|---|
| 188 | char* s=va_arg(args,char*); |
|---|
| 189 | if (!s) |
|---|
| 190 | s="<NULL>"; |
|---|
| 191 | int len=strlen(s); |
|---|
| 192 | if (precision < 0) |
|---|
| 193 | precision=len; |
|---|
| 194 | else if (len > precision) |
|---|
| 195 | len=precision; |
|---|
| 196 | |
|---|
| 197 | if (!(flags & LEFT)) |
|---|
| 198 | while (len < fieldWidth--) |
|---|
| 199 | *str++=' '; |
|---|
| 200 | int i; |
|---|
| 201 | for (i=0; i<len; i++) |
|---|
| 202 | *str++=*s++; |
|---|
| 203 | |
|---|
| 204 | while (len < fieldWidth--) |
|---|
| 205 | *str++=' '; |
|---|
| 206 | break; |
|---|
| 207 | } |
|---|
| 208 | |
|---|
| 209 | case 'o': |
|---|
| 210 | str=number(str,va_arg(args,unsigned long),8,fieldWidth, |
|---|
| 211 | precision,flags); |
|---|
| 212 | break; |
|---|
| 213 | |
|---|
| 214 | case 'p': |
|---|
| 215 | if (fieldWidth == -1) |
|---|
| 216 | { |
|---|
| 217 | fieldWidth=8; |
|---|
| 218 | flags |= ZEROPAD; |
|---|
| 219 | } |
|---|
| 220 | str=number(str,(unsigned long)va_arg(args,void*),16,fieldWidth, |
|---|
| 221 | precision,flags); |
|---|
| 222 | break; |
|---|
| 223 | |
|---|
| 224 | case 'x': |
|---|
| 225 | flags |= SMALL; |
|---|
| 226 | case 'X': |
|---|
| 227 | str=number(str,va_arg(args,unsigned long),16,fieldWidth, |
|---|
| 228 | precision,flags); |
|---|
| 229 | break; |
|---|
| 230 | case 'd': |
|---|
| 231 | case 'i': |
|---|
| 232 | flags |= SIGN; |
|---|
| 233 | case 'u': |
|---|
| 234 | str=number(str,va_arg(args,unsigned long),10,fieldWidth, |
|---|
| 235 | precision,flags); |
|---|
| 236 | break; |
|---|
| 237 | default: |
|---|
| 238 | if (*fmt != '%') |
|---|
| 239 | *str++ = '%'; |
|---|
| 240 | if (*fmt) |
|---|
| 241 | *str++ = *fmt; |
|---|
| 242 | else |
|---|
| 243 | --fmt; |
|---|
| 244 | break; |
|---|
| 245 | } |
|---|
| 246 | } |
|---|
| 247 | *str='\0'; |
|---|
| 248 | return (str-buf); |
|---|
| 249 | } |
|---|
| 250 | |
|---|
| 251 | SYMBOL_EXPORT(vsprintf); |
|---|
| 252 | |
|---|
| 253 | int sprintf(char* buf,const char* fmt,...) |
|---|
| 254 | { |
|---|
| 255 | int i; |
|---|
| 256 | va_list args; |
|---|
| 257 | |
|---|
| 258 | va_start(args,fmt); |
|---|
| 259 | i=vsprintf(buf,fmt,args); |
|---|
| 260 | va_end(args); |
|---|
| 261 | return i; |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | SYMBOL_EXPORT(sprintf); |
|---|