MeterLogger
tinyprintf.c
Go to the documentation of this file.
1 /*
2 File: tinyprintf.c
3 
4 Copyright (C) 2004 Kustaa Nyholm
5 
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10 
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20 */
21 
22 #include <esp8266.h>
23 
24 #include "tinyprintf.h"
25 
26 
27 /*
28  * Configuration
29  */
30 
31 /* Enable long int support */
32 #define PRINTF_LONG_SUPPORT
33 
34 /* Enable long long int support (implies long int support) */
35 #define PRINTF_LONG_LONG_SUPPORT
36 
37 /* Enable %z (size_t) support */
38 #define PRINTF_SIZE_T_SUPPORT
39 
40 /*
41  * Configuration adjustments
42  */
43 #ifdef PRINTF_SIZE_T_SUPPORT
44 #include <sys/types.h>
45 #endif
46 
47 #ifdef PRINTF_LONG_LONG_SUPPORT
48 # define PRINTF_LONG_SUPPORT
49 #endif
50 
51 /* __SIZEOF_<type>__ defined at least by gcc */
52 #ifdef __SIZEOF_POINTER__
53 # define SIZEOF_POINTER __SIZEOF_POINTER__
54 #endif
55 #ifdef __SIZEOF_LONG_LONG__
56 # define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
57 #endif
58 #ifdef __SIZEOF_LONG__
59 # define SIZEOF_LONG __SIZEOF_LONG__
60 #endif
61 #ifdef __SIZEOF_INT__
62 # define SIZEOF_INT __SIZEOF_INT__
63 #endif
64 
65 #ifdef __GNUC__
66 # define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
67 #else
68 # define _TFP_GCC_NO_INLINE_
69 #endif
70 
71 /*
72  * Implementation
73  */
74 struct param {
75  char lz:1; /**< Leading zeros */
76  char alt:1; /**< alternate form */
77  char uc:1; /**< Upper case (for base16 only) */
78  char align_left:1; /**< 0 == align right (default), 1 == align left */
79  unsigned int width; /**< field width */
80  char sign; /**< The sign to display (if any) */
81  unsigned int base; /**< number base (e.g.: 8, 10, 16) */
82  char *bf; /**< Buffer to output */
83 };
84 
85 
86 #ifdef PRINTF_LONG_LONG_SUPPORT
88  unsigned long long int num, struct param *p)
89 {
90  int n = 0;
91  unsigned long long int d = 1;
92  char *bf = p->bf;
93  while (num / d >= p->base)
94  d *= p->base;
95  while (d != 0) {
96  int dgt = num / d;
97  num %= d;
98  d /= p->base;
99  if (n || dgt > 0 || d == 0) {
100  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
101  ++n;
102  }
103  }
104  *bf = 0;
105 }
106 
107 ICACHE_FLASH_ATTR static void lli2a(long long int num, struct param *p)
108 {
109  if (num < 0) {
110  num = -num;
111  p->sign = '-';
112  }
113  ulli2a(num, p);
114 }
115 #endif
116 
117 #ifdef PRINTF_LONG_SUPPORT
118 ICACHE_FLASH_ATTR static void uli2a(unsigned long int num, struct param *p)
119 {
120  int n = 0;
121  unsigned long int d = 1;
122  char *bf = p->bf;
123  while (num / d >= p->base)
124  d *= p->base;
125  while (d != 0) {
126  int dgt = num / d;
127  num %= d;
128  d /= p->base;
129  if (n || dgt > 0 || d == 0) {
130  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
131  ++n;
132  }
133  }
134  *bf = 0;
135 }
136 
137 ICACHE_FLASH_ATTR static void li2a(long num, struct param *p)
138 {
139  if (num < 0) {
140  num = -num;
141  p->sign = '-';
142  }
143  uli2a(num, p);
144 }
145 #endif
146 
147 ICACHE_FLASH_ATTR static void ui2a(unsigned int num, struct param *p)
148 {
149  int n = 0;
150  unsigned int d = 1;
151  char *bf = p->bf;
152  while (num / d >= p->base)
153  d *= p->base;
154  while (d != 0) {
155  int dgt = num / d;
156  num %= d;
157  d /= p->base;
158  if (n || dgt > 0 || d == 0) {
159  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
160  ++n;
161  }
162  }
163  *bf = 0;
164 }
165 
166 ICACHE_FLASH_ATTR static void i2a(int num, struct param *p)
167 {
168  if (num < 0) {
169  num = -num;
170  p->sign = '-';
171  }
172  ui2a(num, p);
173 }
174 
175 ICACHE_FLASH_ATTR static int a2d(char ch)
176 {
177  if (ch >= '0' && ch <= '9')
178  return ch - '0';
179  else if (ch >= 'a' && ch <= 'f')
180  return ch - 'a' + 10;
181  else if (ch >= 'A' && ch <= 'F')
182  return ch - 'A' + 10;
183  else
184  return -1;
185 }
186 
187 ICACHE_FLASH_ATTR static char a2u(char ch, const char **src, int base, unsigned int *nump)
188 {
189  const char *p = *src;
190  unsigned int num = 0;
191  int digit;
192  while ((digit = a2d(ch)) >= 0) {
193  if (digit > base)
194  break;
195  num = num * base + digit;
196  ch = *p++;
197  }
198  *src = p;
199  *nump = num;
200  return ch;
201 }
202 
203 ICACHE_FLASH_ATTR static void putchw(void *putp, putcf putf, struct param *p)
204 {
205  char ch;
206  int n = p->width;
207  char *bf = p->bf;
208 
209  /* Number of filling characters */
210  while (*bf++ && n > 0)
211  n--;
212  if (p->sign)
213  n--;
214  if (p->alt && p->base == 16)
215  n -= 2;
216  else if (p->alt && p->base == 8)
217  n--;
218 
219  /* Fill with space to align to the right, before alternate or sign */
220  if (!p->lz && !p->align_left) {
221  while (n-- > 0)
222  putf(putp, ' ');
223  }
224 
225  /* print sign */
226  if (p->sign)
227  putf(putp, p->sign);
228 
229  /* Alternate */
230  if (p->alt && p->base == 16) {
231  putf(putp, '0');
232  putf(putp, (p->uc ? 'X' : 'x'));
233  } else if (p->alt && p->base == 8) {
234  putf(putp, '0');
235  }
236 
237  /* Fill with zeros, after alternate or sign */
238  if (p->lz) {
239  while (n-- > 0)
240  putf(putp, '0');
241  }
242 
243  /* Put actual buffer */
244  bf = p->bf;
245  while ((ch = *bf++))
246  putf(putp, ch);
247 
248  /* Fill with space to align to the left, after string */
249  if (!p->lz && p->align_left) {
250  while (n-- > 0)
251  putf(putp, ' ');
252  }
253 }
254 
255 ICACHE_FLASH_ATTR void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
256 {
257  struct param p;
258 #ifdef PRINTF_LONG_SUPPORT
259  char bf[23]; /* long = 64b on some architectures */
260 #else
261  char bf[12]; /* int = 32b on some architectures */
262 #endif
263  char ch;
264  p.bf = bf;
265 
266  while ((ch = *(fmt++))) {
267  if (ch != '%') {
268  putf(putp, ch);
269  } else {
270 #ifdef PRINTF_LONG_SUPPORT
271  char lng = 0; /* 1 for long, 2 for long long */
272 #endif
273  /* Init parameter struct */
274  p.lz = 0;
275  p.alt = 0;
276  p.width = 0;
277  p.align_left = 0;
278  p.sign = 0;
279 
280  /* Flags */
281  while ((ch = *(fmt++))) {
282  switch (ch) {
283  case '-':
284  p.align_left = 1;
285  continue;
286  case '0':
287  p.lz = 1;
288  continue;
289  case '#':
290  p.alt = 1;
291  continue;
292  default:
293  break;
294  }
295  break;
296  }
297 
298  /* Width */
299  if (ch >= '0' && ch <= '9') {
300  ch = a2u(ch, &fmt, 10, &(p.width));
301  }
302 
303  /* We accept 'x.y' format but don't support it completely:
304  * we ignore the 'y' digit => this ignores 0-fill
305  * size and makes it == width (ie. 'x') */
306  if (ch == '.') {
307  p.lz = 1; /* zero-padding */
308  /* ignore actual 0-fill size: */
309  do {
310  ch = *(fmt++);
311  } while ((ch >= '0') && (ch <= '9'));
312  }
313 
314 #ifdef PRINTF_SIZE_T_SUPPORT
315 # ifdef PRINTF_LONG_SUPPORT
316  if (ch == 'z') {
317  ch = *(fmt++);
318  if (sizeof(size_t) == sizeof(unsigned long int))
319  lng = 1;
320 # ifdef PRINTF_LONG_LONG_SUPPORT
321  else if (sizeof(size_t) == sizeof(unsigned long long int))
322  lng = 2;
323 # endif
324  } else
325 # endif
326 #endif
327 
328 #ifdef PRINTF_LONG_SUPPORT
329  if (ch == 'l') {
330  ch = *(fmt++);
331  lng = 1;
332 #ifdef PRINTF_LONG_LONG_SUPPORT
333  if (ch == 'l') {
334  ch = *(fmt++);
335  lng = 2;
336  }
337 #endif
338  }
339 #endif
340  switch (ch) {
341  case 0:
342  goto abort;
343  case 'u':
344  p.base = 10;
345 #ifdef PRINTF_LONG_SUPPORT
346 #ifdef PRINTF_LONG_LONG_SUPPORT
347  if (2 == lng)
348  ulli2a(va_arg(va, unsigned long long int), &p);
349  else
350 #endif
351  if (1 == lng)
352  uli2a(va_arg(va, unsigned long int), &p);
353  else
354 #endif
355  ui2a(va_arg(va, unsigned int), &p);
356  putchw(putp, putf, &p);
357  break;
358  case 'd':
359  case 'i':
360  p.base = 10;
361 #ifdef PRINTF_LONG_SUPPORT
362 #ifdef PRINTF_LONG_LONG_SUPPORT
363  if (2 == lng)
364  lli2a(va_arg(va, long long int), &p);
365  else
366 #endif
367  if (1 == lng)
368  li2a(va_arg(va, long int), &p);
369  else
370 #endif
371  i2a(va_arg(va, int), &p);
372  putchw(putp, putf, &p);
373  break;
374 #ifdef SIZEOF_POINTER
375  case 'p':
376  p.alt = 1;
377 # if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
378  lng = 0;
379 # elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
380  lng = 1;
381 # elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
382  lng = 2;
383 # endif
384 #endif
385  case 'x':
386  case 'X':
387  p.base = 16;
388  p.uc = (ch == 'X')?1:0;
389 #ifdef PRINTF_LONG_SUPPORT
390 #ifdef PRINTF_LONG_LONG_SUPPORT
391  if (2 == lng)
392  ulli2a(va_arg(va, unsigned long long int), &p);
393  else
394 #endif
395  if (1 == lng)
396  uli2a(va_arg(va, unsigned long int), &p);
397  else
398 #endif
399  ui2a(va_arg(va, unsigned int), &p);
400  putchw(putp, putf, &p);
401  break;
402  case 'o':
403  p.base = 8;
404  ui2a(va_arg(va, unsigned int), &p);
405  putchw(putp, putf, &p);
406  break;
407  case 'c':
408  putf(putp, (char)(va_arg(va, int)));
409  break;
410  case 's':
411  p.bf = va_arg(va, char *);
412  putchw(putp, putf, &p);
413  p.bf = bf;
414  break;
415  case '%':
416  putf(putp, ch);
417  default:
418  break;
419  }
420  }
421  }
422  abort:;
423 }
424 
425 #if TINYPRINTF_DEFINE_TFP_PRINTF
427 static void *stdout_putp;
428 
429 ICACHE_FLASH_ATTR void init_printf(void *putp, putcf putf)
430 {
431  stdout_putf = putf;
432  stdout_putp = putp;
433 }
434 
435 ICACHE_FLASH_ATTR void tfp_printf(char *fmt, ...)
436 {
437  va_list va;
438  va_start(va, fmt);
440  va_end(va);
441 }
442 #endif
443 
444 #if TINYPRINTF_DEFINE_TFP_SPRINTF
446 {
448  char *dest;
449  size_t num_chars;
450 };
451 
452 ICACHE_FLASH_ATTR static void _vsnprintf_putcf(void *p, char c)
453 {
454  struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
455  if (data->num_chars < data->dest_capacity)
456  data->dest[data->num_chars] = c;
457  data->num_chars ++;
458 }
459 
460 ICACHE_FLASH_ATTR int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
461 {
462  struct _vsnprintf_putcf_data data;
463 
464  if (size < 1)
465  return 0;
466 
467  data.dest = str;
468  data.dest_capacity = size-1;
469  data.num_chars = 0;
470  tfp_format(&data, _vsnprintf_putcf, format, ap);
471 
472  if (data.num_chars < data.dest_capacity)
473  data.dest[data.num_chars] = '\0';
474  else
475  data.dest[data.dest_capacity] = '\0';
476 
477  return data.num_chars;
478 }
479 
480 ICACHE_FLASH_ATTR int tfp_snprintf(char *str, size_t size, const char *format, ...)
481 {
482  va_list ap;
483  int retval;
484 
485  va_start(ap, format);
486  retval = tfp_vsnprintf(str, size, format, ap);
487  va_end(ap);
488  return retval;
489 }
490 
492 {
493  char *dest;
494  size_t num_chars;
495 };
496 
497 ICACHE_FLASH_ATTR static void _vsprintf_putcf(void *p, char c)
498 {
499  struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
500  data->dest[data->num_chars++] = c;
501 }
502 
503 ICACHE_FLASH_ATTR int tfp_vsprintf(char *str, const char *format, va_list ap)
504 {
505  struct _vsprintf_putcf_data data;
506  data.dest = str;
507  data.num_chars = 0;
508  tfp_format(&data, _vsprintf_putcf, format, ap);
509  data.dest[data.num_chars] = '\0';
510  return data.num_chars;
511 }
512 
513 ICACHE_FLASH_ATTR int tfp_sprintf(char *str, const char *format, ...)
514 {
515  va_list ap;
516  int retval;
517 
518  va_start(ap, format);
519  retval = tfp_vsprintf(str, format, ap);
520  va_end(ap);
521  return retval;
522 }
523 #endif
static ICACHE_FLASH_ATTR void lli2a(long long int num, struct param *p)
Definition: tinyprintf.c:107
ICACHE_FLASH_ATTR void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
Definition: tinyprintf.c:255
ICACHE_FLASH_ATTR int tfp_vsprintf(char *str, const char *format, va_list ap)
Definition: tinyprintf.c:503
static ICACHE_FLASH_ATTR void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, struct param *p)
Definition: tinyprintf.c:87
static ICACHE_FLASH_ATTR void uli2a(unsigned long int num, struct param *p)
Definition: tinyprintf.c:118
static putcf stdout_putf
Definition: tinyprintf.c:426
static ICACHE_FLASH_ATTR char a2u(char ch, const char **src, int base, unsigned int *nump)
Definition: tinyprintf.c:187
char uc
Definition: tinyprintf.c:77
ICACHE_FLASH_ATTR int tfp_sprintf(char *str, const char *format,...)
Definition: tinyprintf.c:513
#define ICACHE_FLASH_ATTR
Definition: c_types.h:99
char sign
Definition: tinyprintf.c:80
char alt
Definition: tinyprintf.c:76
#define _TFP_GCC_NO_INLINE_
Definition: tinyprintf.c:68
static ICACHE_FLASH_ATTR void _vsnprintf_putcf(void *p, char c)
Definition: tinyprintf.c:452
static ICACHE_FLASH_ATTR void putchw(void *putp, putcf putf, struct param *p)
Definition: tinyprintf.c:203
unsigned int base
Definition: tinyprintf.c:81
ICACHE_FLASH_ATTR int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Definition: tinyprintf.c:460
static void * stdout_putp
Definition: tinyprintf.c:427
ICACHE_FLASH_ATTR void init_printf(void *putp, putcf putf)
Definition: tinyprintf.c:429
ICACHE_FLASH_ATTR void tfp_printf(char *fmt,...)
Definition: tinyprintf.c:435
static ICACHE_FLASH_ATTR void ui2a(unsigned int num, struct param *p)
Definition: tinyprintf.c:147
static ICACHE_FLASH_ATTR void _vsprintf_putcf(void *p, char c)
Definition: tinyprintf.c:497
char align_left
Definition: tinyprintf.c:78
unsigned int width
Definition: tinyprintf.c:79
ICACHE_FLASH_ATTR int tfp_snprintf(char *str, size_t size, const char *format,...)
Definition: tinyprintf.c:480
void(* putcf)(void *, char)
Definition: tinyprintf.h:145
char * bf
Definition: tinyprintf.c:82
char lz
Definition: tinyprintf.c:75
static ICACHE_FLASH_ATTR void li2a(long num, struct param *p)
Definition: tinyprintf.c:137
static ICACHE_FLASH_ATTR void i2a(int num, struct param *p)
Definition: tinyprintf.c:166
static ICACHE_FLASH_ATTR int a2d(char ch)
Definition: tinyprintf.c:175