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