A tiny printf for embedded applications - by Kustaa Nyholm

Dependents:   lpc1768-picotcp-demo

Committer:
tass
Date:
Fri May 17 12:49:09 2013 +0000
Revision:
0:aa3b196cf64f
supporting printf library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 0:aa3b196cf64f 1 /*
tass 0:aa3b196cf64f 2 File: printf.c
tass 0:aa3b196cf64f 3
tass 0:aa3b196cf64f 4 Copyright (C) 2004 Kustaa Nyholm
tass 0:aa3b196cf64f 5
tass 0:aa3b196cf64f 6 This library is free software; you can redistribute it and/or
tass 0:aa3b196cf64f 7 modify it under the terms of the GNU Lesser General Public
tass 0:aa3b196cf64f 8 License as published by the Free Software Foundation; either
tass 0:aa3b196cf64f 9 version 2.1 of the License, or (at your option) any later version.
tass 0:aa3b196cf64f 10
tass 0:aa3b196cf64f 11 This library is distributed in the hope that it will be useful,
tass 0:aa3b196cf64f 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
tass 0:aa3b196cf64f 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
tass 0:aa3b196cf64f 14 Lesser General Public License for more details.
tass 0:aa3b196cf64f 15
tass 0:aa3b196cf64f 16 You should have received a copy of the GNU Lesser General Public
tass 0:aa3b196cf64f 17 License along with this library; if not, write to the Free Software
tass 0:aa3b196cf64f 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
tass 0:aa3b196cf64f 19
tass 0:aa3b196cf64f 20 */
tass 0:aa3b196cf64f 21
tass 0:aa3b196cf64f 22 #include "printf.h"
tass 0:aa3b196cf64f 23
tass 0:aa3b196cf64f 24 typedef void (*putcf) (void *, char);
tass 0:aa3b196cf64f 25 static putcf stdout_putf;
tass 0:aa3b196cf64f 26 static void *stdout_putp;
tass 0:aa3b196cf64f 27
tass 0:aa3b196cf64f 28 struct param {
tass 0:aa3b196cf64f 29 char lz; /**< Leading zeros */
tass 0:aa3b196cf64f 30 unsigned int width; /**< field width */
tass 0:aa3b196cf64f 31 char sign; /**< The sign to display (if any) */
tass 0:aa3b196cf64f 32 char alt; /**< alternate form */
tass 0:aa3b196cf64f 33 unsigned int base; /**< number base (e.g.: 8, 10, 16) */
tass 0:aa3b196cf64f 34 char uc; /**< Upper case (for base16 only) */
tass 0:aa3b196cf64f 35 char *bf; /**< Buffer to output */
tass 0:aa3b196cf64f 36 };
tass 0:aa3b196cf64f 37
tass 0:aa3b196cf64f 38 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 39
tass 0:aa3b196cf64f 40 static void uli2a(unsigned long int num, struct param *p)
tass 0:aa3b196cf64f 41 {
tass 0:aa3b196cf64f 42 int n = 0;
tass 0:aa3b196cf64f 43 unsigned long int d = 1;
tass 0:aa3b196cf64f 44 char *bf = p->bf;
tass 0:aa3b196cf64f 45 while (num / d >= p->base)
tass 0:aa3b196cf64f 46 d *= p->base;
tass 0:aa3b196cf64f 47 while (d != 0) {
tass 0:aa3b196cf64f 48 int dgt = num / d;
tass 0:aa3b196cf64f 49 num %= d;
tass 0:aa3b196cf64f 50 d /= p->base;
tass 0:aa3b196cf64f 51 if (n || dgt > 0 || d == 0) {
tass 0:aa3b196cf64f 52 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
tass 0:aa3b196cf64f 53 ++n;
tass 0:aa3b196cf64f 54 }
tass 0:aa3b196cf64f 55 }
tass 0:aa3b196cf64f 56 *bf = 0;
tass 0:aa3b196cf64f 57 }
tass 0:aa3b196cf64f 58
tass 0:aa3b196cf64f 59 static void li2a(long num, struct param *p)
tass 0:aa3b196cf64f 60 {
tass 0:aa3b196cf64f 61 if (num < 0) {
tass 0:aa3b196cf64f 62 num = -num;
tass 0:aa3b196cf64f 63 p->sign = '-';
tass 0:aa3b196cf64f 64 }
tass 0:aa3b196cf64f 65 uli2a(num, p);
tass 0:aa3b196cf64f 66 }
tass 0:aa3b196cf64f 67 #endif
tass 0:aa3b196cf64f 68
tass 0:aa3b196cf64f 69 static void ui2a(unsigned int num, struct param *p)
tass 0:aa3b196cf64f 70 {
tass 0:aa3b196cf64f 71 int n = 0;
tass 0:aa3b196cf64f 72 unsigned int d = 1;
tass 0:aa3b196cf64f 73 char *bf = p->bf;
tass 0:aa3b196cf64f 74 while (num / d >= p->base)
tass 0:aa3b196cf64f 75 d *= p->base;
tass 0:aa3b196cf64f 76 while (d != 0) {
tass 0:aa3b196cf64f 77 int dgt = num / d;
tass 0:aa3b196cf64f 78 num %= d;
tass 0:aa3b196cf64f 79 d /= p->base;
tass 0:aa3b196cf64f 80 if (n || dgt > 0 || d == 0) {
tass 0:aa3b196cf64f 81 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
tass 0:aa3b196cf64f 82 ++n;
tass 0:aa3b196cf64f 83 }
tass 0:aa3b196cf64f 84 }
tass 0:aa3b196cf64f 85 *bf = 0;
tass 0:aa3b196cf64f 86 }
tass 0:aa3b196cf64f 87
tass 0:aa3b196cf64f 88 static void i2a(int num, struct param *p)
tass 0:aa3b196cf64f 89 {
tass 0:aa3b196cf64f 90 if (num < 0) {
tass 0:aa3b196cf64f 91 num = -num;
tass 0:aa3b196cf64f 92 p->sign = '-';
tass 0:aa3b196cf64f 93 }
tass 0:aa3b196cf64f 94 ui2a(num, p);
tass 0:aa3b196cf64f 95 }
tass 0:aa3b196cf64f 96
tass 0:aa3b196cf64f 97 static int a2d(char ch)
tass 0:aa3b196cf64f 98 {
tass 0:aa3b196cf64f 99 if (ch >= '0' && ch <= '9')
tass 0:aa3b196cf64f 100 return ch - '0';
tass 0:aa3b196cf64f 101 else if (ch >= 'a' && ch <= 'f')
tass 0:aa3b196cf64f 102 return ch - 'a' + 10;
tass 0:aa3b196cf64f 103 else if (ch >= 'A' && ch <= 'F')
tass 0:aa3b196cf64f 104 return ch - 'A' + 10;
tass 0:aa3b196cf64f 105 else
tass 0:aa3b196cf64f 106 return -1;
tass 0:aa3b196cf64f 107 }
tass 0:aa3b196cf64f 108
tass 0:aa3b196cf64f 109 static char a2i(char ch, char **src, int base, int *nump)
tass 0:aa3b196cf64f 110 {
tass 0:aa3b196cf64f 111 char *p = *src;
tass 0:aa3b196cf64f 112 int num = 0;
tass 0:aa3b196cf64f 113 int digit;
tass 0:aa3b196cf64f 114 while ((digit = a2d(ch)) >= 0) {
tass 0:aa3b196cf64f 115 if (digit > base)
tass 0:aa3b196cf64f 116 break;
tass 0:aa3b196cf64f 117 num = num * base + digit;
tass 0:aa3b196cf64f 118 ch = *p++;
tass 0:aa3b196cf64f 119 }
tass 0:aa3b196cf64f 120 *src = p;
tass 0:aa3b196cf64f 121 *nump = num;
tass 0:aa3b196cf64f 122 return ch;
tass 0:aa3b196cf64f 123 }
tass 0:aa3b196cf64f 124
tass 0:aa3b196cf64f 125 static void putchw(void *putp, putcf putf, struct param *p)
tass 0:aa3b196cf64f 126 {
tass 0:aa3b196cf64f 127 char ch;
tass 0:aa3b196cf64f 128 int n = p->width;
tass 0:aa3b196cf64f 129 char *bf = p->bf;
tass 0:aa3b196cf64f 130
tass 0:aa3b196cf64f 131 /* Number of filling characters */
tass 0:aa3b196cf64f 132 while (*bf++ && n > 0)
tass 0:aa3b196cf64f 133 n--;
tass 0:aa3b196cf64f 134 if (p->sign)
tass 0:aa3b196cf64f 135 n--;
tass 0:aa3b196cf64f 136 if (p->alt && p->base == 16)
tass 0:aa3b196cf64f 137 n -= 2;
tass 0:aa3b196cf64f 138 else if (p->alt && p->base == 8)
tass 0:aa3b196cf64f 139 n--;
tass 0:aa3b196cf64f 140
tass 0:aa3b196cf64f 141 /* Fill with space, before alternate or sign */
tass 0:aa3b196cf64f 142 if (!p->lz) {
tass 0:aa3b196cf64f 143 while (n-- > 0)
tass 0:aa3b196cf64f 144 putf(putp, ' ');
tass 0:aa3b196cf64f 145 }
tass 0:aa3b196cf64f 146
tass 0:aa3b196cf64f 147 /* print sign */
tass 0:aa3b196cf64f 148 if (p->sign)
tass 0:aa3b196cf64f 149 putf(putp, p->sign);
tass 0:aa3b196cf64f 150
tass 0:aa3b196cf64f 151 /* Alternate */
tass 0:aa3b196cf64f 152 if (p->alt && p->base == 16) {
tass 0:aa3b196cf64f 153 putf(putp, '0');
tass 0:aa3b196cf64f 154 putf(putp, (p->uc ? 'X' : 'x'));
tass 0:aa3b196cf64f 155 } else if (p->alt && p->base == 8) {
tass 0:aa3b196cf64f 156 putf(putp, '0');
tass 0:aa3b196cf64f 157 }
tass 0:aa3b196cf64f 158
tass 0:aa3b196cf64f 159 /* Fill with zeros, after alternate or sign */
tass 0:aa3b196cf64f 160 if (p->lz) {
tass 0:aa3b196cf64f 161 while (n-- > 0)
tass 0:aa3b196cf64f 162 putf(putp, '0');
tass 0:aa3b196cf64f 163 }
tass 0:aa3b196cf64f 164
tass 0:aa3b196cf64f 165 /* Put actual buffer */
tass 0:aa3b196cf64f 166 bf = p->bf;
tass 0:aa3b196cf64f 167 while ((ch = *bf++))
tass 0:aa3b196cf64f 168 putf(putp, ch);
tass 0:aa3b196cf64f 169 }
tass 0:aa3b196cf64f 170
tass 0:aa3b196cf64f 171 void tfp_format(void *putp, putcf putf, char *fmt, va_list va)
tass 0:aa3b196cf64f 172 {
tass 0:aa3b196cf64f 173 struct param p;
tass 0:aa3b196cf64f 174 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 175 char bf[23];
tass 0:aa3b196cf64f 176 #else
tass 0:aa3b196cf64f 177 char bf[12];
tass 0:aa3b196cf64f 178 #endif
tass 0:aa3b196cf64f 179 p.bf = bf;
tass 0:aa3b196cf64f 180
tass 0:aa3b196cf64f 181 char ch;
tass 0:aa3b196cf64f 182
tass 0:aa3b196cf64f 183 while ((ch = *(fmt++))) {
tass 0:aa3b196cf64f 184 if (ch != '%') {
tass 0:aa3b196cf64f 185 putf(putp, ch);
tass 0:aa3b196cf64f 186 } else {
tass 0:aa3b196cf64f 187 /* Init parameter struct */
tass 0:aa3b196cf64f 188 p.lz = 0;
tass 0:aa3b196cf64f 189 p.alt = 0;
tass 0:aa3b196cf64f 190 p.width = 0;
tass 0:aa3b196cf64f 191 p.sign = 0;
tass 0:aa3b196cf64f 192 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 193 char lng = 0;
tass 0:aa3b196cf64f 194 #endif
tass 0:aa3b196cf64f 195
tass 0:aa3b196cf64f 196 /* Flags */
tass 0:aa3b196cf64f 197 while ((ch = *(fmt++))) {
tass 0:aa3b196cf64f 198 switch (ch) {
tass 0:aa3b196cf64f 199 case '0':
tass 0:aa3b196cf64f 200 p.lz = 1;
tass 0:aa3b196cf64f 201 continue;
tass 0:aa3b196cf64f 202 case '#':
tass 0:aa3b196cf64f 203 p.alt = 1;
tass 0:aa3b196cf64f 204 continue;
tass 0:aa3b196cf64f 205 default:
tass 0:aa3b196cf64f 206 break;
tass 0:aa3b196cf64f 207 }
tass 0:aa3b196cf64f 208 break;
tass 0:aa3b196cf64f 209 }
tass 0:aa3b196cf64f 210
tass 0:aa3b196cf64f 211 /* Width */
tass 0:aa3b196cf64f 212 if (ch >= '0' && ch <= '9') {
tass 0:aa3b196cf64f 213 ch = a2i(ch, &fmt, 10, &(p.width));
tass 0:aa3b196cf64f 214 }
tass 0:aa3b196cf64f 215 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 216 if (ch == 'l') {
tass 0:aa3b196cf64f 217 ch = *(fmt++);
tass 0:aa3b196cf64f 218 lng = 1;
tass 0:aa3b196cf64f 219 }
tass 0:aa3b196cf64f 220 #endif
tass 0:aa3b196cf64f 221 switch (ch) {
tass 0:aa3b196cf64f 222 case 0:
tass 0:aa3b196cf64f 223 goto abort;
tass 0:aa3b196cf64f 224 case 'u':
tass 0:aa3b196cf64f 225 p.base = 10;
tass 0:aa3b196cf64f 226 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 227 if (lng)
tass 0:aa3b196cf64f 228 uli2a(va_arg(va, unsigned long int), &p);
tass 0:aa3b196cf64f 229 else
tass 0:aa3b196cf64f 230 #endif
tass 0:aa3b196cf64f 231 ui2a(va_arg(va, unsigned int), &p);
tass 0:aa3b196cf64f 232 putchw(putp, putf, &p);
tass 0:aa3b196cf64f 233 break;
tass 0:aa3b196cf64f 234 case 'd':
tass 0:aa3b196cf64f 235 case 'i':
tass 0:aa3b196cf64f 236 p.base = 10;
tass 0:aa3b196cf64f 237 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 238 if (lng)
tass 0:aa3b196cf64f 239 li2a(va_arg(va, unsigned long int), &p);
tass 0:aa3b196cf64f 240 else
tass 0:aa3b196cf64f 241 #endif
tass 0:aa3b196cf64f 242 i2a(va_arg(va, int), &p);
tass 0:aa3b196cf64f 243 putchw(putp, putf, &p);
tass 0:aa3b196cf64f 244 break;
tass 0:aa3b196cf64f 245 case 'x':
tass 0:aa3b196cf64f 246 case 'X':
tass 0:aa3b196cf64f 247 p.base = 16;
tass 0:aa3b196cf64f 248 p.uc = (ch == 'X');
tass 0:aa3b196cf64f 249 #ifdef PRINTF_LONG_SUPPORT
tass 0:aa3b196cf64f 250 if (lng)
tass 0:aa3b196cf64f 251 uli2a(va_arg(va, unsigned long int), &p);
tass 0:aa3b196cf64f 252 else
tass 0:aa3b196cf64f 253 #endif
tass 0:aa3b196cf64f 254 ui2a(va_arg(va, unsigned int), &p);
tass 0:aa3b196cf64f 255 putchw(putp, putf, &p);
tass 0:aa3b196cf64f 256 break;
tass 0:aa3b196cf64f 257 case 'o':
tass 0:aa3b196cf64f 258 p.base = 8;
tass 0:aa3b196cf64f 259 ui2a(va_arg(va, unsigned int), &p);
tass 0:aa3b196cf64f 260 putchw(putp, putf, &p);
tass 0:aa3b196cf64f 261 break;
tass 0:aa3b196cf64f 262 case 'c':
tass 0:aa3b196cf64f 263 putf(putp, (char)(va_arg(va, int)));
tass 0:aa3b196cf64f 264 break;
tass 0:aa3b196cf64f 265 case 's':
tass 0:aa3b196cf64f 266 p.bf = va_arg(va, char *);
tass 0:aa3b196cf64f 267 putchw(putp, putf, &p);
tass 0:aa3b196cf64f 268 p.bf = bf;
tass 0:aa3b196cf64f 269 break;
tass 0:aa3b196cf64f 270 case '%':
tass 0:aa3b196cf64f 271 putf(putp, ch);
tass 0:aa3b196cf64f 272 default:
tass 0:aa3b196cf64f 273 break;
tass 0:aa3b196cf64f 274 }
tass 0:aa3b196cf64f 275 }
tass 0:aa3b196cf64f 276 }
tass 0:aa3b196cf64f 277 abort:;
tass 0:aa3b196cf64f 278 }
tass 0:aa3b196cf64f 279
tass 0:aa3b196cf64f 280 void init_printf(void *putp, void (*putf) (void *, char))
tass 0:aa3b196cf64f 281 {
tass 0:aa3b196cf64f 282 stdout_putf = putf;
tass 0:aa3b196cf64f 283 stdout_putp = putp;
tass 0:aa3b196cf64f 284 }
tass 0:aa3b196cf64f 285
tass 0:aa3b196cf64f 286 void tfp_printf(char *fmt, ...)
tass 0:aa3b196cf64f 287 {
tass 0:aa3b196cf64f 288 va_list va;
tass 0:aa3b196cf64f 289 va_start(va, fmt);
tass 0:aa3b196cf64f 290 tfp_format(stdout_putp, stdout_putf, fmt, va);
tass 0:aa3b196cf64f 291 va_end(va);
tass 0:aa3b196cf64f 292 }
tass 0:aa3b196cf64f 293
tass 0:aa3b196cf64f 294 static void putcp(void *p, char c)
tass 0:aa3b196cf64f 295 {
tass 0:aa3b196cf64f 296 *(*((char **)p))++ = c;
tass 0:aa3b196cf64f 297 }
tass 0:aa3b196cf64f 298
tass 0:aa3b196cf64f 299 void tfp_sprintf(char *s, char *fmt, ...)
tass 0:aa3b196cf64f 300 {
tass 0:aa3b196cf64f 301 va_list va;
tass 0:aa3b196cf64f 302 va_start(va, fmt);
tass 0:aa3b196cf64f 303 tfp_format(&s, putcp, fmt, va);
tass 0:aa3b196cf64f 304 putcp(&s, 0);
tass 0:aa3b196cf64f 305 va_end(va);
tass 0:aa3b196cf64f 306 }