| /*------------------------------------------------------------------------/ |
| / 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 "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 */ |