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