1 /*
2 * Copyright (C) 2015 Virtual Open Systems SAS
3 * Author: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
4 *
5 * printf based on implementation by Kevin Wolf <kwolf@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * SPDX-License-Identifier: GPL-2.0-only
12 */
13
14 #include "minilib.h"
15
16 typedef __builtin_va_list va_list;
17 #define va_start(ap, X) __builtin_va_start(ap, X)
18 #define va_arg(ap, type) __builtin_va_arg(ap, type)
19 #define va_end(ap) __builtin_va_end(ap)
20
print_str(char * s)21 static void print_str(char *s)
22 {
23 while (*s) {
24 __sys_outc(*s++);
25 }
26 }
27
print_num(unsigned long long value,int base)28 static void print_num(unsigned long long value, int base)
29 {
30 static const char digits[] = "0123456789abcdef";
31 char buf[32];
32 int i = sizeof(buf) - 2, j;
33
34 /* Set the buffer to 0. See problem of before. */
35 for (j = 0; j < 32; j++) {
36 buf[j] = 0;
37 }
38
39 do {
40 buf[i--] = digits[value % base];
41 value /= base;
42 } while (value);
43
44 print_str(&buf[i + 1]);
45 }
46
ml_printf(const char * fmt,...)47 void ml_printf(const char *fmt, ...)
48 {
49 va_list ap;
50 char *str;
51 int base;
52 int has_long;
53 int alt_form;
54 unsigned long long val;
55
56 va_start(ap, fmt);
57
58 for (; *fmt; fmt++) {
59 if (*fmt != '%') {
60 __sys_outc(*fmt);
61 continue;
62 }
63 fmt++;
64
65 if (*fmt == '#') {
66 fmt++;
67 alt_form = 1;
68 } else {
69 alt_form = 0;
70 }
71
72 if (*fmt == 'l') {
73 fmt++;
74 if (*fmt == 'l') {
75 fmt++;
76 has_long = 2;
77 } else {
78 has_long = 1;
79 }
80 } else {
81 has_long = 0;
82 }
83
84 switch (*fmt) {
85 case 'x':
86 case 'p':
87 base = 16;
88 goto convert_number;
89 case 'd':
90 case 'i':
91 case 'u':
92 base = 10;
93 goto convert_number;
94 case 'o':
95 base = 8;
96 goto convert_number;
97
98 convert_number:
99 switch (has_long) {
100 case 0:
101 val = va_arg(ap, unsigned int);
102 break;
103 case 1:
104 val = va_arg(ap, unsigned long);
105 break;
106 case 2:
107 val = va_arg(ap, unsigned long long);
108 break;
109 }
110
111 if (alt_form && base == 16) {
112 print_str("0x");
113 }
114
115 print_num(val, base);
116 break;
117
118 case 's':
119 str = va_arg(ap, char*);
120 print_str(str);
121 break;
122 case 'c':
123 __sys_outc(va_arg(ap, int));
124 break;
125 case '%':
126 __sys_outc(*fmt);
127 break;
128 default:
129 __sys_outc('%');
130 __sys_outc(*fmt);
131 break;
132 }
133 }
134
135 va_end(ap);
136 }
137