1 /* 2 * Copyright (C) Paul Mackerras 1997. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 #include <stdarg.h> 10 #include <stddef.h> 11 12 size_t strnlen(const char * s, size_t count) 13 { 14 const char *sc; 15 16 for (sc = s; count-- && *sc != '\0'; ++sc) 17 /* nothing */; 18 return sc - s; 19 } 20 21 # define do_div(n, base) ({ \ 22 unsigned int __base = (base); \ 23 unsigned int __rem; \ 24 __rem = ((unsigned long long)(n)) % __base; \ 25 (n) = ((unsigned long long)(n)) / __base; \ 26 __rem; \ 27 }) 28 29 30 static int skip_atoi(const char **s) 31 { 32 int i, c; 33 34 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s) 35 i = i*10 + c - '0'; 36 return i; 37 } 38 39 #define ZEROPAD 1 /* pad with zero */ 40 #define SIGN 2 /* unsigned/signed long */ 41 #define PLUS 4 /* show plus */ 42 #define SPACE 8 /* space if plus */ 43 #define LEFT 16 /* left justified */ 44 #define SPECIAL 32 /* 0x */ 45 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 46 47 static char * number(char * str, unsigned long long num, int base, int size, int precision, int type) 48 { 49 char c,sign,tmp[66]; 50 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; 51 int i; 52 53 if (type & LARGE) 54 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 55 if (type & LEFT) 56 type &= ~ZEROPAD; 57 if (base < 2 || base > 36) 58 return 0; 59 c = (type & ZEROPAD) ? '0' : ' '; 60 sign = 0; 61 if (type & SIGN) { 62 if ((signed long long)num < 0) { 63 sign = '-'; 64 num = - (signed long long)num; 65 size--; 66 } else if (type & PLUS) { 67 sign = '+'; 68 size--; 69 } else if (type & SPACE) { 70 sign = ' '; 71 size--; 72 } 73 } 74 if (type & SPECIAL) { 75 if (base == 16) 76 size -= 2; 77 else if (base == 8) 78 size--; 79 } 80 i = 0; 81 if (num == 0) 82 tmp[i++]='0'; 83 else while (num != 0) { 84 tmp[i++] = digits[do_div(num, base)]; 85 } 86 if (i > precision) 87 precision = i; 88 size -= precision; 89 if (!(type&(ZEROPAD+LEFT))) 90 while(size-->0) 91 *str++ = ' '; 92 if (sign) 93 *str++ = sign; 94 if (type & SPECIAL) { 95 if (base==8) 96 *str++ = '0'; 97 else if (base==16) { 98 *str++ = '0'; 99 *str++ = digits[33]; 100 } 101 } 102 if (!(type & LEFT)) 103 while (size-- > 0) 104 *str++ = c; 105 while (i < precision--) 106 *str++ = '0'; 107 while (i-- > 0) 108 *str++ = tmp[i]; 109 while (size-- > 0) 110 *str++ = ' '; 111 return str; 112 } 113 114 int vsprintf(char *buf, const char *fmt, va_list args) 115 { 116 int len; 117 unsigned long long num; 118 int i, base; 119 char * str; 120 const char *s; 121 122 int flags; /* flags to number() */ 123 124 int field_width; /* width of output field */ 125 int precision; /* min. # of digits for integers; max 126 number of chars for from string */ 127 int qualifier; /* 'h', 'l', or 'L' for integer fields */ 128 /* 'z' support added 23/7/1999 S.H. */ 129 /* 'z' changed to 'Z' --davidm 1/25/99 */ 130 131 132 for (str=buf ; *fmt ; ++fmt) { 133 if (*fmt != '%') { 134 *str++ = *fmt; 135 continue; 136 } 137 138 /* process flags */ 139 flags = 0; 140 repeat: 141 ++fmt; /* this also skips first '%' */ 142 switch (*fmt) { 143 case '-': flags |= LEFT; goto repeat; 144 case '+': flags |= PLUS; goto repeat; 145 case ' ': flags |= SPACE; goto repeat; 146 case '#': flags |= SPECIAL; goto repeat; 147 case '0': flags |= ZEROPAD; goto repeat; 148 } 149 150 /* get field width */ 151 field_width = -1; 152 if ('0' <= *fmt && *fmt <= '9') 153 field_width = skip_atoi(&fmt); 154 else if (*fmt == '*') { 155 ++fmt; 156 /* it's the next argument */ 157 field_width = va_arg(args, int); 158 if (field_width < 0) { 159 field_width = -field_width; 160 flags |= LEFT; 161 } 162 } 163 164 /* get the precision */ 165 precision = -1; 166 if (*fmt == '.') { 167 ++fmt; 168 if ('0' <= *fmt && *fmt <= '9') 169 precision = skip_atoi(&fmt); 170 else if (*fmt == '*') { 171 ++fmt; 172 /* it's the next argument */ 173 precision = va_arg(args, int); 174 } 175 if (precision < 0) 176 precision = 0; 177 } 178 179 /* get the conversion qualifier */ 180 qualifier = -1; 181 if (*fmt == 'l' && *(fmt + 1) == 'l') { 182 qualifier = 'q'; 183 fmt += 2; 184 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' 185 || *fmt == 'Z') { 186 qualifier = *fmt; 187 ++fmt; 188 } 189 190 /* default base */ 191 base = 10; 192 193 switch (*fmt) { 194 case 'c': 195 if (!(flags & LEFT)) 196 while (--field_width > 0) 197 *str++ = ' '; 198 *str++ = (unsigned char) va_arg(args, int); 199 while (--field_width > 0) 200 *str++ = ' '; 201 continue; 202 203 case 's': 204 s = va_arg(args, char *); 205 if (!s) 206 s = "<NULL>"; 207 208 len = strnlen(s, precision); 209 210 if (!(flags & LEFT)) 211 while (len < field_width--) 212 *str++ = ' '; 213 for (i = 0; i < len; ++i) 214 *str++ = *s++; 215 while (len < field_width--) 216 *str++ = ' '; 217 continue; 218 219 case 'p': 220 if (field_width == -1) { 221 field_width = 2*sizeof(void *); 222 flags |= ZEROPAD; 223 } 224 str = number(str, 225 (unsigned long) va_arg(args, void *), 16, 226 field_width, precision, flags); 227 continue; 228 229 230 case 'n': 231 if (qualifier == 'l') { 232 long * ip = va_arg(args, long *); 233 *ip = (str - buf); 234 } else if (qualifier == 'Z') { 235 size_t * ip = va_arg(args, size_t *); 236 *ip = (str - buf); 237 } else { 238 int * ip = va_arg(args, int *); 239 *ip = (str - buf); 240 } 241 continue; 242 243 case '%': 244 *str++ = '%'; 245 continue; 246 247 /* integer number formats - set up the flags and "break" */ 248 case 'o': 249 base = 8; 250 break; 251 252 case 'X': 253 flags |= LARGE; 254 case 'x': 255 base = 16; 256 break; 257 258 case 'd': 259 case 'i': 260 flags |= SIGN; 261 case 'u': 262 break; 263 264 default: 265 *str++ = '%'; 266 if (*fmt) 267 *str++ = *fmt; 268 else 269 --fmt; 270 continue; 271 } 272 if (qualifier == 'l') { 273 num = va_arg(args, unsigned long); 274 if (flags & SIGN) 275 num = (signed long) num; 276 } else if (qualifier == 'q') { 277 num = va_arg(args, unsigned long long); 278 if (flags & SIGN) 279 num = (signed long long) num; 280 } else if (qualifier == 'Z') { 281 num = va_arg(args, size_t); 282 } else if (qualifier == 'h') { 283 num = (unsigned short) va_arg(args, int); 284 if (flags & SIGN) 285 num = (signed short) num; 286 } else { 287 num = va_arg(args, unsigned int); 288 if (flags & SIGN) 289 num = (signed int) num; 290 } 291 str = number(str, num, base, field_width, precision, flags); 292 } 293 *str = '\0'; 294 return str-buf; 295 } 296 297 int sprintf(char * buf, const char *fmt, ...) 298 { 299 va_list args; 300 int i; 301 302 va_start(args, fmt); 303 i=vsprintf(buf,fmt,args); 304 va_end(args); 305 return i; 306 } 307