Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / qemu-palcode / printf.c
1 /* A reduced version of the printf function.
2
3    Copyright (C) 2011 Richard Henderson
4
5    This file is part of QEMU PALcode.
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 as published by
9    the Free Software Foundation; either version 2 of the License or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the text
15    of the GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; see the file COPYING.  If not see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include "console.h"
25
26 static int print_buf_pad(char *buf, int buflen, char *p, int width, int pad)
27 {
28   int len = buf + buflen - p;
29   int r = 0;
30
31   if (width > len)
32     {
33       *--p = pad;
34       len++;
35
36       while (width > buflen)
37         {
38           crb_puts(0, p, 1);
39           width--;
40           r++;
41         }
42       while (width > len)
43         *--p = pad, len++;
44     }
45
46   crb_puts(0, p, len);
47   return r + len;
48 }
49
50 static int print_decimal(unsigned long val, int width, int pad)
51 {
52   char buf[32];
53   char *p = buf + sizeof(buf);
54
55   if (val == 0)
56     *--p = '0';
57   else
58     {
59       do
60         {
61           unsigned long d, r;
62
63           /* Compiling with -Os results in a call to the division routine.
64              Do what the compiler ought to have done.  */
65           d = __builtin_alpha_umulh(val, 0xcccccccccccccccd);
66           d >>= 3;
67           r = val - (d * 10);
68
69           *--p = r + '0';
70           val = d;
71         }
72       while (val);
73     }
74
75   return print_buf_pad(buf, sizeof(buf), p, width, pad);
76 }
77
78 static int print_hex(unsigned long val, int width, char pad)
79 {
80   char buf[32];
81   char *p = buf + sizeof(buf);
82
83   if (val == 0)
84     *--p = '0';
85   else
86     {
87       do
88         {
89           int d = val % 16;
90           *--p = (d < 10 ? '0' : 'a' - 10) + d;
91           val /= 16;
92         }
93       while (val);
94     }
95
96   return print_buf_pad(buf, sizeof(buf), p, width, pad);
97 }
98
99 int printf(const char *fmt, ...)
100 {
101   va_list args;
102   unsigned long val;
103   int r = 0;
104
105   va_start(args, fmt);
106
107   for (; *fmt ; fmt++)
108     if (*fmt != '%')
109       {
110         crb_puts(0, fmt, 1);
111         r++;
112       }
113     else
114       {
115         const char *percent = fmt;
116         bool is_long = false;
117         char pad = ' ';
118         int width = 0;
119
120       restart:
121         switch (*++fmt)
122           {
123           case '%':
124             crb_puts(0, "%", 1);
125             r++;
126             break;
127
128           case 'l':
129             is_long = true;
130             goto restart;
131
132           case 'd':
133             if (is_long)
134               {
135                 long d = va_arg (args, long);
136                 if (d < 0)
137                   {
138                     crb_puts(0, "-", 1);
139                     d = -d;
140                   }
141                 val = d;
142               }
143             else
144               {
145                 int d = va_arg (args, int);
146                 if (d < 0)
147                   {
148                     crb_puts(0, "-", 1);
149                     d = -d;
150                     r++;
151                   }
152                 val = d;
153               }
154             goto do_unsigned;
155
156           case 'u':
157             if (is_long)
158               val = va_arg (args, unsigned long);
159             else
160               val = va_arg (args, unsigned int);
161
162           do_unsigned:
163             r += print_decimal (val, width, pad);
164             break;
165
166           case 'x':
167             if (is_long)
168               val = va_arg (args, unsigned long);
169             else
170               val = va_arg (args, unsigned int);
171             r += print_hex (val, width, pad);
172             break;
173
174           case 's':
175             {
176               const char *s = va_arg (args, const char *);
177               int len = strlen(s);
178               crb_puts(0, s, len);
179               r += len;
180             }
181             break;
182
183           case '0':
184             pad = '0';
185           case '1' ... '9':
186             width = *fmt - '0';
187             while (fmt[1] >= '0' && fmt[1] <= '9')
188               width = width * 10 + *++fmt - '0';
189             goto restart;
190
191           default:
192             {
193               int len = fmt - percent;
194               crb_puts(0, percent, len);
195               r += len;
196             }
197             break;
198           }
199       }
200
201   va_end(args);
202   return r;
203 }