1*97873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- * 396ae6ea0SThomas Gleixner * 496ae6ea0SThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds 596ae6ea0SThomas Gleixner * Copyright 2007 rPath, Inc. - All Rights Reserved 696ae6ea0SThomas Gleixner * 796ae6ea0SThomas Gleixner * ----------------------------------------------------------------------- */ 896ae6ea0SThomas Gleixner 996ae6ea0SThomas Gleixner /* 1096ae6ea0SThomas Gleixner * Oh, it's a waste of space, but oh-so-yummy for debugging. This 1196ae6ea0SThomas Gleixner * version of printf() does not include 64-bit support. "Live with 1296ae6ea0SThomas Gleixner * it." 1396ae6ea0SThomas Gleixner * 1496ae6ea0SThomas Gleixner */ 1596ae6ea0SThomas Gleixner 1696ae6ea0SThomas Gleixner #include "boot.h" 1796ae6ea0SThomas Gleixner 1896ae6ea0SThomas Gleixner static int skip_atoi(const char **s) 1996ae6ea0SThomas Gleixner { 2096ae6ea0SThomas Gleixner int i = 0; 2196ae6ea0SThomas Gleixner 2296ae6ea0SThomas Gleixner while (isdigit(**s)) 2396ae6ea0SThomas Gleixner i = i * 10 + *((*s)++) - '0'; 2496ae6ea0SThomas Gleixner return i; 2596ae6ea0SThomas Gleixner } 2696ae6ea0SThomas Gleixner 2796ae6ea0SThomas Gleixner #define ZEROPAD 1 /* pad with zero */ 2896ae6ea0SThomas Gleixner #define SIGN 2 /* unsigned/signed long */ 2996ae6ea0SThomas Gleixner #define PLUS 4 /* show plus */ 3096ae6ea0SThomas Gleixner #define SPACE 8 /* space if plus */ 3196ae6ea0SThomas Gleixner #define LEFT 16 /* left justified */ 329b706aeeSDenys Vlasenko #define SMALL 32 /* Must be 32 == 0x20 */ 339b706aeeSDenys Vlasenko #define SPECIAL 64 /* 0x */ 3496ae6ea0SThomas Gleixner 35f4ed2877SYinghai Lu #define __do_div(n, base) ({ \ 3696ae6ea0SThomas Gleixner int __res; \ 3796ae6ea0SThomas Gleixner __res = ((unsigned long) n) % (unsigned) base; \ 3896ae6ea0SThomas Gleixner n = ((unsigned long) n) / (unsigned) base; \ 3996ae6ea0SThomas Gleixner __res; }) 4096ae6ea0SThomas Gleixner 4196ae6ea0SThomas Gleixner static char *number(char *str, long num, int base, int size, int precision, 4296ae6ea0SThomas Gleixner int type) 4396ae6ea0SThomas Gleixner { 449b706aeeSDenys Vlasenko /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 459b706aeeSDenys Vlasenko static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 469b706aeeSDenys Vlasenko 479b706aeeSDenys Vlasenko char tmp[66]; 489b706aeeSDenys Vlasenko char c, sign, locase; 4996ae6ea0SThomas Gleixner int i; 5096ae6ea0SThomas Gleixner 519b706aeeSDenys Vlasenko /* locase = 0 or 0x20. ORing digits or letters with 'locase' 529b706aeeSDenys Vlasenko * produces same digits or (maybe lowercased) letters */ 539b706aeeSDenys Vlasenko locase = (type & SMALL); 5496ae6ea0SThomas Gleixner if (type & LEFT) 5596ae6ea0SThomas Gleixner type &= ~ZEROPAD; 565b8fafcaSDan Carpenter if (base < 2 || base > 16) 577fafd91dSHarvey Harrison return NULL; 5896ae6ea0SThomas Gleixner c = (type & ZEROPAD) ? '0' : ' '; 5996ae6ea0SThomas Gleixner sign = 0; 6096ae6ea0SThomas Gleixner if (type & SIGN) { 6196ae6ea0SThomas Gleixner if (num < 0) { 6296ae6ea0SThomas Gleixner sign = '-'; 6396ae6ea0SThomas Gleixner num = -num; 6496ae6ea0SThomas Gleixner size--; 6596ae6ea0SThomas Gleixner } else if (type & PLUS) { 6696ae6ea0SThomas Gleixner sign = '+'; 6796ae6ea0SThomas Gleixner size--; 6896ae6ea0SThomas Gleixner } else if (type & SPACE) { 6996ae6ea0SThomas Gleixner sign = ' '; 7096ae6ea0SThomas Gleixner size--; 7196ae6ea0SThomas Gleixner } 7296ae6ea0SThomas Gleixner } 7396ae6ea0SThomas Gleixner if (type & SPECIAL) { 7496ae6ea0SThomas Gleixner if (base == 16) 7596ae6ea0SThomas Gleixner size -= 2; 7696ae6ea0SThomas Gleixner else if (base == 8) 7796ae6ea0SThomas Gleixner size--; 7896ae6ea0SThomas Gleixner } 7996ae6ea0SThomas Gleixner i = 0; 8096ae6ea0SThomas Gleixner if (num == 0) 8196ae6ea0SThomas Gleixner tmp[i++] = '0'; 8296ae6ea0SThomas Gleixner else 8396ae6ea0SThomas Gleixner while (num != 0) 84f4ed2877SYinghai Lu tmp[i++] = (digits[__do_div(num, base)] | locase); 8596ae6ea0SThomas Gleixner if (i > precision) 8696ae6ea0SThomas Gleixner precision = i; 8796ae6ea0SThomas Gleixner size -= precision; 8896ae6ea0SThomas Gleixner if (!(type & (ZEROPAD + LEFT))) 8996ae6ea0SThomas Gleixner while (size-- > 0) 9096ae6ea0SThomas Gleixner *str++ = ' '; 9196ae6ea0SThomas Gleixner if (sign) 9296ae6ea0SThomas Gleixner *str++ = sign; 9396ae6ea0SThomas Gleixner if (type & SPECIAL) { 9496ae6ea0SThomas Gleixner if (base == 8) 9596ae6ea0SThomas Gleixner *str++ = '0'; 9696ae6ea0SThomas Gleixner else if (base == 16) { 9796ae6ea0SThomas Gleixner *str++ = '0'; 989b706aeeSDenys Vlasenko *str++ = ('X' | locase); 9996ae6ea0SThomas Gleixner } 10096ae6ea0SThomas Gleixner } 10196ae6ea0SThomas Gleixner if (!(type & LEFT)) 10296ae6ea0SThomas Gleixner while (size-- > 0) 10396ae6ea0SThomas Gleixner *str++ = c; 10496ae6ea0SThomas Gleixner while (i < precision--) 10596ae6ea0SThomas Gleixner *str++ = '0'; 10696ae6ea0SThomas Gleixner while (i-- > 0) 10796ae6ea0SThomas Gleixner *str++ = tmp[i]; 10896ae6ea0SThomas Gleixner while (size-- > 0) 10996ae6ea0SThomas Gleixner *str++ = ' '; 11096ae6ea0SThomas Gleixner return str; 11196ae6ea0SThomas Gleixner } 11296ae6ea0SThomas Gleixner 11396ae6ea0SThomas Gleixner int vsprintf(char *buf, const char *fmt, va_list args) 11496ae6ea0SThomas Gleixner { 11596ae6ea0SThomas Gleixner int len; 11696ae6ea0SThomas Gleixner unsigned long num; 11796ae6ea0SThomas Gleixner int i, base; 11896ae6ea0SThomas Gleixner char *str; 11996ae6ea0SThomas Gleixner const char *s; 12096ae6ea0SThomas Gleixner 12196ae6ea0SThomas Gleixner int flags; /* flags to number() */ 12296ae6ea0SThomas Gleixner 12396ae6ea0SThomas Gleixner int field_width; /* width of output field */ 12496ae6ea0SThomas Gleixner int precision; /* min. # of digits for integers; max 12596ae6ea0SThomas Gleixner number of chars for from string */ 12696ae6ea0SThomas Gleixner int qualifier; /* 'h', 'l', or 'L' for integer fields */ 12796ae6ea0SThomas Gleixner 12896ae6ea0SThomas Gleixner for (str = buf; *fmt; ++fmt) { 12996ae6ea0SThomas Gleixner if (*fmt != '%') { 13096ae6ea0SThomas Gleixner *str++ = *fmt; 13196ae6ea0SThomas Gleixner continue; 13296ae6ea0SThomas Gleixner } 13396ae6ea0SThomas Gleixner 13496ae6ea0SThomas Gleixner /* process flags */ 13596ae6ea0SThomas Gleixner flags = 0; 13696ae6ea0SThomas Gleixner repeat: 13796ae6ea0SThomas Gleixner ++fmt; /* this also skips first '%' */ 13896ae6ea0SThomas Gleixner switch (*fmt) { 13996ae6ea0SThomas Gleixner case '-': 14096ae6ea0SThomas Gleixner flags |= LEFT; 14196ae6ea0SThomas Gleixner goto repeat; 14296ae6ea0SThomas Gleixner case '+': 14396ae6ea0SThomas Gleixner flags |= PLUS; 14496ae6ea0SThomas Gleixner goto repeat; 14596ae6ea0SThomas Gleixner case ' ': 14696ae6ea0SThomas Gleixner flags |= SPACE; 14796ae6ea0SThomas Gleixner goto repeat; 14896ae6ea0SThomas Gleixner case '#': 14996ae6ea0SThomas Gleixner flags |= SPECIAL; 15096ae6ea0SThomas Gleixner goto repeat; 15196ae6ea0SThomas Gleixner case '0': 15296ae6ea0SThomas Gleixner flags |= ZEROPAD; 15396ae6ea0SThomas Gleixner goto repeat; 15496ae6ea0SThomas Gleixner } 15596ae6ea0SThomas Gleixner 15696ae6ea0SThomas Gleixner /* get field width */ 15796ae6ea0SThomas Gleixner field_width = -1; 15896ae6ea0SThomas Gleixner if (isdigit(*fmt)) 15996ae6ea0SThomas Gleixner field_width = skip_atoi(&fmt); 16096ae6ea0SThomas Gleixner else if (*fmt == '*') { 16196ae6ea0SThomas Gleixner ++fmt; 16296ae6ea0SThomas Gleixner /* it's the next argument */ 16396ae6ea0SThomas Gleixner field_width = va_arg(args, int); 16496ae6ea0SThomas Gleixner if (field_width < 0) { 16596ae6ea0SThomas Gleixner field_width = -field_width; 16696ae6ea0SThomas Gleixner flags |= LEFT; 16796ae6ea0SThomas Gleixner } 16896ae6ea0SThomas Gleixner } 16996ae6ea0SThomas Gleixner 17096ae6ea0SThomas Gleixner /* get the precision */ 17196ae6ea0SThomas Gleixner precision = -1; 17296ae6ea0SThomas Gleixner if (*fmt == '.') { 17396ae6ea0SThomas Gleixner ++fmt; 17496ae6ea0SThomas Gleixner if (isdigit(*fmt)) 17596ae6ea0SThomas Gleixner precision = skip_atoi(&fmt); 17696ae6ea0SThomas Gleixner else if (*fmt == '*') { 17796ae6ea0SThomas Gleixner ++fmt; 17896ae6ea0SThomas Gleixner /* it's the next argument */ 17996ae6ea0SThomas Gleixner precision = va_arg(args, int); 18096ae6ea0SThomas Gleixner } 18196ae6ea0SThomas Gleixner if (precision < 0) 18296ae6ea0SThomas Gleixner precision = 0; 18396ae6ea0SThomas Gleixner } 18496ae6ea0SThomas Gleixner 18596ae6ea0SThomas Gleixner /* get the conversion qualifier */ 18696ae6ea0SThomas Gleixner qualifier = -1; 18796ae6ea0SThomas Gleixner if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 18896ae6ea0SThomas Gleixner qualifier = *fmt; 18996ae6ea0SThomas Gleixner ++fmt; 19096ae6ea0SThomas Gleixner } 19196ae6ea0SThomas Gleixner 19296ae6ea0SThomas Gleixner /* default base */ 19396ae6ea0SThomas Gleixner base = 10; 19496ae6ea0SThomas Gleixner 19596ae6ea0SThomas Gleixner switch (*fmt) { 19696ae6ea0SThomas Gleixner case 'c': 19796ae6ea0SThomas Gleixner if (!(flags & LEFT)) 19896ae6ea0SThomas Gleixner while (--field_width > 0) 19996ae6ea0SThomas Gleixner *str++ = ' '; 20096ae6ea0SThomas Gleixner *str++ = (unsigned char)va_arg(args, int); 20196ae6ea0SThomas Gleixner while (--field_width > 0) 20296ae6ea0SThomas Gleixner *str++ = ' '; 20396ae6ea0SThomas Gleixner continue; 20496ae6ea0SThomas Gleixner 20596ae6ea0SThomas Gleixner case 's': 20696ae6ea0SThomas Gleixner s = va_arg(args, char *); 20796ae6ea0SThomas Gleixner len = strnlen(s, precision); 20896ae6ea0SThomas Gleixner 20996ae6ea0SThomas Gleixner if (!(flags & LEFT)) 21096ae6ea0SThomas Gleixner while (len < field_width--) 21196ae6ea0SThomas Gleixner *str++ = ' '; 21296ae6ea0SThomas Gleixner for (i = 0; i < len; ++i) 21396ae6ea0SThomas Gleixner *str++ = *s++; 21496ae6ea0SThomas Gleixner while (len < field_width--) 21596ae6ea0SThomas Gleixner *str++ = ' '; 21696ae6ea0SThomas Gleixner continue; 21796ae6ea0SThomas Gleixner 21896ae6ea0SThomas Gleixner case 'p': 21996ae6ea0SThomas Gleixner if (field_width == -1) { 22096ae6ea0SThomas Gleixner field_width = 2 * sizeof(void *); 22196ae6ea0SThomas Gleixner flags |= ZEROPAD; 22296ae6ea0SThomas Gleixner } 22396ae6ea0SThomas Gleixner str = number(str, 22496ae6ea0SThomas Gleixner (unsigned long)va_arg(args, void *), 16, 22596ae6ea0SThomas Gleixner field_width, precision, flags); 22696ae6ea0SThomas Gleixner continue; 22796ae6ea0SThomas Gleixner 22896ae6ea0SThomas Gleixner case 'n': 22996ae6ea0SThomas Gleixner if (qualifier == 'l') { 23096ae6ea0SThomas Gleixner long *ip = va_arg(args, long *); 23196ae6ea0SThomas Gleixner *ip = (str - buf); 23296ae6ea0SThomas Gleixner } else { 23396ae6ea0SThomas Gleixner int *ip = va_arg(args, int *); 23496ae6ea0SThomas Gleixner *ip = (str - buf); 23596ae6ea0SThomas Gleixner } 23696ae6ea0SThomas Gleixner continue; 23796ae6ea0SThomas Gleixner 23896ae6ea0SThomas Gleixner case '%': 23996ae6ea0SThomas Gleixner *str++ = '%'; 24096ae6ea0SThomas Gleixner continue; 24196ae6ea0SThomas Gleixner 24296ae6ea0SThomas Gleixner /* integer number formats - set up the flags and "break" */ 24396ae6ea0SThomas Gleixner case 'o': 24496ae6ea0SThomas Gleixner base = 8; 24596ae6ea0SThomas Gleixner break; 24696ae6ea0SThomas Gleixner 24796ae6ea0SThomas Gleixner case 'x': 2489b706aeeSDenys Vlasenko flags |= SMALL; 2499b706aeeSDenys Vlasenko case 'X': 25096ae6ea0SThomas Gleixner base = 16; 25196ae6ea0SThomas Gleixner break; 25296ae6ea0SThomas Gleixner 25396ae6ea0SThomas Gleixner case 'd': 25496ae6ea0SThomas Gleixner case 'i': 25596ae6ea0SThomas Gleixner flags |= SIGN; 25696ae6ea0SThomas Gleixner case 'u': 25796ae6ea0SThomas Gleixner break; 25896ae6ea0SThomas Gleixner 25996ae6ea0SThomas Gleixner default: 26096ae6ea0SThomas Gleixner *str++ = '%'; 26196ae6ea0SThomas Gleixner if (*fmt) 26296ae6ea0SThomas Gleixner *str++ = *fmt; 26396ae6ea0SThomas Gleixner else 26496ae6ea0SThomas Gleixner --fmt; 26596ae6ea0SThomas Gleixner continue; 26696ae6ea0SThomas Gleixner } 26796ae6ea0SThomas Gleixner if (qualifier == 'l') 26896ae6ea0SThomas Gleixner num = va_arg(args, unsigned long); 26996ae6ea0SThomas Gleixner else if (qualifier == 'h') { 27096ae6ea0SThomas Gleixner num = (unsigned short)va_arg(args, int); 27196ae6ea0SThomas Gleixner if (flags & SIGN) 27296ae6ea0SThomas Gleixner num = (short)num; 27396ae6ea0SThomas Gleixner } else if (flags & SIGN) 27496ae6ea0SThomas Gleixner num = va_arg(args, int); 27596ae6ea0SThomas Gleixner else 27696ae6ea0SThomas Gleixner num = va_arg(args, unsigned int); 27796ae6ea0SThomas Gleixner str = number(str, num, base, field_width, precision, flags); 27896ae6ea0SThomas Gleixner } 27996ae6ea0SThomas Gleixner *str = '\0'; 28096ae6ea0SThomas Gleixner return str - buf; 28196ae6ea0SThomas Gleixner } 28296ae6ea0SThomas Gleixner 28396ae6ea0SThomas Gleixner int sprintf(char *buf, const char *fmt, ...) 28496ae6ea0SThomas Gleixner { 28596ae6ea0SThomas Gleixner va_list args; 28696ae6ea0SThomas Gleixner int i; 28796ae6ea0SThomas Gleixner 28896ae6ea0SThomas Gleixner va_start(args, fmt); 28996ae6ea0SThomas Gleixner i = vsprintf(buf, fmt, args); 29096ae6ea0SThomas Gleixner va_end(args); 29196ae6ea0SThomas Gleixner return i; 29296ae6ea0SThomas Gleixner } 29396ae6ea0SThomas Gleixner 29496ae6ea0SThomas Gleixner int printf(const char *fmt, ...) 29596ae6ea0SThomas Gleixner { 29696ae6ea0SThomas Gleixner char printf_buf[1024]; 29796ae6ea0SThomas Gleixner va_list args; 29896ae6ea0SThomas Gleixner int printed; 29996ae6ea0SThomas Gleixner 30096ae6ea0SThomas Gleixner va_start(args, fmt); 30196ae6ea0SThomas Gleixner printed = vsprintf(printf_buf, fmt, args); 30296ae6ea0SThomas Gleixner va_end(args); 30396ae6ea0SThomas Gleixner 30496ae6ea0SThomas Gleixner puts(printf_buf); 30596ae6ea0SThomas Gleixner 30696ae6ea0SThomas Gleixner return printed; 30796ae6ea0SThomas Gleixner } 308