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