printf.c revision 8013:2dfcde2e9998
1/*
2 * Copyright (c) 2003, 2004
3 * The Regents of The University of Michigan
4 * All Rights Reserved
5 *
6 * This code is part of the M5 simulator, developed by Nathan Binkert,
7 * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
8 * from Ron Dreslinski, Dave Greene, Lisa Hsu, Ali Saidi, and Andrew
9 * Schultz.
10 *
11 * Permission is granted to use, copy, create derivative works and
12 * redistribute this software and such derivative works for any purpose,
13 * so long as the copyright notice above, this grant of permission, and
14 * the disclaimer below appear in all copies made; and so long as the
15 * name of The University of Michigan is not used in any advertising or
16 * publicity pertaining to the use or distribution of this software
17 * without specific, written prior authorization.
18 *
19 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
20 * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT
21 * WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR
22 * IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF
24 * THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES,
25 * INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
26 * DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION
27 * WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
29 */
30
31/*
32 * Copyright 1993 Hewlett-Packard Development Company, L.P.
33 *
34 * Permission is hereby granted, free of charge, to any person
35 * obtaining a copy of this software and associated documentation
36 * files (the "Software"), to deal in the Software without
37 * restriction, including without limitation the rights to use, copy,
38 * modify, merge, publish, distribute, sublicense, and/or sell copies
39 * of the Software, and to permit persons to whom the Software is
40 * furnished to do so, subject to the following conditions:
41 *
42 * The above copyright notice and this permission notice shall be
43 * included in all copies or substantial portions of the Software.
44 *
45 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
49 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
50 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
51 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52 * SOFTWARE.
53 */
54
55#include <sys/types.h>
56#include <stdarg.h>
57
58/* The string s is terminated by a '\0' */
59void
60PutString(const char *s)
61{
62    while (*s)
63        PutChar(*s++);
64}
65
66/* print c count times */
67void
68PutRepChar(char c, int count)
69{
70    while (count--)
71        PutChar(c);
72}
73
74/* put string reverse */
75void
76PutStringReverse(const char *s, int index)
77{
78    while (index-- > 0)
79        PutChar(s[index]);
80}
81
82/*
83 * prints value in radix, in a field width width, with fill
84 * character fill
85 * if radix is negative, print as signed quantity
86 * if width is negative, left justify
87 * if width is 0, use whatever is needed
88 * if fill is 0, use ' '
89 */
90void
91PutNumber(long value, int radix, int width, char fill)
92{
93    char buffer[40];
94    uint bufferindex = 0;
95    ulong uvalue;
96    ushort digit;
97    ushort left = 0;
98    ushort negative = 0;
99
100    if (fill == 0)
101        fill = ' ';
102
103    if (width < 0) {
104        width = -width;
105        left = 1;
106    }
107
108    if (width < 0 || width > 80)
109        width = 0;
110
111    if (radix < 0) {
112        radix = -radix;
113        if (value < 0) {
114            negative = 1;
115            value = -value;
116        }
117    }
118
119    switch (radix) {
120      case 8:
121      case 10:
122      case 16:
123        break;
124
125      default:
126        PutString("****");
127        return;
128    }
129
130    uvalue = value;
131
132    do {
133        if (radix != 16) {
134            digit = (ushort)(uvalue % radix);
135            uvalue /= radix;
136        } else {
137            digit = (ushort)(uvalue & 0xf);
138            uvalue = uvalue >> 4;
139        }
140        buffer[bufferindex] = digit + ((digit <= 9) ? '0' : ('A' - 10));
141        bufferindex += 1;
142    } while (uvalue != 0);
143
144  /* fill # ' ' and negative cannot happen at once */
145    if (negative) {
146        buffer[bufferindex] = '-';
147        bufferindex += 1;
148    }
149
150    if ((uint)width <= bufferindex) {
151        PutStringReverse(buffer, bufferindex);
152    } else {
153        width -= bufferindex;
154        if (!left)
155            PutRepChar(fill, width);
156        PutStringReverse(buffer, bufferindex);
157        if (left)
158            PutRepChar(fill, width);
159    }
160}
161
162ulong
163power(long base, long n)
164{
165    ulong p;
166
167    for (p = 1; n > 0; --n)
168        p = p * base;
169    return p;
170}
171
172void
173putFloat(double a, int fieldwidth, char fill)
174{
175    int i;
176    ulong b;
177
178    /*
179     *  Put out everything before the decimal place.
180     */
181    PutNumber(((ulong) a), 10, fieldwidth, fill);
182
183    /*
184     *  Output the decimal place.
185     */
186    PutChar('.' & 0x7f);
187
188    /*
189     *  Output the n digits after the decimal place.
190     */
191    for (i = 1; i < 6; i++) {
192        b = (ulong)(power(10, i) * (double)(a - (ulong) a));
193        PutChar((char)(b % 10) + '0');
194    }
195}
196
197const char *
198FormatItem(const char *f, va_list *ap)
199{
200    char c;
201    int fieldwidth = 0;
202    int leftjust = 0;
203    int radix = 0;
204    char fill = ' ';
205
206    if (*f == '0')
207        fill = '0';
208
209    while (c = *f++) {
210        if (c >= '0' && c <= '9') {
211            fieldwidth = (fieldwidth * 10) + (c - '0');
212        } else {
213            switch (c) {
214              case '\000':
215                return(--f);
216              case '%':
217                PutChar('%');
218                return(f);
219              case '-':
220                leftjust = 1;
221                break;
222              case 'c': {
223                  char a = (char)va_arg(*ap, int);
224
225                  if (leftjust)
226                      PutChar(a & 0x7f);
227                  if (fieldwidth > 0)
228                      PutRepChar(fill, fieldwidth - 1);
229                  if (!leftjust)
230                      PutChar(a & 0x7f);
231                  return(f);
232              }
233              case 's': {
234                  const char *a = va_arg(*ap, const char *);
235
236                  if (leftjust)
237                      PutString((const char *) a);
238                  if (fieldwidth > strlen((const char *) a))
239                      PutRepChar(fill, fieldwidth - strlen((const char *)a));
240                  if (!leftjust)
241                      PutString((const char *) a);
242                  return(f);
243              }
244              case 'd':
245                radix = -10;
246                break;
247              case 'u':
248                radix = 10;
249                break;
250              case 'x':
251                radix = 16;
252                break;
253              case 'X':
254                radix = 16;
255                break;
256              case 'o':
257                radix = 8;
258                break;
259              case 'f': {
260                  double a = va_arg(*ap, double);
261
262                  putFloat(a, fieldwidth, fill);
263                  return(f);
264              }
265              default:   /* unknown switch! */
266                radix = 3;
267                break;
268            }
269        }
270
271        if (radix)
272            break;
273    }
274
275    if (leftjust)
276        fieldwidth = -fieldwidth;
277
278    long a = va_arg(*ap, long);
279    PutNumber(a, radix, fieldwidth, fill);
280
281    return(f);
282}
283
284int
285printf(const char *f, ...)
286{
287    va_list ap;
288
289    va_start(ap, f);
290
291    while (*f) {
292        if (*f == '%')
293            f = FormatItem(f + 1, &ap);
294        else
295            PutChar(*f++);
296    }
297
298    if (*(f - 1) == '\n') {
299        /* add a line-feed (SimOS console output goes to shell */
300        PutChar('\r');
301    }
302
303    va_end(ap);         /* clean up */
304    return 0;
305}
306
307void
308panic(const char *f, ...)
309{
310    va_list ap;
311
312    va_start(ap, f);
313
314    printf("CONSOLE PANIC (looping): ");
315    while (*f) {
316        if (*f == '%')
317            f = FormatItem(f + 1, &ap);
318        else
319            PutChar(*f++);
320    }
321
322    va_end(ap);         /* clean up */
323    while(1);
324}
325