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