Files
FireBee_SVN/BaS_gcc/tos/vmem_test/sources/bas_printf.c

457 lines
13 KiB
C

/*
* 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 <stdarg.h>
#include "MCF5475.h"
#include "bas_printf.h"
#include "bas_string.h"
/*
* 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 snil[] = "(nil)";
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","d2","a0","memory"
);
}
static void doprnt(void (*addchar)(int), const char *sfmt, va_list ap)
{
char buf[128];
char *bp;
const char *f;
float flt;
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:
default:
l = va_arg(ap, long);
break;
}
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 'f':
/* this is actually more than stupid, but does work for now */
flt = (float) (va_arg(ap, double)); /* beware: va_arg() extends float to double! */
if (flt < 0)
{
sign = 1;
flt = -flt;
}
{
int quotient, remainder;
quotient = (int) flt;
remainder = (flt - quotient) * 10E5;
for (i = 0; i < 6; i++)
{
*bp++ = (char) (remainder % 10) + '0';
remainder /= 10;
}
*bp++ = '.';
do
{
*bp++ = (char) (quotient % 10) + '0';
} while ((quotient /= 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';
/* no break */
case 'o':
case 'x':
case 'u':
switch (do_long)
{
case 0:
u = (unsigned long) (va_arg(ap, unsigned int));
break;
case 1:
default:
u = va_arg(ap, unsigned long);
break;
}
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;
void xaddchar(int c)
{
if (xestring == xstring)
*xstring = '\0';
else
*xstring++ = (char) c;
}
int sprintf(char *str, const char *format, ...)
{
va_list va;
va_start(va, format);
xstring = str;
doprnt(xaddchar, format, va);
va_end(va);
*xstring++ = '\0';
return 0;
}
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';
}
void display_progress()
{
static int _progress_index;
char progress_char[] = "|/-\\";
xputchar(progress_char[_progress_index++ % strlen(progress_char)]);
xputchar('\r');
}
void hexdump(uint8_t buffer[], int size)
{
int i;
int line = 0;
uint8_t *bp = buffer;
while (bp < buffer + size) {
uint8_t *lbp = bp;
xprintf("%08x ", line);
for (i = 0; i < 16; i++) {
if (bp + i > buffer + size) {
break;
}
xprintf("%02x ", (uint8_t) *lbp++);
}
lbp = bp;
for (i = 0; i < 16; i++) {
int8_t c = *lbp++;
if (bp + i > buffer + size) {
break;
}
if (c > ' ' && c < '~') {
xprintf("%c", c);
} else {
xprintf(".");
}
}
xprintf("\r\n");
bp += 16;
line += 16;
}
}