18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- * 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 58c2ecf20Sopenharmony_ci * Copyright 2007 rPath, Inc. - All Rights Reserved 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * ----------------------------------------------------------------------- */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Oh, it's a waste of space, but oh-so-yummy for debugging. This 118c2ecf20Sopenharmony_ci * version of printf() does not include 64-bit support. "Live with 128c2ecf20Sopenharmony_ci * it." 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "boot.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int skip_atoi(const char **s) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int i = 0; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci while (isdigit(**s)) 238c2ecf20Sopenharmony_ci i = i * 10 + *((*s)++) - '0'; 248c2ecf20Sopenharmony_ci return i; 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define ZEROPAD 1 /* pad with zero */ 288c2ecf20Sopenharmony_ci#define SIGN 2 /* unsigned/signed long */ 298c2ecf20Sopenharmony_ci#define PLUS 4 /* show plus */ 308c2ecf20Sopenharmony_ci#define SPACE 8 /* space if plus */ 318c2ecf20Sopenharmony_ci#define LEFT 16 /* left justified */ 328c2ecf20Sopenharmony_ci#define SMALL 32 /* Must be 32 == 0x20 */ 338c2ecf20Sopenharmony_ci#define SPECIAL 64 /* 0x */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define __do_div(n, base) ({ \ 368c2ecf20Sopenharmony_ciint __res; \ 378c2ecf20Sopenharmony_ci__res = ((unsigned long) n) % (unsigned) base; \ 388c2ecf20Sopenharmony_cin = ((unsigned long) n) / (unsigned) base; \ 398c2ecf20Sopenharmony_ci__res; }) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic char *number(char *str, long num, int base, int size, int precision, 428c2ecf20Sopenharmony_ci int type) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 458c2ecf20Sopenharmony_ci static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci char tmp[66]; 488c2ecf20Sopenharmony_ci char c, sign, locase; 498c2ecf20Sopenharmony_ci int i; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* locase = 0 or 0x20. ORing digits or letters with 'locase' 528c2ecf20Sopenharmony_ci * produces same digits or (maybe lowercased) letters */ 538c2ecf20Sopenharmony_ci locase = (type & SMALL); 548c2ecf20Sopenharmony_ci if (type & LEFT) 558c2ecf20Sopenharmony_ci type &= ~ZEROPAD; 568c2ecf20Sopenharmony_ci if (base < 2 || base > 16) 578c2ecf20Sopenharmony_ci return NULL; 588c2ecf20Sopenharmony_ci c = (type & ZEROPAD) ? '0' : ' '; 598c2ecf20Sopenharmony_ci sign = 0; 608c2ecf20Sopenharmony_ci if (type & SIGN) { 618c2ecf20Sopenharmony_ci if (num < 0) { 628c2ecf20Sopenharmony_ci sign = '-'; 638c2ecf20Sopenharmony_ci num = -num; 648c2ecf20Sopenharmony_ci size--; 658c2ecf20Sopenharmony_ci } else if (type & PLUS) { 668c2ecf20Sopenharmony_ci sign = '+'; 678c2ecf20Sopenharmony_ci size--; 688c2ecf20Sopenharmony_ci } else if (type & SPACE) { 698c2ecf20Sopenharmony_ci sign = ' '; 708c2ecf20Sopenharmony_ci size--; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci if (type & SPECIAL) { 748c2ecf20Sopenharmony_ci if (base == 16) 758c2ecf20Sopenharmony_ci size -= 2; 768c2ecf20Sopenharmony_ci else if (base == 8) 778c2ecf20Sopenharmony_ci size--; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci i = 0; 808c2ecf20Sopenharmony_ci if (num == 0) 818c2ecf20Sopenharmony_ci tmp[i++] = '0'; 828c2ecf20Sopenharmony_ci else 838c2ecf20Sopenharmony_ci while (num != 0) 848c2ecf20Sopenharmony_ci tmp[i++] = (digits[__do_div(num, base)] | locase); 858c2ecf20Sopenharmony_ci if (i > precision) 868c2ecf20Sopenharmony_ci precision = i; 878c2ecf20Sopenharmony_ci size -= precision; 888c2ecf20Sopenharmony_ci if (!(type & (ZEROPAD + LEFT))) 898c2ecf20Sopenharmony_ci while (size-- > 0) 908c2ecf20Sopenharmony_ci *str++ = ' '; 918c2ecf20Sopenharmony_ci if (sign) 928c2ecf20Sopenharmony_ci *str++ = sign; 938c2ecf20Sopenharmony_ci if (type & SPECIAL) { 948c2ecf20Sopenharmony_ci if (base == 8) 958c2ecf20Sopenharmony_ci *str++ = '0'; 968c2ecf20Sopenharmony_ci else if (base == 16) { 978c2ecf20Sopenharmony_ci *str++ = '0'; 988c2ecf20Sopenharmony_ci *str++ = ('X' | locase); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci if (!(type & LEFT)) 1028c2ecf20Sopenharmony_ci while (size-- > 0) 1038c2ecf20Sopenharmony_ci *str++ = c; 1048c2ecf20Sopenharmony_ci while (i < precision--) 1058c2ecf20Sopenharmony_ci *str++ = '0'; 1068c2ecf20Sopenharmony_ci while (i-- > 0) 1078c2ecf20Sopenharmony_ci *str++ = tmp[i]; 1088c2ecf20Sopenharmony_ci while (size-- > 0) 1098c2ecf20Sopenharmony_ci *str++ = ' '; 1108c2ecf20Sopenharmony_ci return str; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint vsprintf(char *buf, const char *fmt, va_list args) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int len; 1168c2ecf20Sopenharmony_ci unsigned long num; 1178c2ecf20Sopenharmony_ci int i, base; 1188c2ecf20Sopenharmony_ci char *str; 1198c2ecf20Sopenharmony_ci const char *s; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci int flags; /* flags to number() */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci int field_width; /* width of output field */ 1248c2ecf20Sopenharmony_ci int precision; /* min. # of digits for integers; max 1258c2ecf20Sopenharmony_ci number of chars for from string */ 1268c2ecf20Sopenharmony_ci int qualifier; /* 'h', 'l', or 'L' for integer fields */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (str = buf; *fmt; ++fmt) { 1298c2ecf20Sopenharmony_ci if (*fmt != '%') { 1308c2ecf20Sopenharmony_ci *str++ = *fmt; 1318c2ecf20Sopenharmony_ci continue; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* process flags */ 1358c2ecf20Sopenharmony_ci flags = 0; 1368c2ecf20Sopenharmony_ci repeat: 1378c2ecf20Sopenharmony_ci ++fmt; /* this also skips first '%' */ 1388c2ecf20Sopenharmony_ci switch (*fmt) { 1398c2ecf20Sopenharmony_ci case '-': 1408c2ecf20Sopenharmony_ci flags |= LEFT; 1418c2ecf20Sopenharmony_ci goto repeat; 1428c2ecf20Sopenharmony_ci case '+': 1438c2ecf20Sopenharmony_ci flags |= PLUS; 1448c2ecf20Sopenharmony_ci goto repeat; 1458c2ecf20Sopenharmony_ci case ' ': 1468c2ecf20Sopenharmony_ci flags |= SPACE; 1478c2ecf20Sopenharmony_ci goto repeat; 1488c2ecf20Sopenharmony_ci case '#': 1498c2ecf20Sopenharmony_ci flags |= SPECIAL; 1508c2ecf20Sopenharmony_ci goto repeat; 1518c2ecf20Sopenharmony_ci case '0': 1528c2ecf20Sopenharmony_ci flags |= ZEROPAD; 1538c2ecf20Sopenharmony_ci goto repeat; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* get field width */ 1578c2ecf20Sopenharmony_ci field_width = -1; 1588c2ecf20Sopenharmony_ci if (isdigit(*fmt)) 1598c2ecf20Sopenharmony_ci field_width = skip_atoi(&fmt); 1608c2ecf20Sopenharmony_ci else if (*fmt == '*') { 1618c2ecf20Sopenharmony_ci ++fmt; 1628c2ecf20Sopenharmony_ci /* it's the next argument */ 1638c2ecf20Sopenharmony_ci field_width = va_arg(args, int); 1648c2ecf20Sopenharmony_ci if (field_width < 0) { 1658c2ecf20Sopenharmony_ci field_width = -field_width; 1668c2ecf20Sopenharmony_ci flags |= LEFT; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* get the precision */ 1718c2ecf20Sopenharmony_ci precision = -1; 1728c2ecf20Sopenharmony_ci if (*fmt == '.') { 1738c2ecf20Sopenharmony_ci ++fmt; 1748c2ecf20Sopenharmony_ci if (isdigit(*fmt)) 1758c2ecf20Sopenharmony_ci precision = skip_atoi(&fmt); 1768c2ecf20Sopenharmony_ci else if (*fmt == '*') { 1778c2ecf20Sopenharmony_ci ++fmt; 1788c2ecf20Sopenharmony_ci /* it's the next argument */ 1798c2ecf20Sopenharmony_ci precision = va_arg(args, int); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (precision < 0) 1828c2ecf20Sopenharmony_ci precision = 0; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* get the conversion qualifier */ 1868c2ecf20Sopenharmony_ci qualifier = -1; 1878c2ecf20Sopenharmony_ci if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 1888c2ecf20Sopenharmony_ci qualifier = *fmt; 1898c2ecf20Sopenharmony_ci ++fmt; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* default base */ 1938c2ecf20Sopenharmony_ci base = 10; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci switch (*fmt) { 1968c2ecf20Sopenharmony_ci case 'c': 1978c2ecf20Sopenharmony_ci if (!(flags & LEFT)) 1988c2ecf20Sopenharmony_ci while (--field_width > 0) 1998c2ecf20Sopenharmony_ci *str++ = ' '; 2008c2ecf20Sopenharmony_ci *str++ = (unsigned char)va_arg(args, int); 2018c2ecf20Sopenharmony_ci while (--field_width > 0) 2028c2ecf20Sopenharmony_ci *str++ = ' '; 2038c2ecf20Sopenharmony_ci continue; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci case 's': 2068c2ecf20Sopenharmony_ci s = va_arg(args, char *); 2078c2ecf20Sopenharmony_ci len = strnlen(s, precision); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!(flags & LEFT)) 2108c2ecf20Sopenharmony_ci while (len < field_width--) 2118c2ecf20Sopenharmony_ci *str++ = ' '; 2128c2ecf20Sopenharmony_ci for (i = 0; i < len; ++i) 2138c2ecf20Sopenharmony_ci *str++ = *s++; 2148c2ecf20Sopenharmony_ci while (len < field_width--) 2158c2ecf20Sopenharmony_ci *str++ = ' '; 2168c2ecf20Sopenharmony_ci continue; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci case 'p': 2198c2ecf20Sopenharmony_ci if (field_width == -1) { 2208c2ecf20Sopenharmony_ci field_width = 2 * sizeof(void *); 2218c2ecf20Sopenharmony_ci flags |= ZEROPAD; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci str = number(str, 2248c2ecf20Sopenharmony_ci (unsigned long)va_arg(args, void *), 16, 2258c2ecf20Sopenharmony_ci field_width, precision, flags); 2268c2ecf20Sopenharmony_ci continue; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci case 'n': 2298c2ecf20Sopenharmony_ci if (qualifier == 'l') { 2308c2ecf20Sopenharmony_ci long *ip = va_arg(args, long *); 2318c2ecf20Sopenharmony_ci *ip = (str - buf); 2328c2ecf20Sopenharmony_ci } else { 2338c2ecf20Sopenharmony_ci int *ip = va_arg(args, int *); 2348c2ecf20Sopenharmony_ci *ip = (str - buf); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci continue; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case '%': 2398c2ecf20Sopenharmony_ci *str++ = '%'; 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* integer number formats - set up the flags and "break" */ 2438c2ecf20Sopenharmony_ci case 'o': 2448c2ecf20Sopenharmony_ci base = 8; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci case 'x': 2488c2ecf20Sopenharmony_ci flags |= SMALL; 2498c2ecf20Sopenharmony_ci case 'X': 2508c2ecf20Sopenharmony_ci base = 16; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci case 'd': 2548c2ecf20Sopenharmony_ci case 'i': 2558c2ecf20Sopenharmony_ci flags |= SIGN; 2568c2ecf20Sopenharmony_ci case 'u': 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci default: 2608c2ecf20Sopenharmony_ci *str++ = '%'; 2618c2ecf20Sopenharmony_ci if (*fmt) 2628c2ecf20Sopenharmony_ci *str++ = *fmt; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci --fmt; 2658c2ecf20Sopenharmony_ci continue; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci if (qualifier == 'l') 2688c2ecf20Sopenharmony_ci num = va_arg(args, unsigned long); 2698c2ecf20Sopenharmony_ci else if (qualifier == 'h') { 2708c2ecf20Sopenharmony_ci num = (unsigned short)va_arg(args, int); 2718c2ecf20Sopenharmony_ci if (flags & SIGN) 2728c2ecf20Sopenharmony_ci num = (short)num; 2738c2ecf20Sopenharmony_ci } else if (flags & SIGN) 2748c2ecf20Sopenharmony_ci num = va_arg(args, int); 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci num = va_arg(args, unsigned int); 2778c2ecf20Sopenharmony_ci str = number(str, num, base, field_width, precision, flags); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci *str = '\0'; 2808c2ecf20Sopenharmony_ci return str - buf; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciint sprintf(char *buf, const char *fmt, ...) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci va_list args; 2868c2ecf20Sopenharmony_ci int i; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci va_start(args, fmt); 2898c2ecf20Sopenharmony_ci i = vsprintf(buf, fmt, args); 2908c2ecf20Sopenharmony_ci va_end(args); 2918c2ecf20Sopenharmony_ci return i; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint printf(const char *fmt, ...) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci char printf_buf[1024]; 2978c2ecf20Sopenharmony_ci va_list args; 2988c2ecf20Sopenharmony_ci int printed; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci va_start(args, fmt); 3018c2ecf20Sopenharmony_ci printed = vsprintf(printf_buf, fmt, args); 3028c2ecf20Sopenharmony_ci va_end(args); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci puts(printf_buf); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return printed; 3078c2ecf20Sopenharmony_ci} 308