162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* -*- linux-c -*- ------------------------------------------------------- * 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 562306a36Sopenharmony_ci * Copyright 2007 rPath, Inc. - All Rights Reserved 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * ----------------------------------------------------------------------- */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * Oh, it's a waste of space, but oh-so-yummy for debugging. This 1162306a36Sopenharmony_ci * version of printf() does not include 64-bit support. "Live with 1262306a36Sopenharmony_ci * it." 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "boot.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int skip_atoi(const char **s) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci int i = 0; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci while (isdigit(**s)) 2362306a36Sopenharmony_ci i = i * 10 + *((*s)++) - '0'; 2462306a36Sopenharmony_ci return i; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define ZEROPAD 1 /* pad with zero */ 2862306a36Sopenharmony_ci#define SIGN 2 /* unsigned/signed long */ 2962306a36Sopenharmony_ci#define PLUS 4 /* show plus */ 3062306a36Sopenharmony_ci#define SPACE 8 /* space if plus */ 3162306a36Sopenharmony_ci#define LEFT 16 /* left justified */ 3262306a36Sopenharmony_ci#define SMALL 32 /* Must be 32 == 0x20 */ 3362306a36Sopenharmony_ci#define SPECIAL 64 /* 0x */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define __do_div(n, base) ({ \ 3662306a36Sopenharmony_ciint __res; \ 3762306a36Sopenharmony_ci__res = ((unsigned long) n) % (unsigned) base; \ 3862306a36Sopenharmony_cin = ((unsigned long) n) / (unsigned) base; \ 3962306a36Sopenharmony_ci__res; }) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic char *number(char *str, long num, int base, int size, int precision, 4262306a36Sopenharmony_ci int type) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 4562306a36Sopenharmony_ci static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci char tmp[66]; 4862306a36Sopenharmony_ci char c, sign, locase; 4962306a36Sopenharmony_ci int i; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* locase = 0 or 0x20. ORing digits or letters with 'locase' 5262306a36Sopenharmony_ci * produces same digits or (maybe lowercased) letters */ 5362306a36Sopenharmony_ci locase = (type & SMALL); 5462306a36Sopenharmony_ci if (type & LEFT) 5562306a36Sopenharmony_ci type &= ~ZEROPAD; 5662306a36Sopenharmony_ci if (base < 2 || base > 16) 5762306a36Sopenharmony_ci return NULL; 5862306a36Sopenharmony_ci c = (type & ZEROPAD) ? '0' : ' '; 5962306a36Sopenharmony_ci sign = 0; 6062306a36Sopenharmony_ci if (type & SIGN) { 6162306a36Sopenharmony_ci if (num < 0) { 6262306a36Sopenharmony_ci sign = '-'; 6362306a36Sopenharmony_ci num = -num; 6462306a36Sopenharmony_ci size--; 6562306a36Sopenharmony_ci } else if (type & PLUS) { 6662306a36Sopenharmony_ci sign = '+'; 6762306a36Sopenharmony_ci size--; 6862306a36Sopenharmony_ci } else if (type & SPACE) { 6962306a36Sopenharmony_ci sign = ' '; 7062306a36Sopenharmony_ci size--; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci if (type & SPECIAL) { 7462306a36Sopenharmony_ci if (base == 16) 7562306a36Sopenharmony_ci size -= 2; 7662306a36Sopenharmony_ci else if (base == 8) 7762306a36Sopenharmony_ci size--; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci i = 0; 8062306a36Sopenharmony_ci if (num == 0) 8162306a36Sopenharmony_ci tmp[i++] = '0'; 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci while (num != 0) 8462306a36Sopenharmony_ci tmp[i++] = (digits[__do_div(num, base)] | locase); 8562306a36Sopenharmony_ci if (i > precision) 8662306a36Sopenharmony_ci precision = i; 8762306a36Sopenharmony_ci size -= precision; 8862306a36Sopenharmony_ci if (!(type & (ZEROPAD + LEFT))) 8962306a36Sopenharmony_ci while (size-- > 0) 9062306a36Sopenharmony_ci *str++ = ' '; 9162306a36Sopenharmony_ci if (sign) 9262306a36Sopenharmony_ci *str++ = sign; 9362306a36Sopenharmony_ci if (type & SPECIAL) { 9462306a36Sopenharmony_ci if (base == 8) 9562306a36Sopenharmony_ci *str++ = '0'; 9662306a36Sopenharmony_ci else if (base == 16) { 9762306a36Sopenharmony_ci *str++ = '0'; 9862306a36Sopenharmony_ci *str++ = ('X' | locase); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci if (!(type & LEFT)) 10262306a36Sopenharmony_ci while (size-- > 0) 10362306a36Sopenharmony_ci *str++ = c; 10462306a36Sopenharmony_ci while (i < precision--) 10562306a36Sopenharmony_ci *str++ = '0'; 10662306a36Sopenharmony_ci while (i-- > 0) 10762306a36Sopenharmony_ci *str++ = tmp[i]; 10862306a36Sopenharmony_ci while (size-- > 0) 10962306a36Sopenharmony_ci *str++ = ' '; 11062306a36Sopenharmony_ci return str; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint vsprintf(char *buf, const char *fmt, va_list args) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci int len; 11662306a36Sopenharmony_ci unsigned long num; 11762306a36Sopenharmony_ci int i, base; 11862306a36Sopenharmony_ci char *str; 11962306a36Sopenharmony_ci const char *s; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci int flags; /* flags to number() */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci int field_width; /* width of output field */ 12462306a36Sopenharmony_ci int precision; /* min. # of digits for integers; max 12562306a36Sopenharmony_ci number of chars for from string */ 12662306a36Sopenharmony_ci int qualifier; /* 'h', 'l', or 'L' for integer fields */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (str = buf; *fmt; ++fmt) { 12962306a36Sopenharmony_ci if (*fmt != '%') { 13062306a36Sopenharmony_ci *str++ = *fmt; 13162306a36Sopenharmony_ci continue; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* process flags */ 13562306a36Sopenharmony_ci flags = 0; 13662306a36Sopenharmony_ci repeat: 13762306a36Sopenharmony_ci ++fmt; /* this also skips first '%' */ 13862306a36Sopenharmony_ci switch (*fmt) { 13962306a36Sopenharmony_ci case '-': 14062306a36Sopenharmony_ci flags |= LEFT; 14162306a36Sopenharmony_ci goto repeat; 14262306a36Sopenharmony_ci case '+': 14362306a36Sopenharmony_ci flags |= PLUS; 14462306a36Sopenharmony_ci goto repeat; 14562306a36Sopenharmony_ci case ' ': 14662306a36Sopenharmony_ci flags |= SPACE; 14762306a36Sopenharmony_ci goto repeat; 14862306a36Sopenharmony_ci case '#': 14962306a36Sopenharmony_ci flags |= SPECIAL; 15062306a36Sopenharmony_ci goto repeat; 15162306a36Sopenharmony_ci case '0': 15262306a36Sopenharmony_ci flags |= ZEROPAD; 15362306a36Sopenharmony_ci goto repeat; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* get field width */ 15762306a36Sopenharmony_ci field_width = -1; 15862306a36Sopenharmony_ci if (isdigit(*fmt)) 15962306a36Sopenharmony_ci field_width = skip_atoi(&fmt); 16062306a36Sopenharmony_ci else if (*fmt == '*') { 16162306a36Sopenharmony_ci ++fmt; 16262306a36Sopenharmony_ci /* it's the next argument */ 16362306a36Sopenharmony_ci field_width = va_arg(args, int); 16462306a36Sopenharmony_ci if (field_width < 0) { 16562306a36Sopenharmony_ci field_width = -field_width; 16662306a36Sopenharmony_ci flags |= LEFT; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* get the precision */ 17162306a36Sopenharmony_ci precision = -1; 17262306a36Sopenharmony_ci if (*fmt == '.') { 17362306a36Sopenharmony_ci ++fmt; 17462306a36Sopenharmony_ci if (isdigit(*fmt)) 17562306a36Sopenharmony_ci precision = skip_atoi(&fmt); 17662306a36Sopenharmony_ci else if (*fmt == '*') { 17762306a36Sopenharmony_ci ++fmt; 17862306a36Sopenharmony_ci /* it's the next argument */ 17962306a36Sopenharmony_ci precision = va_arg(args, int); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci if (precision < 0) 18262306a36Sopenharmony_ci precision = 0; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* get the conversion qualifier */ 18662306a36Sopenharmony_ci qualifier = -1; 18762306a36Sopenharmony_ci if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 18862306a36Sopenharmony_ci qualifier = *fmt; 18962306a36Sopenharmony_ci ++fmt; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* default base */ 19362306a36Sopenharmony_ci base = 10; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci switch (*fmt) { 19662306a36Sopenharmony_ci case 'c': 19762306a36Sopenharmony_ci if (!(flags & LEFT)) 19862306a36Sopenharmony_ci while (--field_width > 0) 19962306a36Sopenharmony_ci *str++ = ' '; 20062306a36Sopenharmony_ci *str++ = (unsigned char)va_arg(args, int); 20162306a36Sopenharmony_ci while (--field_width > 0) 20262306a36Sopenharmony_ci *str++ = ' '; 20362306a36Sopenharmony_ci continue; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci case 's': 20662306a36Sopenharmony_ci s = va_arg(args, char *); 20762306a36Sopenharmony_ci len = strnlen(s, precision); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!(flags & LEFT)) 21062306a36Sopenharmony_ci while (len < field_width--) 21162306a36Sopenharmony_ci *str++ = ' '; 21262306a36Sopenharmony_ci for (i = 0; i < len; ++i) 21362306a36Sopenharmony_ci *str++ = *s++; 21462306a36Sopenharmony_ci while (len < field_width--) 21562306a36Sopenharmony_ci *str++ = ' '; 21662306a36Sopenharmony_ci continue; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci case 'p': 21962306a36Sopenharmony_ci if (field_width == -1) { 22062306a36Sopenharmony_ci field_width = 2 * sizeof(void *); 22162306a36Sopenharmony_ci flags |= ZEROPAD; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci str = number(str, 22462306a36Sopenharmony_ci (unsigned long)va_arg(args, void *), 16, 22562306a36Sopenharmony_ci field_width, precision, flags); 22662306a36Sopenharmony_ci continue; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci case 'n': 22962306a36Sopenharmony_ci if (qualifier == 'l') { 23062306a36Sopenharmony_ci long *ip = va_arg(args, long *); 23162306a36Sopenharmony_ci *ip = (str - buf); 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci int *ip = va_arg(args, int *); 23462306a36Sopenharmony_ci *ip = (str - buf); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci continue; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci case '%': 23962306a36Sopenharmony_ci *str++ = '%'; 24062306a36Sopenharmony_ci continue; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* integer number formats - set up the flags and "break" */ 24362306a36Sopenharmony_ci case 'o': 24462306a36Sopenharmony_ci base = 8; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci case 'x': 24862306a36Sopenharmony_ci flags |= SMALL; 24962306a36Sopenharmony_ci case 'X': 25062306a36Sopenharmony_ci base = 16; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci case 'd': 25462306a36Sopenharmony_ci case 'i': 25562306a36Sopenharmony_ci flags |= SIGN; 25662306a36Sopenharmony_ci case 'u': 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci default: 26062306a36Sopenharmony_ci *str++ = '%'; 26162306a36Sopenharmony_ci if (*fmt) 26262306a36Sopenharmony_ci *str++ = *fmt; 26362306a36Sopenharmony_ci else 26462306a36Sopenharmony_ci --fmt; 26562306a36Sopenharmony_ci continue; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci if (qualifier == 'l') 26862306a36Sopenharmony_ci num = va_arg(args, unsigned long); 26962306a36Sopenharmony_ci else if (qualifier == 'h') { 27062306a36Sopenharmony_ci num = (unsigned short)va_arg(args, int); 27162306a36Sopenharmony_ci if (flags & SIGN) 27262306a36Sopenharmony_ci num = (short)num; 27362306a36Sopenharmony_ci } else if (flags & SIGN) 27462306a36Sopenharmony_ci num = va_arg(args, int); 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci num = va_arg(args, unsigned int); 27762306a36Sopenharmony_ci str = number(str, num, base, field_width, precision, flags); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci *str = '\0'; 28062306a36Sopenharmony_ci return str - buf; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciint sprintf(char *buf, const char *fmt, ...) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci va_list args; 28662306a36Sopenharmony_ci int i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci va_start(args, fmt); 28962306a36Sopenharmony_ci i = vsprintf(buf, fmt, args); 29062306a36Sopenharmony_ci va_end(args); 29162306a36Sopenharmony_ci return i; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ciint printf(const char *fmt, ...) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci char printf_buf[1024]; 29762306a36Sopenharmony_ci va_list args; 29862306a36Sopenharmony_ci int printed; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci va_start(args, fmt); 30162306a36Sopenharmony_ci printed = vsprintf(printf_buf, fmt, args); 30262306a36Sopenharmony_ci va_end(args); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci puts(printf_buf); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return printed; 30762306a36Sopenharmony_ci} 308