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