1/*
2 * Copyright (c) 2003-2004 The Regents of The University of Michigan
3 * Copyright (c) 1993 The Hewlett-Packard Development Company
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <stdarg.h>
32#include <stdint.h>
33#include "m5op.h"
34
35/* The string s is terminated by a '\0' */
36void
37PutString(const char *s)
38{
39    while (*s)
40        PutChar(*s++);
41}
42
43/* print c count times */
44void
45PutRepChar(char c, int count)
46{
47    while (count--)
48        PutChar(c);
49}
50
51/* put string reverse */
52void
53PutStringReverse(const char *s, int index)
54{
55    while (index-- > 0)
56        PutChar(s[index]);
57}
58
59/*
60 * prints value in radix, in a field width width, with fill
61 * character fill
62 * if radix is negative, print as signed quantity
63 * if width is negative, left justify
64 * if width is 0, use whatever is needed
65 * if fill is 0, use ' '
66 */
67void
68PutNumber(long value, int radix, int width, char fill)
69{
70    char buffer[40];
71    uint bufferindex = 0;
72    ulong uvalue;
73    ushort digit;
74    ushort left = 0;
75    ushort negative = 0;
76
77    if (fill == 0)
78        fill = ' ';
79
80    if (width < 0) {
81        width = -width;
82        left = 1;
83    }
84
85    if (width < 0 || width > 80)
86        width = 0;
87
88    if (radix < 0) {
89        radix = -radix;
90        if (value < 0) {
91            negative = 1;
92            value = -value;
93        }
94    }
95
96    switch (radix) {
97      case 8:
98      case 10:
99      case 16:
100        break;
101
102      default:
103        PutString("****");
104        return;
105    }
106
107    uvalue = value;
108
109    do {
110        if (radix != 16) {
111            digit = (ushort)(uvalue % radix);
112            uvalue /= radix;
113        } else {
114            digit = (ushort)(uvalue & 0xf);
115            uvalue = uvalue >> 4;
116        }
117        buffer[bufferindex] = digit + ((digit <= 9) ? '0' : ('A' - 10));
118        bufferindex += 1;
119    } while (uvalue != 0);
120
121  /* fill # ' ' and negative cannot happen at once */
122    if (negative) {
123        buffer[bufferindex] = '-';
124        bufferindex += 1;
125    }
126
127    if ((uint)width <= bufferindex) {
128        PutStringReverse(buffer, bufferindex);
129    } else {
130        width -= bufferindex;
131        if (!left)
132            PutRepChar(fill, width);
133        PutStringReverse(buffer, bufferindex);
134        if (left)
135            PutRepChar(fill, width);
136    }
137}
138
139ulong
140power(long base, long n)
141{
142    ulong p;
143
144    for (p = 1; n > 0; --n)
145        p = p * base;
146    return p;
147}
148
149void
150putFloat(double a, int fieldwidth, char fill)
151{
152    int i;
153    ulong b;
154
155    /*
156     *  Put out everything before the decimal place.
157     */
158    PutNumber(((ulong) a), 10, fieldwidth, fill);
159
160    /*
161     *  Output the decimal place.
162     */
163    PutChar('.' & 0x7f);
164
165    /*
166     *  Output the n digits after the decimal place.
167     */
168    for (i = 1; i < 6; i++) {
169        b = (ulong)(power(10, i) * (double)(a - (ulong) a));
170        PutChar((char)(b % 10) + '0');
171    }
172}
173
174const char *
175FormatItem(const char *f, va_list *ap)
176{
177    char c;
178    int fieldwidth = 0;
179    int leftjust = 0;
180    int radix = 0;
181    char fill = ' ';
182
183    if (*f == '0')
184        fill = '0';
185
186    while (c = *f++) {
187        if (c >= '0' && c <= '9') {
188            fieldwidth = (fieldwidth * 10) + (c - '0');
189        } else {
190            switch (c) {
191              case '\000':
192                return(--f);
193              case '%':
194                PutChar('%');
195                return(f);
196              case '-':
197                leftjust = 1;
198                break;
199              case 'c': {
200                  char a = (char)va_arg(*ap, int);
201
202                  if (leftjust)
203                      PutChar(a & 0x7f);
204                  if (fieldwidth > 0)
205                      PutRepChar(fill, fieldwidth - 1);
206                  if (!leftjust)
207                      PutChar(a & 0x7f);
208                  return(f);
209              }
210              case 's': {
211                  const char *a = va_arg(*ap, const char *);
212
213                  if (leftjust)
214                      PutString((const char *) a);
215                  if (fieldwidth > strlen((const char *) a))
216                      PutRepChar(fill, fieldwidth - strlen((const char *)a));
217                  if (!leftjust)
218                      PutString((const char *) a);
219                  return(f);
220              }
221              case 'd':
222                radix = -10;
223                break;
224              case 'u':
225                radix = 10;
226                break;
227              case 'x':
228                radix = 16;
229                break;
230              case 'X':
231                radix = 16;
232                break;
233              case 'o':
234                radix = 8;
235                break;
236              case 'f': {
237                  double a = va_arg(*ap, double);
238
239                  putFloat(a, fieldwidth, fill);
240                  return(f);
241              }
242              default:   /* unknown switch! */
243                radix = 3;
244                break;
245            }
246        }
247
248        if (radix)
249            break;
250    }
251
252    if (leftjust)
253        fieldwidth = -fieldwidth;
254
255    long a = va_arg(*ap, long);
256    PutNumber(a, radix, fieldwidth, fill);
257
258    return(f);
259}
260
261int
262printf(const char *f, ...)
263{
264    va_list ap;
265
266    va_start(ap, f);
267
268    while (*f) {
269        if (*f == '%')
270            f = FormatItem(f + 1, &ap);
271        else
272            PutChar(*f++);
273    }
274
275    if (*(f - 1) == '\n') {
276        /* add a line-feed (SimOS console output goes to shell */
277        PutChar('\r');
278    }
279
280    va_end(ap);         /* clean up */
281    return 0;
282}
283
284void
285panic(const char *f, ...)
286{
287    va_list ap;
288
289    va_start(ap, f);
290
291    printf("CONSOLE PANIC (looping): ");
292    while (*f) {
293        if (*f == '%')
294            f = FormatItem(f + 1, &ap);
295        else
296            PutChar(*f++);
297    }
298
299    va_end(ap);         /* clean up */
300    m5_panic();
301}
302