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
skip_atoi(const char ** s)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
number(char * str,long num,int base,int size,int precision,int type)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
vsprintf(char * buf,const char * fmt,va_list args)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
sprintf(char * buf,const char * fmt,...)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
printf(const char * fmt,...)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