| /* | |
| * 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(); | |
| } |