| /* |
| * Copyright (c) 2003-2004 The Regents of The University of Michigan |
| * Copyright (c) 1993 The Hewlett-Packard Development Company |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <sys/types.h> |
| #include <stdarg.h> |
| #include <stdint.h> |
| #include "m5op.h" |
| |
| /* The string s is terminated by a '\0' */ |
| void |
| PutString(const char *s) |
| { |
| while (*s) |
| PutChar(*s++); |
| } |
| |
| /* print c count times */ |
| void |
| PutRepChar(char c, int count) |
| { |
| while (count--) |
| PutChar(c); |
| } |
| |
| /* put string reverse */ |
| void |
| PutStringReverse(const char *s, int index) |
| { |
| while (index-- > 0) |
| PutChar(s[index]); |
| } |
| |
| /* |
| * prints value in radix, in a field width width, with fill |
| * character fill |
| * if radix is negative, print as signed quantity |
| * if width is negative, left justify |
| * if width is 0, use whatever is needed |
| * if fill is 0, use ' ' |
| */ |
| void |
| PutNumber(long value, int radix, int width, char fill) |
| { |
| char buffer[40]; |
| uint bufferindex = 0; |
| ulong uvalue; |
| ushort digit; |
| ushort left = 0; |
| ushort negative = 0; |
| |
| if (fill == 0) |
| fill = ' '; |
| |
| if (width < 0) { |
| width = -width; |
| left = 1; |
| } |
| |
| if (width < 0 || width > 80) |
| width = 0; |
| |
| if (radix < 0) { |
| radix = -radix; |
| if (value < 0) { |
| negative = 1; |
| value = -value; |
| } |
| } |
| |
| switch (radix) { |
| case 8: |
| case 10: |
| case 16: |
| break; |
| |
| default: |
| PutString("****"); |
| return; |
| } |
| |
| uvalue = value; |
| |
| do { |
| if (radix != 16) { |
| digit = (ushort)(uvalue % radix); |
| uvalue /= radix; |
| } else { |
| digit = (ushort)(uvalue & 0xf); |
| uvalue = uvalue >> 4; |
| } |
| buffer[bufferindex] = digit + ((digit <= 9) ? '0' : ('A' - 10)); |
| bufferindex += 1; |
| } while (uvalue != 0); |
| |
| /* fill # ' ' and negative cannot happen at once */ |
| if (negative) { |
| buffer[bufferindex] = '-'; |
| bufferindex += 1; |
| } |
| |
| if ((uint)width <= bufferindex) { |
| PutStringReverse(buffer, bufferindex); |
| } else { |
| width -= bufferindex; |
| if (!left) |
| PutRepChar(fill, width); |
| PutStringReverse(buffer, bufferindex); |
| if (left) |
| PutRepChar(fill, width); |
| } |
| } |
| |
| ulong |
| power(long base, long n) |
| { |
| ulong p; |
| |
| for (p = 1; n > 0; --n) |
| p = p * base; |
| return p; |
| } |
| |
| void |
| putFloat(double a, int fieldwidth, char fill) |
| { |
| int i; |
| ulong b; |
| |
| /* |
| * Put out everything before the decimal place. |
| */ |
| PutNumber(((ulong) a), 10, fieldwidth, fill); |
| |
| /* |
| * Output the decimal place. |
| */ |
| PutChar('.' & 0x7f); |
| |
| /* |
| * Output the n digits after the decimal place. |
| */ |
| for (i = 1; i < 6; i++) { |
| b = (ulong)(power(10, i) * (double)(a - (ulong) a)); |
| PutChar((char)(b % 10) + '0'); |
| } |
| } |
| |
| const char * |
| FormatItem(const char *f, va_list *ap) |
| { |
| char c; |
| int fieldwidth = 0; |
| int leftjust = 0; |
| int radix = 0; |
| char fill = ' '; |
| |
| if (*f == '0') |
| fill = '0'; |
| |
| while (c = *f++) { |
| if (c >= '0' && c <= '9') { |
| fieldwidth = (fieldwidth * 10) + (c - '0'); |
| } else { |
| switch (c) { |
| case '\000': |
| return(--f); |
| case '%': |
| PutChar('%'); |
| return(f); |
| case '-': |
| leftjust = 1; |
| break; |
| case 'c': { |
| char a = (char)va_arg(*ap, int); |
| |
| if (leftjust) |
| PutChar(a & 0x7f); |
| if (fieldwidth > 0) |
| PutRepChar(fill, fieldwidth - 1); |
| if (!leftjust) |
| PutChar(a & 0x7f); |
| return(f); |
| } |
| case 's': { |
| const char *a = va_arg(*ap, const char *); |
| |
| if (leftjust) |
| PutString((const char *) a); |
| if (fieldwidth > strlen((const char *) a)) |
| PutRepChar(fill, fieldwidth - strlen((const char *)a)); |
| if (!leftjust) |
| PutString((const char *) a); |
| return(f); |
| } |
| case 'd': |
| radix = -10; |
| break; |
| case 'u': |
| radix = 10; |
| break; |
| case 'x': |
| radix = 16; |
| break; |
| case 'X': |
| radix = 16; |
| break; |
| case 'o': |
| radix = 8; |
| break; |
| case 'f': { |
| double a = va_arg(*ap, double); |
| |
| putFloat(a, fieldwidth, fill); |
| return(f); |
| } |
| default: /* unknown switch! */ |
| radix = 3; |
| break; |
| } |
| } |
| |
| if (radix) |
| break; |
| } |
| |
| if (leftjust) |
| fieldwidth = -fieldwidth; |
| |
| long a = va_arg(*ap, long); |
| PutNumber(a, radix, fieldwidth, fill); |
| |
| return(f); |
| } |
| |
| int |
| printf(const char *f, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, f); |
| |
| while (*f) { |
| if (*f == '%') |
| f = FormatItem(f + 1, &ap); |
| else |
| PutChar(*f++); |
| } |
| |
| if (*(f - 1) == '\n') { |
| /* add a line-feed (SimOS console output goes to shell */ |
| PutChar('\r'); |
| } |
| |
| va_end(ap); /* clean up */ |
| return 0; |
| } |
| |
| void |
| panic(const char *f, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, f); |
| |
| printf("CONSOLE PANIC (looping): "); |
| while (*f) { |
| if (*f == '%') |
| f = FormatItem(f + 1, &ap); |
| else |
| PutChar(*f++); |
| } |
| |
| va_end(ap); /* clean up */ |
| m5_panic(); |
| } |