/*------------------------------------------------------------------------/ | |
/ Universal string handler for user console interface | |
/-------------------------------------------------------------------------/ | |
/ | |
/ Copyright (C) 2011, ChaN, all right reserved. | |
/ | |
/ * This software is a free software and there is NO WARRANTY. | |
/ * No restriction on use. You can use, modify and redistribute it for | |
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. | |
/ * Redistributions of source code must retain the above copyright notice. | |
/ | |
/-------------------------------------------------------------------------*/ | |
#include "common/xprintf/xprintf.h" | |
#if _USE_XFUNC_OUT | |
#include <stdarg.h> | |
void (*xfunc_out)(unsigned char); /* Pointer to the output stream */ | |
static char *outptr; | |
/*----------------------------------------------*/ | |
/* Put a character */ | |
/*----------------------------------------------*/ | |
void xputc(char c) | |
{ | |
if (_CR_CRLF && c == '\n') { xputc('\r'); } /* CR -> CRLF */ | |
if (outptr) | |
{ | |
*outptr++ = (unsigned char)c; | |
return; | |
} | |
if (xfunc_out) { xfunc_out((unsigned char)c); } | |
} | |
/*----------------------------------------------*/ | |
/* Put a null-terminated string */ | |
/*----------------------------------------------*/ | |
void xputs( /* Put a string to the default device */ | |
const char *str /* Pointer to the string */ | |
) | |
{ | |
while (*str) | |
{ | |
xputc(*str++); | |
} | |
} | |
void xfputs( /* Put a string to the specified device */ | |
void(*func)(unsigned char), /* Pointer to the output function */ | |
const char *str /* Pointer to the string */ | |
) | |
{ | |
void (*pf)(unsigned char); | |
pf = xfunc_out; /* Save current output device */ | |
xfunc_out = func; /* Switch output to specified device */ | |
while (*str) /* Put the string */ | |
{ | |
xputc(*str++); | |
} | |
xfunc_out = pf; /* Restore output device */ | |
} | |
/*----------------------------------------------*/ | |
/* Formatted string output */ | |
/*----------------------------------------------*/ | |
/* xprintf("%d", 1234); "1234" | |
xprintf("%6d,%3d%%", -200, 5); " -200, 5%" | |
xprintf("%-6u", 100); "100 " | |
xprintf("%ld", 12345678L); "12345678" | |
xprintf("%04x", 0xA3); "00a3" | |
xprintf("%08LX", 0x123ABC); "00123ABC" | |
xprintf("%016b", 0x550F); "0101010100001111" | |
xprintf("%s", "String"); "String" | |
xprintf("%-4s", "abc"); "abc " | |
xprintf("%4s", "abc"); " abc" | |
xprintf("%c", 'a'); "a" | |
xprintf("%f", 10.0); <xprintf lacks floating point support> | |
*/ | |
void xvprintf( | |
const char *fmt, /* Pointer to the format string */ | |
va_list arp /* Pointer to arguments */ | |
) | |
{ | |
unsigned int r, i, j, w, f; | |
unsigned long v; | |
char s[16], c, d, *p; | |
for (;;) | |
{ | |
c = *fmt++; /* Get a char */ | |
if (!c) { break; } /* End of format? */ | |
if (c != '%') /* Pass through it if not a % sequense */ | |
{ | |
xputc(c); | |
continue; | |
} | |
f = 0; | |
c = *fmt++; /* Get first char of the sequense */ | |
if (c == '0') /* Flag: '0' padded */ | |
{ | |
f = 1; | |
c = *fmt++; | |
} | |
else | |
{ | |
if (c == '-') /* Flag: left justified */ | |
{ | |
f = 2; | |
c = *fmt++; | |
} | |
} | |
for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */ | |
{ | |
w = w * 10 + c - '0'; | |
} | |
if (c == 'l' || c == 'L') /* Prefix: Size is long int */ | |
{ | |
f |= 4; | |
c = *fmt++; | |
} | |
if (!c) { break; } /* End of format? */ | |
d = c; | |
if (d >= 'a') { d -= 0x20; } | |
switch (d) /* Type is... */ | |
{ | |
case 'S' : /* String */ | |
p = va_arg(arp, char *); | |
for (j = 0; p[j]; j++) ; | |
while (!(f & 2) && j++ < w) { xputc(' '); } | |
xputs(p); | |
while (j++ < w) { xputc(' '); } | |
continue; | |
case 'C' : /* Character */ | |
xputc((char)va_arg(arp, int)); | |
continue; | |
case 'B' : /* Binary */ | |
r = 2; | |
break; | |
case 'O' : /* Octal */ | |
r = 8; | |
break; | |
case 'D' : /* Signed decimal */ | |
case 'U' : /* Unsigned decimal */ | |
r = 10; | |
break; | |
case 'X' : /* Hexdecimal */ | |
r = 16; | |
break; | |
default: /* Unknown type (passthrough) */ | |
xputc(c); | |
continue; | |
} | |
/* Get an argument and put it in numeral */ | |
v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int)); | |
if (d == 'D' && (v & 0x80000000)) | |
{ | |
v = 0 - v; | |
f |= 8; | |
} | |
i = 0; | |
do | |
{ | |
d = (char)(v % r); | |
v /= r; | |
if (d > 9) { d += (c == 'x') ? 0x27 : 0x07; } | |
s[i++] = d + '0'; | |
} | |
while (v && i < sizeof(s)); | |
if ((f & 8) && (i < sizeof(s))) { s[i++] = '-'; } | |
j = i; | |
d = (f & 1) ? '0' : ' '; | |
while (!(f & 2) && j++ < w) { xputc(d); } | |
do { xputc(s[--i]); } | |
while (i); | |
while (j++ < w) { xputc(' '); } | |
} | |
} | |
void xprintf( /* Put a formatted string to the default device */ | |
const char *fmt, /* Pointer to the format string */ | |
... /* Optional arguments */ | |
) | |
{ | |
va_list arp; | |
va_start(arp, fmt); | |
xvprintf(fmt, arp); | |
va_end(arp); | |
} | |
void xsprintf( /* Put a formatted string to the memory */ | |
char *buff, /* Pointer to the output buffer */ | |
const char *fmt, /* Pointer to the format string */ | |
... /* Optional arguments */ | |
) | |
{ | |
va_list arp; | |
outptr = buff; /* Switch destination for memory */ | |
va_start(arp, fmt); | |
xvprintf(fmt, arp); | |
va_end(arp); | |
*outptr = 0; /* Terminate output string with a \0 */ | |
outptr = 0; /* Switch destination for device */ | |
} | |
void xfprintf( /* Put a formatted string to the specified device */ | |
void(*func)(unsigned char), /* Pointer to the output function */ | |
const char *fmt, /* Pointer to the format string */ | |
... /* Optional arguments */ | |
) | |
{ | |
va_list arp; | |
void (*pf)(unsigned char); | |
pf = xfunc_out; /* Save current output device */ | |
xfunc_out = func; /* Switch output to specified device */ | |
va_start(arp, fmt); | |
xvprintf(fmt, arp); | |
va_end(arp); | |
xfunc_out = pf; /* Restore output device */ | |
} | |
/*----------------------------------------------*/ | |
/* Dump a line of binary dump */ | |
/*----------------------------------------------*/ | |
void put_dump( | |
const void *buff, /* Pointer to the array to be dumped */ | |
unsigned long addr, /* Heading address value */ | |
int len, /* Number of items to be dumped */ | |
int width /* Size of the items (DF_CHAR, DF_SHORT, DF_LONG) */ | |
) | |
{ | |
int i; | |
const unsigned char *bp; | |
const unsigned short *sp; | |
const unsigned long *lp; | |
xprintf("%08lX ", addr); /* address */ | |
switch (width) | |
{ | |
case DW_CHAR: | |
bp = buff; | |
for (i = 0; i < len; i++) /* Hexdecimal dump */ | |
{ | |
xprintf(" %02X", bp[i]); | |
} | |
xputc(' '); | |
for (i = 0; i < len; i++) /* ASCII dump */ | |
{ | |
xputc((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.'); | |
} | |
break; | |
case DW_SHORT: | |
sp = buff; | |
do /* Hexdecimal dump */ | |
{ | |
xprintf(" %04X", *sp++); | |
} | |
while (--len); | |
break; | |
case DW_LONG: | |
lp = buff; | |
do /* Hexdecimal dump */ | |
{ | |
xprintf(" %08LX", *lp++); | |
} | |
while (--len); | |
break; | |
} | |
xputc('\n'); | |
} | |
#endif /* _USE_XFUNC_OUT */ | |
#if _USE_XFUNC_IN | |
unsigned char (*xfunc_in)(void); /* Pointer to the input stream */ | |
/*----------------------------------------------*/ | |
/* Get a line from the input */ | |
/*----------------------------------------------*/ | |
int xgets( /* 0:End of stream, 1:A line arrived */ | |
char *buff, /* Pointer to the buffer */ | |
int len /* Buffer length */ | |
) | |
{ | |
int c, i; | |
if (!xfunc_in) { return 0; } /* No input function specified */ | |
i = 0; | |
for (;;) | |
{ | |
c = xfunc_in(); /* Get a char from the incoming stream */ | |
if (!c) { return 0; } /* End of stream? */ | |
if (c == '\r') { break; } /* End of line? */ | |
if (c == '\b' && i) /* Back space? */ | |
{ | |
i--; | |
if (_LINE_ECHO) { xputc(c); } | |
continue; | |
} | |
if (c >= ' ' && i < len - 1) /* Visible chars */ | |
{ | |
buff[i++] = c; | |
if (_LINE_ECHO) { xputc(c); } | |
} | |
} | |
buff[i] = 0; /* Terminate with a \0 */ | |
if (_LINE_ECHO) { xputc('\n'); } | |
return 1; | |
} | |
int xfgets( /* 0:End of stream, 1:A line arrived */ | |
unsigned char (*func)(void), /* Pointer to the input stream function */ | |
char *buff, /* Pointer to the buffer */ | |
int len /* Buffer length */ | |
) | |
{ | |
unsigned char (*pf)(void); | |
int n; | |
pf = xfunc_in; /* Save current input device */ | |
xfunc_in = func; /* Switch input to specified device */ | |
n = xgets(buff, len); /* Get a line */ | |
xfunc_in = pf; /* Restore input device */ | |
return n; | |
} | |
/*----------------------------------------------*/ | |
/* Get a value of the string */ | |
/*----------------------------------------------*/ | |
/* "123 -5 0x3ff 0b1111 0377 w " | |
^ 1st call returns 123 and next ptr | |
^ 2nd call returns -5 and next ptr | |
^ 3rd call returns 1023 and next ptr | |
^ 4th call returns 15 and next ptr | |
^ 5th call returns 255 and next ptr | |
^ 6th call fails and returns 0 | |
*/ | |
int xatoi( /* 0:Failed, 1:Successful */ | |
char **str, /* Pointer to pointer to the string */ | |
long *res /* Pointer to the valiable to store the value */ | |
) | |
{ | |
unsigned long val; | |
unsigned char c, r, s = 0; | |
*res = 0; | |
while ((c = **str) == ' ') { (*str)++; } /* Skip leading spaces */ | |
if (c == '-') /* negative? */ | |
{ | |
s = 1; | |
c = *(++(*str)); | |
} | |
if (c == '0') | |
{ | |
c = *(++(*str)); | |
switch (c) | |
{ | |
case 'x': /* hexdecimal */ | |
r = 16; | |
c = *(++(*str)); | |
break; | |
case 'b': /* binary */ | |
r = 2; | |
c = *(++(*str)); | |
break; | |
default: | |
if (c <= ' ') { return 1; } /* single zero */ | |
if (c < '0' || c > '9') { return 0; } /* invalid char */ | |
r = 8; /* octal */ | |
} | |
} | |
else | |
{ | |
if (c < '0' || c > '9') { return 0; } /* EOL or invalid char */ | |
r = 10; /* decimal */ | |
} | |
val = 0; | |
while (c > ' ') | |
{ | |
if (c >= 'a') { c -= 0x20; } | |
c -= '0'; | |
if (c >= 17) | |
{ | |
c -= 7; | |
} | |
if (c >= r) { return 0; } /* invalid char for current radix */ | |
val = val * r + c; | |
c = *(++(*str)); | |
} | |
if (s) { val = 0 - val; } /* apply sign if needed */ | |
*res = val; | |
return 1; | |
} | |
#endif /* _USE_XFUNC_IN */ |