/* * tc.printf.c: A public-domain, minimal printf/sprintf routine that prints * through the putchar() routine. Feel free to use for * anything... -- 7/17/87 Paul Placeway */ /*- * Copyright (c) 1980, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 "MCF5475.h" #include /* * Lexical definitions. * * All lexical space is allocated dynamically. * The eighth/sixteenth bit of characters is used to prevent recognition, * and eventually stripped. */ #define META 0200 #define ASCII 0177 # define QUOTE ((char) 0200) /* Eighth char bit used for 'ing */ # define TRIM 0177 /* Mask to strip quote bit */ # define UNDER 0000000 /* No extra bits to do both */ # define BOLD 0000000 /* Bold flag */ # define STANDOUT META /* Standout flag */ # define LITERAL 0000000 /* Literal character flag */ # define ATTRIBUTES 0200 /* The bits used for attributes */ # define CHAR 0000177 /* Mask to mask out the character */ #define INF 32766 /* should be bigger than any field to print */ static char buf[128]; static char snil[] = "(nil)"; static void xputchar(int c) { __asm__ __volatile__ ( ".extern printf_helper\n\t" "move.b %0,d0\n\t" "bsr printf_helper\n\t" /* output */: /* input */: "r" (c) /* clobber */ : "d0","a0" ); } #define isdigit(c) (((c) >= '0') && ((c) <= '9')) #define isupper(c) ((c) >= 'A' && ((c) <= 'Z')) #define islower(c) ((c) >= 'a' && ((c) <= 'z')) #define isalpha(c) (isupper((c)) || islower(c)) #define tolower(c) (isupper(c) ? ((c) + 'a' - 'A') : (c)) static int atoi(const char *c) { int value = 0; while (isdigit(*c) ) { value *= 10; value += (int) (*c-'0'); c++; } return value; } size_t strlen(const char *s) { int length = 0; while (*s++) { length++; } return length; } static void doprnt(void (*addchar) (int), const char *sfmt, va_list ap) { char *bp; const char *f; long l; unsigned long u; int i; int fmt; unsigned char pad = ' '; int flush_left = 0; int f_width = 0; int prec = INF; int hash = 0; int do_long = 0; int sign = 0; int attributes = 0; f = sfmt; for (; *f; f++) { if (*f != '%') { /* then just out the char */ (*addchar) ((int)(((unsigned char)*f) | attributes)); } else { f++; /* skip the % */ if (*f == '-') { /* minus: flush left */ flush_left = 1; f++; } if (*f == '0' || *f == '.') { /* padding with 0 rather than blank */ pad = '0'; f++; } if (*f == '*') { /* field width */ f_width = va_arg(ap, int); f++; } else if (isdigit((unsigned char)*f)) { f_width = atoi(f); while (isdigit((unsigned char)*f)) f++; /* skip the digits */ } if (*f == '.') { /* precision */ f++; if (*f == '*') { prec = va_arg(ap, int); f++; } else if (isdigit((unsigned char)*f)) { prec = atoi(f); while (isdigit((unsigned char)*f)) f++; /* skip the digits */ } } if (*f == '#') { /* alternate form */ hash = 1; f++; } if (*f == 'l') { /* long format */ do_long++; f++; if (*f == 'l') { do_long++; f++; } } fmt = (unsigned char)*f; if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) { do_long = 1; fmt = tolower(fmt); } bp = buf; switch (fmt) { /* do the format */ case 'd': switch (do_long) { case 0: l = (long)(va_arg(ap, int)); break; case 1: #ifndef HAVE_LONG_LONG default: #endif l = va_arg(ap, long); break; #ifdef HAVE_LONG_LONG default: l = va_arg(ap, long long); break; #endif } if (l < 0) { sign = 1; l = -l; } do { *bp++ = (char)(l % 10) + '0'; } while ((l /= 10) > 0); if (sign) *bp++ = '-'; f_width = f_width - (int)(bp - buf); if (!flush_left) while (f_width-- > 0) (*addchar) ((int) (pad | attributes)); for (bp--; bp >= buf; bp--) (*addchar) ((int) (((unsigned char)*bp) | attributes)); if (flush_left) while (f_width-- > 0) (*addchar) ((int) (' ' | attributes)); break; case 'p': do_long = 1; hash = 1; fmt = 'x'; /*FALLTHROUGH*/ case 'o': case 'x': case 'u': switch (do_long) { case 0: u = (unsigned long)(va_arg(ap, unsigned int)); break; case 1: #ifndef HAVE_LONG_LONG default: #endif u = va_arg(ap, unsigned long); break; #ifdef HAVE_LONG_LONG default: u = va_arg(ap, unsigned long long); break; #endif } if (fmt == 'u') { /* unsigned decimal */ do { *bp++ = (char)(u % 10) + '0'; } while ((u /= 10) > 0); } else if (fmt == 'o') { /* octal */ do { *bp++ = (char)(u % 8) + '0'; } while ((u /= 8) > 0); if (hash) *bp++ = '0'; } else if (fmt == 'x') { /* hex */ do { i = (int)(u % 16); if (i < 10) *bp++ = i + '0'; else *bp++ = i - 10 + 'a'; } while ((u /= 16) > 0); if (hash) { *bp++ = 'x'; *bp++ = '0'; } } i = f_width - (int)(bp - buf); if (!flush_left) while (i-- > 0) (*addchar) ((int) (pad | attributes)); for (bp--; bp >= buf; bp--) (*addchar) ((int) (((unsigned char)*bp) | attributes)); if (flush_left) while (i-- > 0) (*addchar) ((int) (' ' | attributes)); break; case 'c': i = va_arg(ap, int); (*addchar) ((int)(i | attributes)); break; case 'S': case 'Q': case 's': case 'q': bp = va_arg(ap, char *); if (!bp) bp = snil; f_width = f_width - strlen((char *)bp); if (!flush_left) while (f_width-- > 0) (*addchar) ((int)(pad | attributes)); for (i = 0; *bp && i < prec; i++) { if (fmt == 'q' && *bp & QUOTE) (*addchar) ((int)('\\' | attributes)); (*addchar) ((int)(((unsigned char)*bp & TRIM) | attributes)); bp++; } if (flush_left) while (f_width-- > 0) (*addchar) ((int)(' ' | attributes)); break; case 'a': attributes = va_arg(ap, int); break; case '%': (*addchar) ((int)('%' | attributes)); break; default: break; } flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; sign = 0; pad = ' '; } } } static char *xstring, *xestring; static void xaddchar(int c) { if (xestring == xstring) *xstring = '\0'; else *xstring++ = (char)c; } void xsnprintf(char *str, size_t size, const char *fmt, ...) { va_list va; va_start(va, fmt); xstring = str; xestring = str + size - 1; doprnt(xaddchar, fmt, va); va_end(va); *xstring++ = '\0'; } void xprintf(const char *fmt, ...) { va_list va; va_start(va, fmt); doprnt(xputchar, fmt, va); va_end(va); } void xvprintf(const char *fmt, va_list va) { doprnt(xputchar, fmt, va); } void xvsnprintf(char *str, size_t size, const char *fmt, va_list va) { xstring = str; xestring = str + size - 1; doprnt(xaddchar, fmt, va); *xstring++ = '\0'; }