integrated printf routines. Only tested yet for "before copy"-case (which is more difficult than afterwards).
This commit is contained in:
373
sources/bas_printf.c
Normal file
373
sources/bas_printf.c
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* 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 <bas_printf.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 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';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user