/**************************************************************************
MISC Support Routines
**************************************************************************/
#include "misc.h"
#include "printf.h"
#include "etherboot.h"
/* Recursive call of sprintf in vsprintf */
int sprintf(char *buf, const char *fmt, ...);
extern void putchar(int);
/**************************************************************************
PRINTF and friends
Formats:
%[#]x - 4 bytes long (8 hex digits, lower case)
%[#]X - 4 bytes long (8 hex digits, upper case)
%[#]hx - 2 bytes int (4 hex digits, lower case)
%[#]hX - 2 bytes int (4 hex digits, upper case)
%[#]hhx - 1 byte int (2 hex digits, lower case)
%[#]hhX - 1 byte int (2 hex digits, upper case)
- optional # prefixes 0x or 0X
%d - decimal int
%c - char
%s - string
%@ - Internet address in ddd.ddd.ddd.ddd notation
#ifdef PRINT_ENET_ADDRS
%! - Ethernet address in xx:xx:xx:xx:xx:xx notation
#endif
Note: width specification ignored
**************************************************************************/
int vsprintf(char *buf, const char *fmt, const int *dp)
{
char *p, *s;
s = buf;
for ( ; *fmt != '\0'; ++fmt) {
if (*fmt != '%') {
buf ? *s++ = *fmt : putchar(*fmt);
continue;
}
/* skip width specs */
fmt++;
while (*fmt >= '0' && *fmt <= '9')
fmt++;
if (*fmt == '.')
fmt++;
while (*fmt >= '0' && *fmt <= '9')
fmt++;
if (*fmt == 's') {
for (p = (char *)*dp++; *p != '\0'; p++)
buf ? *s++ = *p : putchar(*p);
}
else { /* Length of item is bounded */
char tmp[20], *q = tmp;
int alt = 0;
int shift = 28;
if (*fmt == '#') {
alt = 1;
fmt++;
}
if (*fmt == 'h') {
shift = 12;
fmt++;
}
if (*fmt == 'h') {
shift = 4;
fmt++;
}
/*
* Before each format q points to tmp buffer
* After each format q points past end of item
*/
if ((*fmt | 0x20) == 'x') {
/* With x86 gcc, sizeof(long) == sizeof(int) */
const long *lp = (const long *)dp;
long h = *lp++;
int ncase = (*fmt & 0x20);
dp = (const int *)lp;
if (alt) {
*q++ = '0';
*q++ = 'X' | ncase;
}
for ( ; shift >= 0; shift -= 4)
*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
}
else if (*fmt == 'd') {
int i = *dp++;
char *r;
if (i < 0) {
*q++ = '-';
i = -i;
}
p = q; /* save beginning of digits */
do {
*q++ = '0' + (i % 10);
i /= 10;
} while (i);
/* reverse digits, stop in middle */
r = q; /* don't alter q */
while (--r > p) {
i = *r;
*r = *p;
*p++ = i;
}
}
else if (*fmt == '@') {
unsigned char *r;
union {
long l;
unsigned char c[4];
} u;
const long *lp = (const long *)dp;
u.l = *lp++;
dp = (const int *)lp;
for (r = &u.c[0]; r < &u.c[4]; ++r)
q += sprintf(q, "%d.", *r);
--q;
}
#ifdef PRINT_ENET_ADDRS
else if (*fmt == '!') {
char *r;
p = (char *)*dp++;
for (r = p + ETH_ALEN; p < r; ++p)
q += sprintf(q, "%hhX:", *p);
--q;
}
#endif /* PRINT_ENET_ADDRS */
else if (*fmt == 'c')
*q++ = *dp++;
else
*q++ = *fmt;
/* now output the saved string */
for (p = tmp; p < q; ++p)
buf ? *s++ = *p : putchar(*p);
}
}
if (buf)
*s = '\0';
return (s - buf);
}
int sprintf(char *buf, const char *fmt, ...)
{
return vsprintf(buf, fmt, ((const int *)&fmt)+1);
}
int printf(const char *fmt, ...)
{
return vsprintf(0, fmt, ((const int *)&fmt)+1);
}
syntax highlighted by Code2HTML, v. 0.9.1