0001
0002
0003
0004
0005 #include <stdarg.h>
0006 #include <stddef.h>
0007
0008 size_t strnlen(const char * s, size_t count)
0009 {
0010 const char *sc;
0011
0012 for (sc = s; count-- && *sc != '\0'; ++sc)
0013 ;
0014 return sc - s;
0015 }
0016
0017 # define do_div(n, base) ({ \
0018 unsigned int __base = (base); \
0019 unsigned int __rem; \
0020 __rem = ((unsigned long long)(n)) % __base; \
0021 (n) = ((unsigned long long)(n)) / __base; \
0022 __rem; \
0023 })
0024
0025
0026 static int skip_atoi(const char **s)
0027 {
0028 int i, c;
0029
0030 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
0031 i = i*10 + c - '0';
0032 return i;
0033 }
0034
0035 #define ZEROPAD 1
0036 #define SIGN 2
0037 #define PLUS 4
0038 #define SPACE 8
0039 #define LEFT 16
0040 #define SPECIAL 32
0041 #define LARGE 64
0042
0043 static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
0044 {
0045 char c,sign,tmp[66];
0046 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
0047 int i;
0048
0049 if (type & LARGE)
0050 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
0051 if (type & LEFT)
0052 type &= ~ZEROPAD;
0053 if (base < 2 || base > 36)
0054 return 0;
0055 c = (type & ZEROPAD) ? '0' : ' ';
0056 sign = 0;
0057 if (type & SIGN) {
0058 if ((signed long long)num < 0) {
0059 sign = '-';
0060 num = - (signed long long)num;
0061 size--;
0062 } else if (type & PLUS) {
0063 sign = '+';
0064 size--;
0065 } else if (type & SPACE) {
0066 sign = ' ';
0067 size--;
0068 }
0069 }
0070 if (type & SPECIAL) {
0071 if (base == 16)
0072 size -= 2;
0073 else if (base == 8)
0074 size--;
0075 }
0076 i = 0;
0077 if (num == 0)
0078 tmp[i++]='0';
0079 else while (num != 0) {
0080 tmp[i++] = digits[do_div(num, base)];
0081 }
0082 if (i > precision)
0083 precision = i;
0084 size -= precision;
0085 if (!(type&(ZEROPAD+LEFT)))
0086 while(size-->0)
0087 *str++ = ' ';
0088 if (sign)
0089 *str++ = sign;
0090 if (type & SPECIAL) {
0091 if (base==8)
0092 *str++ = '0';
0093 else if (base==16) {
0094 *str++ = '0';
0095 *str++ = digits[33];
0096 }
0097 }
0098 if (!(type & LEFT))
0099 while (size-- > 0)
0100 *str++ = c;
0101 while (i < precision--)
0102 *str++ = '0';
0103 while (i-- > 0)
0104 *str++ = tmp[i];
0105 while (size-- > 0)
0106 *str++ = ' ';
0107 return str;
0108 }
0109
0110 int vsprintf(char *buf, const char *fmt, va_list args)
0111 {
0112 int len;
0113 unsigned long long num;
0114 int i, base;
0115 char * str;
0116 const char *s;
0117
0118 int flags;
0119
0120 int field_width;
0121 int precision;
0122
0123 int qualifier;
0124
0125
0126
0127
0128 for (str=buf ; *fmt ; ++fmt) {
0129 if (*fmt != '%') {
0130 *str++ = *fmt;
0131 continue;
0132 }
0133
0134
0135 flags = 0;
0136 repeat:
0137 ++fmt;
0138 switch (*fmt) {
0139 case '-': flags |= LEFT; goto repeat;
0140 case '+': flags |= PLUS; goto repeat;
0141 case ' ': flags |= SPACE; goto repeat;
0142 case '#': flags |= SPECIAL; goto repeat;
0143 case '0': flags |= ZEROPAD; goto repeat;
0144 }
0145
0146
0147 field_width = -1;
0148 if ('0' <= *fmt && *fmt <= '9')
0149 field_width = skip_atoi(&fmt);
0150 else if (*fmt == '*') {
0151 ++fmt;
0152
0153 field_width = va_arg(args, int);
0154 if (field_width < 0) {
0155 field_width = -field_width;
0156 flags |= LEFT;
0157 }
0158 }
0159
0160
0161 precision = -1;
0162 if (*fmt == '.') {
0163 ++fmt;
0164 if ('0' <= *fmt && *fmt <= '9')
0165 precision = skip_atoi(&fmt);
0166 else if (*fmt == '*') {
0167 ++fmt;
0168
0169 precision = va_arg(args, int);
0170 }
0171 if (precision < 0)
0172 precision = 0;
0173 }
0174
0175
0176 qualifier = -1;
0177 if (*fmt == 'l' && *(fmt + 1) == 'l') {
0178 qualifier = 'q';
0179 fmt += 2;
0180 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
0181 || *fmt == 'Z') {
0182 qualifier = *fmt;
0183 ++fmt;
0184 }
0185
0186
0187 base = 10;
0188
0189 switch (*fmt) {
0190 case 'c':
0191 if (!(flags & LEFT))
0192 while (--field_width > 0)
0193 *str++ = ' ';
0194 *str++ = (unsigned char) va_arg(args, int);
0195 while (--field_width > 0)
0196 *str++ = ' ';
0197 continue;
0198
0199 case 's':
0200 s = va_arg(args, char *);
0201 if (!s)
0202 s = "<NULL>";
0203
0204 len = strnlen(s, precision);
0205
0206 if (!(flags & LEFT))
0207 while (len < field_width--)
0208 *str++ = ' ';
0209 for (i = 0; i < len; ++i)
0210 *str++ = *s++;
0211 while (len < field_width--)
0212 *str++ = ' ';
0213 continue;
0214
0215 case 'p':
0216 if (field_width == -1) {
0217 field_width = 2*sizeof(void *);
0218 flags |= ZEROPAD;
0219 }
0220 str = number(str,
0221 (unsigned long) va_arg(args, void *), 16,
0222 field_width, precision, flags);
0223 continue;
0224
0225
0226 case 'n':
0227 if (qualifier == 'l') {
0228 long * ip = va_arg(args, long *);
0229 *ip = (str - buf);
0230 } else if (qualifier == 'Z') {
0231 size_t * ip = va_arg(args, size_t *);
0232 *ip = (str - buf);
0233 } else {
0234 int * ip = va_arg(args, int *);
0235 *ip = (str - buf);
0236 }
0237 continue;
0238
0239 case '%':
0240 *str++ = '%';
0241 continue;
0242
0243
0244 case 'o':
0245 base = 8;
0246 break;
0247
0248 case 'X':
0249 flags |= LARGE;
0250 case 'x':
0251 base = 16;
0252 break;
0253
0254 case 'd':
0255 case 'i':
0256 flags |= SIGN;
0257 case 'u':
0258 break;
0259
0260 default:
0261 *str++ = '%';
0262 if (*fmt)
0263 *str++ = *fmt;
0264 else
0265 --fmt;
0266 continue;
0267 }
0268 if (qualifier == 'l') {
0269 num = va_arg(args, unsigned long);
0270 if (flags & SIGN)
0271 num = (signed long) num;
0272 } else if (qualifier == 'q') {
0273 num = va_arg(args, unsigned long long);
0274 if (flags & SIGN)
0275 num = (signed long long) num;
0276 } else if (qualifier == 'Z') {
0277 num = va_arg(args, size_t);
0278 } else if (qualifier == 'h') {
0279 num = (unsigned short) va_arg(args, int);
0280 if (flags & SIGN)
0281 num = (signed short) num;
0282 } else {
0283 num = va_arg(args, unsigned int);
0284 if (flags & SIGN)
0285 num = (signed int) num;
0286 }
0287 str = number(str, num, base, field_width, precision, flags);
0288 }
0289 *str = '\0';
0290 return str-buf;
0291 }
0292
0293 int sprintf(char * buf, const char *fmt, ...)
0294 {
0295 va_list args;
0296 int i;
0297
0298 va_start(args, fmt);
0299 i=vsprintf(buf,fmt,args);
0300 va_end(args);
0301 return i;
0302 }