/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 2011,2012 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . --- A special exception to the GPL can be applied should you wish to distribute a combined work that includes ChibiOS/RT, without being obliged to provide the source code for any proprietary components. See the file exception.txt for full details of how and when the exception can be applied. */ /** * @file chprintf.c * @brief Mini printf-like functionality. * * @addtogroup chprintf * @{ */ #include #include "ch.h" #define MAX_FILLER 11 static char *ltoa(char *p, long num, unsigned radix) { int i; char *q; q = p + MAX_FILLER; do { i = (int)(num % radix); i += '0'; if (i > '9') i += 'A' - '0' - 10; *--q = i; } while ((num /= radix) != 0); i = (int)(p + MAX_FILLER - q); do *p++ = *q++; while (--i); return p; } /** * @brief System formatted output function. * @details This function implements a minimal @p printf() like functionality * with output on a @p BaseChannel. * The general parameters format is: %[-][width|*][.precision|*][l|L]p. * The following parameter types (p) are supported: * - x hexadecimal integer. * - X hexadecimal long. * - o octal integer. * - O octal long. * - d decimal signed integer. * - D decimal signed long. * - u decimal unsigned integer. * - U decimal unsigned long. * - c character. * - s string. * . * @note Floating point types are not implemented, this function is meant * as a system utility and not a full implementation. * * @param[in] chp pointer to a @p BaseChannel implementing object * @param[in] fmt formatting string */ void chprintf(BaseChannel *chp, const char *fmt, ...) { va_list ap; char tmpbuf[MAX_FILLER + 1]; char *p, *s, c, filler; int i, precision, width; bool_t is_long, left_align; long l; va_start(ap, fmt); while (TRUE) { c = *fmt++; if (c == 0) { va_end(ap); return; } if (c != '%') { chIOPut(chp, (uint8_t)c); continue; } p = tmpbuf; s = tmpbuf; left_align = FALSE; if (*fmt == '-') { fmt++; left_align = TRUE; } filler = ' '; if (*fmt == '.') { fmt++; filler = '0'; } width = 0; while (TRUE) { c = *fmt++; if (c >= '0' && c <= '9') c -= '0'; else if (c == '*') c = va_arg(ap, int); else break; width = width * 10 + c; } precision = 0; if (c == '.') { while (TRUE) { c = *fmt++; if (c >= '0' && c <= '9') c -= '0'; else if (c == '*') c = va_arg(ap, int); else break; precision *= 10; precision += c; } } /* Long modifier.*/ if (c == 'l' || c == 'L') { is_long = TRUE; if (*fmt) c = *fmt++; } else is_long = (c >= 'A') && (c <= 'Z'); /* Command decoding.*/ switch (c) { case 'c': filler = ' '; *p++ = va_arg(ap, int); break; case 's': filler = ' '; if ((s = va_arg(ap, char *)) == 0) s = "(null)"; if (precision == 0) precision = 32767; for (p = s; *p && (--precision >= 0); p++) ; break; case 'D': case 'd': if (is_long) l = va_arg(ap, long); else l = va_arg(ap, int); if (l < 0) { *p++ = '-'; l = -l; } p = ltoa(p, l, 10); break; case 'X': case 'x': c = 16; goto unsigned_common; case 'U': case 'u': c = 10; goto unsigned_common; case 'O': case 'o': c = 8; unsigned_common: if (is_long) l = va_arg(ap, long); else l = va_arg(ap, int); p = ltoa(p, l, c); break; default: *p++ = c; break; } i = (int)(p - s); if ((width -= i) < 0) width = 0; if (left_align == FALSE) width = -width; if (width < 0) { if (*s == '-' && filler == '0') { chIOPut(chp, (uint8_t)*s++); i--; } do chIOPut(chp, (uint8_t)filler); while (++width != 0); } while (--i >= 0) chIOPut(chp, (uint8_t)*s++); while (width) { chIOPut(chp, (uint8_t)filler); width--; } } } /** @} */