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