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 #include "string.h" 12 #include "stdio.h" 13 #include "ops.h" 14 15 size_t strnlen(const char * s, size_t count) 16 { 17 const char *sc; 18 19 for (sc = s; count-- && *sc != '\0'; ++sc) 20 /* nothing */; 21 return sc - s; 22 } 23 24 char *strrchr(const char *s, int c) 25 { 26 const char *last = NULL; 27 do { 28 if (*s == (char)c) 29 last = s; 30 } while (*s++); 31 return (char *)last; 32 } 33 34 #ifdef __powerpc64__ 35 36 # define do_div(n, base) ({ \ 37 unsigned int __base = (base); \ 38 unsigned int __rem; \ 39 __rem = ((unsigned long long)(n)) % __base; \ 40 (n) = ((unsigned long long)(n)) / __base; \ 41 __rem; \ 42 }) 43 44 #else 45 46 extern unsigned int __div64_32(unsigned long long *dividend, 47 unsigned int divisor); 48 49 /* The unnecessary pointer compare is there 50 * to check for type safety (n must be 64bit) 51 */ 52 # define do_div(n,base) ({ \ 53 unsigned int __base = (base); \ 54 unsigned int __rem; \ 55 (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \ 56 if (((n) >> 32) == 0) { \ 57 __rem = (unsigned int)(n) % __base; \ 58 (n) = (unsigned int)(n) / __base; \ 59 } else \ 60 __rem = __div64_32(&(n), __base); \ 61 __rem; \ 62 }) 63 64 #endif /* __powerpc64__ */ 65 66 static int skip_atoi(const char **s) 67 { 68 int i, c; 69 70 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s) 71 i = i*10 + c - '0'; 72 return i; 73 } 74 75 #define ZEROPAD 1 /* pad with zero */ 76 #define SIGN 2 /* unsigned/signed long */ 77 #define PLUS 4 /* show plus */ 78 #define SPACE 8 /* space if plus */ 79 #define LEFT 16 /* left justified */ 80 #define SPECIAL 32 /* 0x */ 81 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 82 83 static char * number(char * str, unsigned long long num, int base, int size, int precision, int type) 84 { 85 char c,sign,tmp[66]; 86 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; 87 int i; 88 89 if (type & LARGE) 90 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 91 if (type & LEFT) 92 type &= ~ZEROPAD; 93 if (base < 2 || base > 36) 94 return 0; 95 c = (type & ZEROPAD) ? '0' : ' '; 96 sign = 0; 97 if (type & SIGN) { 98 if ((signed long long)num < 0) { 99 sign = '-'; 100 num = - (signed long long)num; 101 size--; 102 } else if (type & PLUS) { 103 sign = '+'; 104 size--; 105 } else if (type & SPACE) { 106 sign = ' '; 107 size--; 108 } 109 } 110 if (type & SPECIAL) { 111 if (base == 16) 112 size -= 2; 113 else if (base == 8) 114 size--; 115 } 116 i = 0; 117 if (num == 0) 118 tmp[i++]='0'; 119 else while (num != 0) { 120 tmp[i++] = digits[do_div(num, base)]; 121 } 122 if (i > precision) 123 precision = i; 124 size -= precision; 125 if (!(type&(ZEROPAD+LEFT))) 126 while(size-->0) 127 *str++ = ' '; 128 if (sign) 129 *str++ = sign; 130 if (type & SPECIAL) { 131 if (base==8) 132 *str++ = '0'; 133 else if (base==16) { 134 *str++ = '0'; 135 *str++ = digits[33]; 136 } 137 } 138 if (!(type & LEFT)) 139 while (size-- > 0) 140 *str++ = c; 141 while (i < precision--) 142 *str++ = '0'; 143 while (i-- > 0) 144 *str++ = tmp[i]; 145 while (size-- > 0) 146 *str++ = ' '; 147 return str; 148 } 149 150 int vsprintf(char *buf, const char *fmt, va_list args) 151 { 152 int len; 153 unsigned long long num; 154 int i, base; 155 char * str; 156 const char *s; 157 158 int flags; /* flags to number() */ 159 160 int field_width; /* width of output field */ 161 int precision; /* min. # of digits for integers; max 162 number of chars for from string */ 163 int qualifier; /* 'h', 'l', or 'L' for integer fields */ 164 /* 'z' support added 23/7/1999 S.H. */ 165 /* 'z' changed to 'Z' --davidm 1/25/99 */ 166 167 168 for (str=buf ; *fmt ; ++fmt) { 169 if (*fmt != '%') { 170 *str++ = *fmt; 171 continue; 172 } 173 174 /* process flags */ 175 flags = 0; 176 repeat: 177 ++fmt; /* this also skips first '%' */ 178 switch (*fmt) { 179 case '-': flags |= LEFT; goto repeat; 180 case '+': flags |= PLUS; goto repeat; 181 case ' ': flags |= SPACE; goto repeat; 182 case '#': flags |= SPECIAL; goto repeat; 183 case '0': flags |= ZEROPAD; goto repeat; 184 } 185 186 /* get field width */ 187 field_width = -1; 188 if ('0' <= *fmt && *fmt <= '9') 189 field_width = skip_atoi(&fmt); 190 else if (*fmt == '*') { 191 ++fmt; 192 /* it's the next argument */ 193 field_width = va_arg(args, int); 194 if (field_width < 0) { 195 field_width = -field_width; 196 flags |= LEFT; 197 } 198 } 199 200 /* get the precision */ 201 precision = -1; 202 if (*fmt == '.') { 203 ++fmt; 204 if ('0' <= *fmt && *fmt <= '9') 205 precision = skip_atoi(&fmt); 206 else if (*fmt == '*') { 207 ++fmt; 208 /* it's the next argument */ 209 precision = va_arg(args, int); 210 } 211 if (precision < 0) 212 precision = 0; 213 } 214 215 /* get the conversion qualifier */ 216 qualifier = -1; 217 if (*fmt == 'l' && *(fmt + 1) == 'l') { 218 qualifier = 'q'; 219 fmt += 2; 220 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' 221 || *fmt == 'Z') { 222 qualifier = *fmt; 223 ++fmt; 224 } 225 226 /* default base */ 227 base = 10; 228 229 switch (*fmt) { 230 case 'c': 231 if (!(flags & LEFT)) 232 while (--field_width > 0) 233 *str++ = ' '; 234 *str++ = (unsigned char) va_arg(args, int); 235 while (--field_width > 0) 236 *str++ = ' '; 237 continue; 238 239 case 's': 240 s = va_arg(args, char *); 241 if (!s) 242 s = "<NULL>"; 243 244 len = strnlen(s, precision); 245 246 if (!(flags & LEFT)) 247 while (len < field_width--) 248 *str++ = ' '; 249 for (i = 0; i < len; ++i) 250 *str++ = *s++; 251 while (len < field_width--) 252 *str++ = ' '; 253 continue; 254 255 case 'p': 256 if (field_width == -1) { 257 field_width = 2*sizeof(void *); 258 flags |= ZEROPAD; 259 } 260 str = number(str, 261 (unsigned long) va_arg(args, void *), 16, 262 field_width, precision, flags); 263 continue; 264 265 266 case 'n': 267 if (qualifier == 'l') { 268 long * ip = va_arg(args, long *); 269 *ip = (str - buf); 270 } else if (qualifier == 'Z') { 271 size_t * ip = va_arg(args, size_t *); 272 *ip = (str - buf); 273 } else { 274 int * ip = va_arg(args, int *); 275 *ip = (str - buf); 276 } 277 continue; 278 279 case '%': 280 *str++ = '%'; 281 continue; 282 283 /* integer number formats - set up the flags and "break" */ 284 case 'o': 285 base = 8; 286 break; 287 288 case 'X': 289 flags |= LARGE; 290 case 'x': 291 base = 16; 292 break; 293 294 case 'd': 295 case 'i': 296 flags |= SIGN; 297 case 'u': 298 break; 299 300 default: 301 *str++ = '%'; 302 if (*fmt) 303 *str++ = *fmt; 304 else 305 --fmt; 306 continue; 307 } 308 if (qualifier == 'l') { 309 num = va_arg(args, unsigned long); 310 if (flags & SIGN) 311 num = (signed long) num; 312 } else if (qualifier == 'q') { 313 num = va_arg(args, unsigned long long); 314 if (flags & SIGN) 315 num = (signed long long) num; 316 } else if (qualifier == 'Z') { 317 num = va_arg(args, size_t); 318 } else if (qualifier == 'h') { 319 num = (unsigned short) va_arg(args, int); 320 if (flags & SIGN) 321 num = (signed short) num; 322 } else { 323 num = va_arg(args, unsigned int); 324 if (flags & SIGN) 325 num = (signed int) num; 326 } 327 str = number(str, num, base, field_width, precision, flags); 328 } 329 *str = '\0'; 330 return str-buf; 331 } 332 333 int sprintf(char * buf, const char *fmt, ...) 334 { 335 va_list args; 336 int i; 337 338 va_start(args, fmt); 339 i=vsprintf(buf,fmt,args); 340 va_end(args); 341 return i; 342 } 343 344 static char sprint_buf[1024]; 345 346 int 347 printf(const char *fmt, ...) 348 { 349 va_list args; 350 int n; 351 352 va_start(args, fmt); 353 n = vsprintf(sprint_buf, fmt, args); 354 va_end(args); 355 if (console_ops.write) 356 console_ops.write(sprint_buf, n); 357 return n; 358 } 359