1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
266a45dd3SPaul Mackerras /*
366a45dd3SPaul Mackerras * Copyright (C) Paul Mackerras 1997.
466a45dd3SPaul Mackerras */
566a45dd3SPaul Mackerras #include <stdarg.h>
666a45dd3SPaul Mackerras #include <stddef.h>
766a45dd3SPaul Mackerras #include "string.h"
866a45dd3SPaul Mackerras #include "stdio.h"
9b2c5f619SMark A. Greer #include "ops.h"
1066a45dd3SPaul Mackerras
strnlen(const char * s,size_t count)1166a45dd3SPaul Mackerras size_t strnlen(const char * s, size_t count)
1266a45dd3SPaul Mackerras {
1366a45dd3SPaul Mackerras const char *sc;
1466a45dd3SPaul Mackerras
1566a45dd3SPaul Mackerras for (sc = s; count-- && *sc != '\0'; ++sc)
1666a45dd3SPaul Mackerras /* nothing */;
1766a45dd3SPaul Mackerras return sc - s;
1866a45dd3SPaul Mackerras }
1966a45dd3SPaul Mackerras
strrchr(const char * s,int c)20a54b81eaSRob Herring char *strrchr(const char *s, int c)
21a54b81eaSRob Herring {
22a54b81eaSRob Herring const char *last = NULL;
23a54b81eaSRob Herring do {
24a54b81eaSRob Herring if (*s == (char)c)
25a54b81eaSRob Herring last = s;
26a54b81eaSRob Herring } while (*s++);
27a54b81eaSRob Herring return (char *)last;
28a54b81eaSRob Herring }
29a54b81eaSRob Herring
30f4bce2f7SCédric Le Goater #ifdef __powerpc64__
31f4bce2f7SCédric Le Goater
32f4bce2f7SCédric Le Goater # define do_div(n, base) ({ \
33f4bce2f7SCédric Le Goater unsigned int __base = (base); \
34f4bce2f7SCédric Le Goater unsigned int __rem; \
35f4bce2f7SCédric Le Goater __rem = ((unsigned long long)(n)) % __base; \
36f4bce2f7SCédric Le Goater (n) = ((unsigned long long)(n)) / __base; \
37f4bce2f7SCédric Le Goater __rem; \
38f4bce2f7SCédric Le Goater })
39f4bce2f7SCédric Le Goater
40f4bce2f7SCédric Le Goater #else
41f4bce2f7SCédric Le Goater
4266a45dd3SPaul Mackerras extern unsigned int __div64_32(unsigned long long *dividend,
4366a45dd3SPaul Mackerras unsigned int divisor);
4466a45dd3SPaul Mackerras
4566a45dd3SPaul Mackerras /* The unnecessary pointer compare is there
4666a45dd3SPaul Mackerras * to check for type safety (n must be 64bit)
4766a45dd3SPaul Mackerras */
4866a45dd3SPaul Mackerras # define do_div(n,base) ({ \
4966a45dd3SPaul Mackerras unsigned int __base = (base); \
5066a45dd3SPaul Mackerras unsigned int __rem; \
5166a45dd3SPaul Mackerras (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
5266a45dd3SPaul Mackerras if (((n) >> 32) == 0) { \
5366a45dd3SPaul Mackerras __rem = (unsigned int)(n) % __base; \
5466a45dd3SPaul Mackerras (n) = (unsigned int)(n) / __base; \
5566a45dd3SPaul Mackerras } else \
5666a45dd3SPaul Mackerras __rem = __div64_32(&(n), __base); \
5766a45dd3SPaul Mackerras __rem; \
5866a45dd3SPaul Mackerras })
5966a45dd3SPaul Mackerras
60f4bce2f7SCédric Le Goater #endif /* __powerpc64__ */
61f4bce2f7SCédric Le Goater
skip_atoi(const char ** s)6266a45dd3SPaul Mackerras static int skip_atoi(const char **s)
6366a45dd3SPaul Mackerras {
6466a45dd3SPaul Mackerras int i, c;
6566a45dd3SPaul Mackerras
6666a45dd3SPaul Mackerras for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
6766a45dd3SPaul Mackerras i = i*10 + c - '0';
6866a45dd3SPaul Mackerras return i;
6966a45dd3SPaul Mackerras }
7066a45dd3SPaul Mackerras
7166a45dd3SPaul Mackerras #define ZEROPAD 1 /* pad with zero */
7266a45dd3SPaul Mackerras #define SIGN 2 /* unsigned/signed long */
7366a45dd3SPaul Mackerras #define PLUS 4 /* show plus */
7466a45dd3SPaul Mackerras #define SPACE 8 /* space if plus */
7566a45dd3SPaul Mackerras #define LEFT 16 /* left justified */
7666a45dd3SPaul Mackerras #define SPECIAL 32 /* 0x */
7766a45dd3SPaul Mackerras #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
7866a45dd3SPaul Mackerras
number(char * str,unsigned long long num,int base,int size,int precision,int type)7966a45dd3SPaul Mackerras static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
8066a45dd3SPaul Mackerras {
8166a45dd3SPaul Mackerras char c,sign,tmp[66];
8266a45dd3SPaul Mackerras const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
8366a45dd3SPaul Mackerras int i;
8466a45dd3SPaul Mackerras
8566a45dd3SPaul Mackerras if (type & LARGE)
8666a45dd3SPaul Mackerras digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
8766a45dd3SPaul Mackerras if (type & LEFT)
8866a45dd3SPaul Mackerras type &= ~ZEROPAD;
8966a45dd3SPaul Mackerras if (base < 2 || base > 36)
9066a45dd3SPaul Mackerras return 0;
9166a45dd3SPaul Mackerras c = (type & ZEROPAD) ? '0' : ' ';
9266a45dd3SPaul Mackerras sign = 0;
9366a45dd3SPaul Mackerras if (type & SIGN) {
9466a45dd3SPaul Mackerras if ((signed long long)num < 0) {
9566a45dd3SPaul Mackerras sign = '-';
9666a45dd3SPaul Mackerras num = - (signed long long)num;
9766a45dd3SPaul Mackerras size--;
9866a45dd3SPaul Mackerras } else if (type & PLUS) {
9966a45dd3SPaul Mackerras sign = '+';
10066a45dd3SPaul Mackerras size--;
10166a45dd3SPaul Mackerras } else if (type & SPACE) {
10266a45dd3SPaul Mackerras sign = ' ';
10366a45dd3SPaul Mackerras size--;
10466a45dd3SPaul Mackerras }
10566a45dd3SPaul Mackerras }
10666a45dd3SPaul Mackerras if (type & SPECIAL) {
10766a45dd3SPaul Mackerras if (base == 16)
10866a45dd3SPaul Mackerras size -= 2;
10966a45dd3SPaul Mackerras else if (base == 8)
11066a45dd3SPaul Mackerras size--;
11166a45dd3SPaul Mackerras }
11266a45dd3SPaul Mackerras i = 0;
11366a45dd3SPaul Mackerras if (num == 0)
11466a45dd3SPaul Mackerras tmp[i++]='0';
11566a45dd3SPaul Mackerras else while (num != 0) {
11666a45dd3SPaul Mackerras tmp[i++] = digits[do_div(num, base)];
11766a45dd3SPaul Mackerras }
11866a45dd3SPaul Mackerras if (i > precision)
11966a45dd3SPaul Mackerras precision = i;
12066a45dd3SPaul Mackerras size -= precision;
12166a45dd3SPaul Mackerras if (!(type&(ZEROPAD+LEFT)))
12266a45dd3SPaul Mackerras while(size-->0)
12366a45dd3SPaul Mackerras *str++ = ' ';
12466a45dd3SPaul Mackerras if (sign)
12566a45dd3SPaul Mackerras *str++ = sign;
12666a45dd3SPaul Mackerras if (type & SPECIAL) {
12766a45dd3SPaul Mackerras if (base==8)
12866a45dd3SPaul Mackerras *str++ = '0';
12966a45dd3SPaul Mackerras else if (base==16) {
13066a45dd3SPaul Mackerras *str++ = '0';
13166a45dd3SPaul Mackerras *str++ = digits[33];
13266a45dd3SPaul Mackerras }
13366a45dd3SPaul Mackerras }
13466a45dd3SPaul Mackerras if (!(type & LEFT))
13566a45dd3SPaul Mackerras while (size-- > 0)
13666a45dd3SPaul Mackerras *str++ = c;
13766a45dd3SPaul Mackerras while (i < precision--)
13866a45dd3SPaul Mackerras *str++ = '0';
13966a45dd3SPaul Mackerras while (i-- > 0)
14066a45dd3SPaul Mackerras *str++ = tmp[i];
14166a45dd3SPaul Mackerras while (size-- > 0)
14266a45dd3SPaul Mackerras *str++ = ' ';
14366a45dd3SPaul Mackerras return str;
14466a45dd3SPaul Mackerras }
14566a45dd3SPaul Mackerras
vsprintf(char * buf,const char * fmt,va_list args)14666a45dd3SPaul Mackerras int vsprintf(char *buf, const char *fmt, va_list args)
14766a45dd3SPaul Mackerras {
14866a45dd3SPaul Mackerras int len;
14966a45dd3SPaul Mackerras unsigned long long num;
15066a45dd3SPaul Mackerras int i, base;
15166a45dd3SPaul Mackerras char * str;
15266a45dd3SPaul Mackerras const char *s;
15366a45dd3SPaul Mackerras
15466a45dd3SPaul Mackerras int flags; /* flags to number() */
15566a45dd3SPaul Mackerras
15666a45dd3SPaul Mackerras int field_width; /* width of output field */
15766a45dd3SPaul Mackerras int precision; /* min. # of digits for integers; max
15866a45dd3SPaul Mackerras number of chars for from string */
15966a45dd3SPaul Mackerras int qualifier; /* 'h', 'l', or 'L' for integer fields */
16066a45dd3SPaul Mackerras /* 'z' support added 23/7/1999 S.H. */
16166a45dd3SPaul Mackerras /* 'z' changed to 'Z' --davidm 1/25/99 */
16266a45dd3SPaul Mackerras
16366a45dd3SPaul Mackerras
16466a45dd3SPaul Mackerras for (str=buf ; *fmt ; ++fmt) {
16566a45dd3SPaul Mackerras if (*fmt != '%') {
16666a45dd3SPaul Mackerras *str++ = *fmt;
16766a45dd3SPaul Mackerras continue;
16866a45dd3SPaul Mackerras }
16966a45dd3SPaul Mackerras
17066a45dd3SPaul Mackerras /* process flags */
17166a45dd3SPaul Mackerras flags = 0;
17266a45dd3SPaul Mackerras repeat:
17366a45dd3SPaul Mackerras ++fmt; /* this also skips first '%' */
17466a45dd3SPaul Mackerras switch (*fmt) {
17566a45dd3SPaul Mackerras case '-': flags |= LEFT; goto repeat;
17666a45dd3SPaul Mackerras case '+': flags |= PLUS; goto repeat;
17766a45dd3SPaul Mackerras case ' ': flags |= SPACE; goto repeat;
17866a45dd3SPaul Mackerras case '#': flags |= SPECIAL; goto repeat;
17966a45dd3SPaul Mackerras case '0': flags |= ZEROPAD; goto repeat;
18066a45dd3SPaul Mackerras }
18166a45dd3SPaul Mackerras
18266a45dd3SPaul Mackerras /* get field width */
18366a45dd3SPaul Mackerras field_width = -1;
18466a45dd3SPaul Mackerras if ('0' <= *fmt && *fmt <= '9')
18566a45dd3SPaul Mackerras field_width = skip_atoi(&fmt);
18666a45dd3SPaul Mackerras else if (*fmt == '*') {
18766a45dd3SPaul Mackerras ++fmt;
18866a45dd3SPaul Mackerras /* it's the next argument */
18966a45dd3SPaul Mackerras field_width = va_arg(args, int);
19066a45dd3SPaul Mackerras if (field_width < 0) {
19166a45dd3SPaul Mackerras field_width = -field_width;
19266a45dd3SPaul Mackerras flags |= LEFT;
19366a45dd3SPaul Mackerras }
19466a45dd3SPaul Mackerras }
19566a45dd3SPaul Mackerras
19666a45dd3SPaul Mackerras /* get the precision */
19766a45dd3SPaul Mackerras precision = -1;
19866a45dd3SPaul Mackerras if (*fmt == '.') {
19966a45dd3SPaul Mackerras ++fmt;
20066a45dd3SPaul Mackerras if ('0' <= *fmt && *fmt <= '9')
20166a45dd3SPaul Mackerras precision = skip_atoi(&fmt);
20266a45dd3SPaul Mackerras else if (*fmt == '*') {
20366a45dd3SPaul Mackerras ++fmt;
20466a45dd3SPaul Mackerras /* it's the next argument */
20566a45dd3SPaul Mackerras precision = va_arg(args, int);
20666a45dd3SPaul Mackerras }
20766a45dd3SPaul Mackerras if (precision < 0)
20866a45dd3SPaul Mackerras precision = 0;
20966a45dd3SPaul Mackerras }
21066a45dd3SPaul Mackerras
21166a45dd3SPaul Mackerras /* get the conversion qualifier */
21266a45dd3SPaul Mackerras qualifier = -1;
2130aa97d6eSGeoff Levand if (*fmt == 'l' && *(fmt + 1) == 'l') {
2140aa97d6eSGeoff Levand qualifier = 'q';
2150aa97d6eSGeoff Levand fmt += 2;
2160aa97d6eSGeoff Levand } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
2170aa97d6eSGeoff Levand || *fmt == 'Z') {
21866a45dd3SPaul Mackerras qualifier = *fmt;
21966a45dd3SPaul Mackerras ++fmt;
22066a45dd3SPaul Mackerras }
22166a45dd3SPaul Mackerras
22266a45dd3SPaul Mackerras /* default base */
22366a45dd3SPaul Mackerras base = 10;
22466a45dd3SPaul Mackerras
22566a45dd3SPaul Mackerras switch (*fmt) {
22666a45dd3SPaul Mackerras case 'c':
22766a45dd3SPaul Mackerras if (!(flags & LEFT))
22866a45dd3SPaul Mackerras while (--field_width > 0)
22966a45dd3SPaul Mackerras *str++ = ' ';
23066a45dd3SPaul Mackerras *str++ = (unsigned char) va_arg(args, int);
23166a45dd3SPaul Mackerras while (--field_width > 0)
23266a45dd3SPaul Mackerras *str++ = ' ';
23366a45dd3SPaul Mackerras continue;
23466a45dd3SPaul Mackerras
23566a45dd3SPaul Mackerras case 's':
23666a45dd3SPaul Mackerras s = va_arg(args, char *);
23766a45dd3SPaul Mackerras if (!s)
23866a45dd3SPaul Mackerras s = "<NULL>";
23966a45dd3SPaul Mackerras
24066a45dd3SPaul Mackerras len = strnlen(s, precision);
24166a45dd3SPaul Mackerras
24266a45dd3SPaul Mackerras if (!(flags & LEFT))
24366a45dd3SPaul Mackerras while (len < field_width--)
24466a45dd3SPaul Mackerras *str++ = ' ';
24566a45dd3SPaul Mackerras for (i = 0; i < len; ++i)
24666a45dd3SPaul Mackerras *str++ = *s++;
24766a45dd3SPaul Mackerras while (len < field_width--)
24866a45dd3SPaul Mackerras *str++ = ' ';
24966a45dd3SPaul Mackerras continue;
25066a45dd3SPaul Mackerras
25166a45dd3SPaul Mackerras case 'p':
25266a45dd3SPaul Mackerras if (field_width == -1) {
25366a45dd3SPaul Mackerras field_width = 2*sizeof(void *);
25466a45dd3SPaul Mackerras flags |= ZEROPAD;
25566a45dd3SPaul Mackerras }
25666a45dd3SPaul Mackerras str = number(str,
25766a45dd3SPaul Mackerras (unsigned long) va_arg(args, void *), 16,
25866a45dd3SPaul Mackerras field_width, precision, flags);
25966a45dd3SPaul Mackerras continue;
26066a45dd3SPaul Mackerras
26166a45dd3SPaul Mackerras
26266a45dd3SPaul Mackerras case 'n':
26366a45dd3SPaul Mackerras if (qualifier == 'l') {
26466a45dd3SPaul Mackerras long * ip = va_arg(args, long *);
26566a45dd3SPaul Mackerras *ip = (str - buf);
26666a45dd3SPaul Mackerras } else if (qualifier == 'Z') {
26766a45dd3SPaul Mackerras size_t * ip = va_arg(args, size_t *);
26866a45dd3SPaul Mackerras *ip = (str - buf);
26966a45dd3SPaul Mackerras } else {
27066a45dd3SPaul Mackerras int * ip = va_arg(args, int *);
27166a45dd3SPaul Mackerras *ip = (str - buf);
27266a45dd3SPaul Mackerras }
27366a45dd3SPaul Mackerras continue;
27466a45dd3SPaul Mackerras
27566a45dd3SPaul Mackerras case '%':
27666a45dd3SPaul Mackerras *str++ = '%';
27766a45dd3SPaul Mackerras continue;
27866a45dd3SPaul Mackerras
27966a45dd3SPaul Mackerras /* integer number formats - set up the flags and "break" */
28066a45dd3SPaul Mackerras case 'o':
28166a45dd3SPaul Mackerras base = 8;
28266a45dd3SPaul Mackerras break;
28366a45dd3SPaul Mackerras
28466a45dd3SPaul Mackerras case 'X':
28566a45dd3SPaul Mackerras flags |= LARGE;
28666a45dd3SPaul Mackerras case 'x':
28766a45dd3SPaul Mackerras base = 16;
28866a45dd3SPaul Mackerras break;
28966a45dd3SPaul Mackerras
29066a45dd3SPaul Mackerras case 'd':
29166a45dd3SPaul Mackerras case 'i':
29266a45dd3SPaul Mackerras flags |= SIGN;
29366a45dd3SPaul Mackerras case 'u':
29466a45dd3SPaul Mackerras break;
29566a45dd3SPaul Mackerras
29666a45dd3SPaul Mackerras default:
29766a45dd3SPaul Mackerras *str++ = '%';
29866a45dd3SPaul Mackerras if (*fmt)
29966a45dd3SPaul Mackerras *str++ = *fmt;
30066a45dd3SPaul Mackerras else
30166a45dd3SPaul Mackerras --fmt;
30266a45dd3SPaul Mackerras continue;
30366a45dd3SPaul Mackerras }
30466a45dd3SPaul Mackerras if (qualifier == 'l') {
30566a45dd3SPaul Mackerras num = va_arg(args, unsigned long);
30666a45dd3SPaul Mackerras if (flags & SIGN)
30766a45dd3SPaul Mackerras num = (signed long) num;
3080aa97d6eSGeoff Levand } else if (qualifier == 'q') {
3090aa97d6eSGeoff Levand num = va_arg(args, unsigned long long);
3100aa97d6eSGeoff Levand if (flags & SIGN)
3110aa97d6eSGeoff Levand num = (signed long long) num;
31266a45dd3SPaul Mackerras } else if (qualifier == 'Z') {
31366a45dd3SPaul Mackerras num = va_arg(args, size_t);
31466a45dd3SPaul Mackerras } else if (qualifier == 'h') {
31566a45dd3SPaul Mackerras num = (unsigned short) va_arg(args, int);
31666a45dd3SPaul Mackerras if (flags & SIGN)
31766a45dd3SPaul Mackerras num = (signed short) num;
31866a45dd3SPaul Mackerras } else {
31966a45dd3SPaul Mackerras num = va_arg(args, unsigned int);
32066a45dd3SPaul Mackerras if (flags & SIGN)
32166a45dd3SPaul Mackerras num = (signed int) num;
32266a45dd3SPaul Mackerras }
32366a45dd3SPaul Mackerras str = number(str, num, base, field_width, precision, flags);
32466a45dd3SPaul Mackerras }
32566a45dd3SPaul Mackerras *str = '\0';
32666a45dd3SPaul Mackerras return str-buf;
32766a45dd3SPaul Mackerras }
32866a45dd3SPaul Mackerras
sprintf(char * buf,const char * fmt,...)32966a45dd3SPaul Mackerras int sprintf(char * buf, const char *fmt, ...)
33066a45dd3SPaul Mackerras {
33166a45dd3SPaul Mackerras va_list args;
33266a45dd3SPaul Mackerras int i;
33366a45dd3SPaul Mackerras
33466a45dd3SPaul Mackerras va_start(args, fmt);
33566a45dd3SPaul Mackerras i=vsprintf(buf,fmt,args);
33666a45dd3SPaul Mackerras va_end(args);
33766a45dd3SPaul Mackerras return i;
33866a45dd3SPaul Mackerras }
33966a45dd3SPaul Mackerras
34066a45dd3SPaul Mackerras static char sprint_buf[1024];
34166a45dd3SPaul Mackerras
34266a45dd3SPaul Mackerras int
printf(const char * fmt,...)34366a45dd3SPaul Mackerras printf(const char *fmt, ...)
34466a45dd3SPaul Mackerras {
34566a45dd3SPaul Mackerras va_list args;
34666a45dd3SPaul Mackerras int n;
34766a45dd3SPaul Mackerras
34866a45dd3SPaul Mackerras va_start(args, fmt);
34966a45dd3SPaul Mackerras n = vsprintf(sprint_buf, fmt, args);
35066a45dd3SPaul Mackerras va_end(args);
351c888554bSMark A. Greer if (console_ops.write)
352b2c5f619SMark A. Greer console_ops.write(sprint_buf, n);
35366a45dd3SPaul Mackerras return n;
35466a45dd3SPaul Mackerras }
355