| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | #include <module.h> |
|---|
| 22 | #include <string.h> |
|---|
| 23 | #include <typedefs.h> |
|---|
| 24 | #include <malloc.h> |
|---|
| 25 | #include <types.h> |
|---|
| 26 | |
|---|
| 27 | #define SIGN 1 |
|---|
| 28 | #define ZEROPAD 2 |
|---|
| 29 | #define PLUS 4 |
|---|
| 30 | #define SPACE 8 |
|---|
| 31 | #define LEFT 16 |
|---|
| 32 | #define SPECIAL 32 |
|---|
| 33 | #define SMALL 64 |
|---|
| 34 | |
|---|
| 35 | #define is_digit(c) ((c) >= '0' && (c) <= '9') |
|---|
| 36 | |
|---|
| 37 | #define do_div(n,base) ({ \ |
|---|
| 38 | unsigned long __upper, __low, __high, __mod, __base; \ |
|---|
| 39 | __base = (base); \ |
|---|
| 40 | asm("":"=a" (__low), "=d" (__high):"A" (n)); \ |
|---|
| 41 | __upper = __high; \ |
|---|
| 42 | if (__high) { \ |
|---|
| 43 | __upper = __high % (__base); \ |
|---|
| 44 | __high = __high / (__base); \ |
|---|
| 45 | } \ |
|---|
| 46 | asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \ |
|---|
| 47 | asm("":"=A" (n):"a" (__low),"d" (__high)); \ |
|---|
| 48 | __mod; \ |
|---|
| 49 | }) |
|---|
| 50 | |
|---|
| 51 | int skip_atoi(const char** s) |
|---|
| 52 | { |
|---|
| 53 | int i=0; |
|---|
| 54 | while (is_digit(**s)) |
|---|
| 55 | i=i*10+*((*s)++)-'0'; |
|---|
| 56 | return i; |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | char* number(char* str, char* end, unsigned long long num,int base,int size,int precision,int type) |
|---|
| 60 | { |
|---|
| 61 | char c,sign,tmp[36]; |
|---|
| 62 | const char* digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
|---|
| 63 | int i=0; |
|---|
| 64 | |
|---|
| 65 | if (type & SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; |
|---|
| 66 | if (type & LEFT) type &= ~ZEROPAD; |
|---|
| 67 | |
|---|
| 68 | if (base < 2 || base > 36) |
|---|
| 69 | return NULL; |
|---|
| 70 | |
|---|
| 71 | c=(type & ZEROPAD) ? '0' : ' '; |
|---|
| 72 | |
|---|
| 73 | if (type & SIGN && (signed long long)num < 0) |
|---|
| 74 | { |
|---|
| 75 | sign='-'; |
|---|
| 76 | num= -(signed long long)num; |
|---|
| 77 | }else |
|---|
| 78 | sign=(type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0); |
|---|
| 79 | |
|---|
| 80 | if (sign) |
|---|
| 81 | size--; |
|---|
| 82 | |
|---|
| 83 | if (type & SPECIAL) |
|---|
| 84 | { |
|---|
| 85 | if (base == 16) size-=2; |
|---|
| 86 | else if (base == 8) size--; |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | if (num == 0) |
|---|
| 90 | tmp[i++]='0'; |
|---|
| 91 | else while (num != 0) |
|---|
| 92 | { |
|---|
| 93 | tmp[i++]=digits[do_div(num,base)]; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | if (i>precision) |
|---|
| 97 | precision=i; |
|---|
| 98 | |
|---|
| 99 | size-=precision; |
|---|
| 100 | |
|---|
| 101 | if (!(type & (ZEROPAD+LEFT))) |
|---|
| 102 | while (size-- > 0) |
|---|
| 103 | { |
|---|
| 104 | if (str < end) |
|---|
| 105 | *str = ' '; |
|---|
| 106 | str++; |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | if (sign) |
|---|
| 110 | { |
|---|
| 111 | if (str < end) |
|---|
| 112 | *str = sign; |
|---|
| 113 | |
|---|
| 114 | str++; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | if (type & SPECIAL && str < end) |
|---|
| 118 | { |
|---|
| 119 | if (base == 8) |
|---|
| 120 | { |
|---|
| 121 | if (str < end) |
|---|
| 122 | *str = '0'; |
|---|
| 123 | str++; |
|---|
| 124 | }else if (base == 16) |
|---|
| 125 | { |
|---|
| 126 | if (str < end) |
|---|
| 127 | *str='0'; |
|---|
| 128 | str++; |
|---|
| 129 | |
|---|
| 130 | if (str < end) |
|---|
| 131 | *str = digits[33]; |
|---|
| 132 | |
|---|
| 133 | str++; |
|---|
| 134 | } |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | if (!(type & LEFT)) |
|---|
| 138 | while (size-- > 0) |
|---|
| 139 | { |
|---|
| 140 | if (str < end) |
|---|
| 141 | *str = c; |
|---|
| 142 | str++; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | while (i < precision--) |
|---|
| 146 | { |
|---|
| 147 | if (str < end) |
|---|
| 148 | *str='0'; |
|---|
| 149 | |
|---|
| 150 | str++; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | while (i-- > 0) |
|---|
| 154 | { |
|---|
| 155 | if (str < end) |
|---|
| 156 | *str = tmp[i]; |
|---|
| 157 | |
|---|
| 158 | str++; |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | while (size-- > 0) |
|---|
| 162 | { |
|---|
| 163 | if (str < end) |
|---|
| 164 | *str = ' '; |
|---|
| 165 | |
|---|
| 166 | str++; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | return str; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | int vsnprintf(char* buf, int size, const char* fmt, VaList args) |
|---|
| 173 | { |
|---|
| 174 | char* str=buf; |
|---|
| 175 | char* end; |
|---|
| 176 | int fieldWidth,precision,qualifier,flags; |
|---|
| 177 | |
|---|
| 178 | end = buf+size; |
|---|
| 179 | |
|---|
| 180 | if (end < buf) |
|---|
| 181 | { |
|---|
| 182 | end = ((void*)-1); |
|---|
| 183 | size = end - buf; |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | for (; *fmt; fmt++) |
|---|
| 187 | { |
|---|
| 188 | fieldWidth=precision=qualifier=-1; |
|---|
| 189 | flags=0; |
|---|
| 190 | |
|---|
| 191 | if (LIKELY(*fmt != '%')) |
|---|
| 192 | { |
|---|
| 193 | if (str < end) |
|---|
| 194 | *str = *fmt; |
|---|
| 195 | |
|---|
| 196 | str++; |
|---|
| 197 | continue; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | repeat: |
|---|
| 201 | ++fmt; |
|---|
| 202 | switch (*fmt) |
|---|
| 203 | { |
|---|
| 204 | case '-': flags |= LEFT; goto repeat; |
|---|
| 205 | case '+': flags |= PLUS; goto repeat; |
|---|
| 206 | case ' ': flags |= SPACE; goto repeat; |
|---|
| 207 | case '#': flags |= SPECIAL; goto repeat; |
|---|
| 208 | case '0': flags |= ZEROPAD; goto repeat; |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | if (is_digit(*fmt)) |
|---|
| 213 | fieldWidth=skip_atoi(&fmt); |
|---|
| 214 | else if (*fmt == '*') |
|---|
| 215 | { |
|---|
| 216 | fieldWidth=VaArg(args, int); |
|---|
| 217 | if (fieldWidth < 0) |
|---|
| 218 | { |
|---|
| 219 | fieldWidth=-fieldWidth; |
|---|
| 220 | flags |= LEFT; |
|---|
| 221 | } |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | if (*fmt == '.') |
|---|
| 225 | { |
|---|
| 226 | ++fmt; |
|---|
| 227 | if (is_digit(*fmt)) |
|---|
| 228 | precision=skip_atoi(&fmt); |
|---|
| 229 | else if (*fmt == '*') |
|---|
| 230 | { |
|---|
| 231 | precision=VaArg(args,int); |
|---|
| 232 | } |
|---|
| 233 | if (precision < 0) |
|---|
| 234 | precision=0; |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | qualifier=-1; |
|---|
| 238 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') |
|---|
| 239 | { |
|---|
| 240 | qualifier=*fmt; |
|---|
| 241 | ++fmt; |
|---|
| 242 | } |
|---|
| 243 | |
|---|
| 244 | unsigned long long num=0; |
|---|
| 245 | |
|---|
| 246 | switch (*fmt) |
|---|
| 247 | { |
|---|
| 248 | case 'c': |
|---|
| 249 | if (!(flags & LEFT)) |
|---|
| 250 | while (--fieldWidth > 0) |
|---|
| 251 | { |
|---|
| 252 | if (str < end) |
|---|
| 253 | *str=' '; |
|---|
| 254 | |
|---|
| 255 | ++str; |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | if (str < end) |
|---|
| 259 | *str=(unsigned char)VaArg(args,int); |
|---|
| 260 | |
|---|
| 261 | str++; |
|---|
| 262 | |
|---|
| 263 | while (--fieldWidth > 0) |
|---|
| 264 | { |
|---|
| 265 | if (str < end) |
|---|
| 266 | *str=' '; |
|---|
| 267 | |
|---|
| 268 | str++; |
|---|
| 269 | } |
|---|
| 270 | break; |
|---|
| 271 | |
|---|
| 272 | case 's': |
|---|
| 273 | { |
|---|
| 274 | char* s=VaArg(args,char*); |
|---|
| 275 | if (!s) |
|---|
| 276 | s="<NULL>"; |
|---|
| 277 | int len=strlen(s); |
|---|
| 278 | if (precision < 0) |
|---|
| 279 | precision=len; |
|---|
| 280 | else if (len > precision) |
|---|
| 281 | len=precision; |
|---|
| 282 | |
|---|
| 283 | if (!(flags & LEFT)) |
|---|
| 284 | while (len < fieldWidth--) |
|---|
| 285 | { |
|---|
| 286 | if (str < end) |
|---|
| 287 | *str=' '; |
|---|
| 288 | |
|---|
| 289 | str++; |
|---|
| 290 | } |
|---|
| 291 | int i; |
|---|
| 292 | for (i=0; i<len; i++) |
|---|
| 293 | { |
|---|
| 294 | if (str < end) |
|---|
| 295 | *str=*s; |
|---|
| 296 | |
|---|
| 297 | str++; |
|---|
| 298 | s++; |
|---|
| 299 | } |
|---|
| 300 | |
|---|
| 301 | while (len < fieldWidth--) |
|---|
| 302 | { |
|---|
| 303 | if (str < end) |
|---|
| 304 | *str++=' '; |
|---|
| 305 | } |
|---|
| 306 | break; |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | case 'o': |
|---|
| 310 | str=number(str, end, VaArg(args,unsigned long),8,fieldWidth, |
|---|
| 311 | precision,flags); |
|---|
| 312 | break; |
|---|
| 313 | |
|---|
| 314 | case 'p': |
|---|
| 315 | if (fieldWidth == -1) |
|---|
| 316 | { |
|---|
| 317 | fieldWidth=8; |
|---|
| 318 | flags |= ZEROPAD; |
|---|
| 319 | } |
|---|
| 320 | str=number(str, end, (unsigned long)VaArg(args,void*),16,fieldWidth, |
|---|
| 321 | precision,flags); |
|---|
| 322 | break; |
|---|
| 323 | |
|---|
| 324 | case 'x': |
|---|
| 325 | flags |= SMALL; |
|---|
| 326 | case 'X': |
|---|
| 327 | str=number(str, end, VaArg(args,unsigned long),16,fieldWidth, |
|---|
| 328 | precision,flags); |
|---|
| 329 | break; |
|---|
| 330 | case 'd': |
|---|
| 331 | case 'i': |
|---|
| 332 | flags |= SIGN; |
|---|
| 333 | case 'u': |
|---|
| 334 | num = VaArg(args, unsigned int); |
|---|
| 335 | if (flags & SIGN) |
|---|
| 336 | num = (signed int)num; |
|---|
| 337 | str=number(str, end, num, 10, fieldWidth, precision,flags); |
|---|
| 338 | break; |
|---|
| 339 | default: |
|---|
| 340 | if (str < end) |
|---|
| 341 | *str = '%'; |
|---|
| 342 | |
|---|
| 343 | if (*fmt) |
|---|
| 344 | { |
|---|
| 345 | if (str < end) |
|---|
| 346 | *str = *fmt; |
|---|
| 347 | ++str; |
|---|
| 348 | }else |
|---|
| 349 | --fmt; |
|---|
| 350 | break; |
|---|
| 351 | } |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | if (size > 0) |
|---|
| 355 | { |
|---|
| 356 | if (str < end) |
|---|
| 357 | *str = '\0'; |
|---|
| 358 | else |
|---|
| 359 | end[-1] = '\0'; |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | return (str-buf); |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | SYMBOL_EXPORT(vsnprintf); |
|---|
| 366 | |
|---|
| 367 | int vsprintf(char* buf,const char* fmt, VaList args) |
|---|
| 368 | { |
|---|
| 369 | return vsnprintf(buf, INT_MAX, fmt, args); |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | SYMBOL_EXPORT(vsprintf); |
|---|
| 373 | |
|---|
| 374 | int snprintf(char* buf, unsigned int size, const char* fmt, ...) |
|---|
| 375 | { |
|---|
| 376 | int ret; |
|---|
| 377 | VaList args; |
|---|
| 378 | |
|---|
| 379 | VaStart(args, fmt); |
|---|
| 380 | ret = vsnprintf(buf, size, fmt, args); |
|---|
| 381 | VaEnd(args); |
|---|
| 382 | |
|---|
| 383 | return ret; |
|---|
| 384 | } |
|---|
| 385 | |
|---|
| 386 | SYMBOL_EXPORT(snprintf); |
|---|
| 387 | |
|---|
| 388 | char* vasprintf(const char* fmt, VaList args) |
|---|
| 389 | { |
|---|
| 390 | int length; |
|---|
| 391 | char* ret; |
|---|
| 392 | VaList temp; |
|---|
| 393 | |
|---|
| 394 | VaCopy(temp, args); |
|---|
| 395 | |
|---|
| 396 | length = vsnprintf(NULL, 0, fmt, temp); |
|---|
| 397 | |
|---|
| 398 | VaEnd(temp); |
|---|
| 399 | |
|---|
| 400 | ret = (char*)MemAlloc(length + 1); |
|---|
| 401 | |
|---|
| 402 | if (!ret) |
|---|
| 403 | return NULL; |
|---|
| 404 | |
|---|
| 405 | vsnprintf(ret, length+1, fmt, args); |
|---|
| 406 | |
|---|
| 407 | return ret; |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | SYMBOL_EXPORT(vasprintf); |
|---|
| 411 | |
|---|
| 412 | |
|---|
| 413 | int sprintf(char* str, const char* fmt, ...) |
|---|
| 414 | { |
|---|
| 415 | KePrint("sprintf"); |
|---|
| 416 | return 0; |
|---|
| 417 | } |
|---|
| 418 | |
|---|
| 419 | SYMBOL_EXPORT(sprintf); |
|---|