Appiko
tinyprintf.c
1 /*
2 Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of Kustaa Nyholm or SpareTimeLabs nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include "tinyprintf.h"
29 
30 
31 /*
32  * Configuration
33  */
34 
35 /* Enable long int support */
36 #define PRINTF_LONG_SUPPORT
37 
38 /* Enable long long int support (implies long int support) */
39 #define PRINTF_LONG_LONG_SUPPORT
40 
41 /* Enable %z (size_t) support */
42 #define PRINTF_SIZE_T_SUPPORT
43 
44 /*
45  * Configuration adjustments
46  */
47 #ifdef PRINTF_SIZE_T_SUPPORT
48 #include <sys/types.h>
49 #endif
50 
51 #ifdef PRINTF_LONG_LONG_SUPPORT
52 # define PRINTF_LONG_SUPPORT
53 #endif
54 
55 /* __SIZEOF_<type>__ defined at least by gcc */
56 #ifdef __SIZEOF_POINTER__
57 # define SIZEOF_POINTER __SIZEOF_POINTER__
58 #endif
59 #ifdef __SIZEOF_LONG_LONG__
60 # define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
61 #endif
62 #ifdef __SIZEOF_LONG__
63 # define SIZEOF_LONG __SIZEOF_LONG__
64 #endif
65 #ifdef __SIZEOF_INT__
66 # define SIZEOF_INT __SIZEOF_INT__
67 #endif
68 
69 #ifdef __GNUC__
70 # define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
71 #else
72 # define _TFP_GCC_NO_INLINE_
73 #endif
74 
75 /*
76  * Implementation
77  */
78 struct param {
79  char lz:1;
80  char alt:1;
81  char uc:1;
82  char align_left:1;
83  unsigned int width;
84  char sign;
85  unsigned int base;
86  char *bf;
87 };
88 
89 
90 #ifdef PRINTF_LONG_LONG_SUPPORT
91 static void _TFP_GCC_NO_INLINE_ ulli2a(
92  unsigned long long int num, struct param *p)
93 {
94  int n = 0;
95  unsigned long long int d = 1;
96  char *bf = p->bf;
97  while (num / d >= p->base)
98  d *= p->base;
99  while (d != 0) {
100  int dgt = num / d;
101  num %= d;
102  d /= p->base;
103  if (n || dgt > 0 || d == 0) {
104  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
105  ++n;
106  }
107  }
108  *bf = 0;
109 }
110 
111 static void lli2a(long long int num, struct param *p)
112 {
113  if (num < 0) {
114  num = -num;
115  p->sign = '-';
116  }
117  ulli2a(num, p);
118 }
119 #endif
120 
121 #ifdef PRINTF_LONG_SUPPORT
122 static void uli2a(unsigned long int num, struct param *p)
123 {
124  int n = 0;
125  unsigned long int d = 1;
126  char *bf = p->bf;
127  while (num / d >= p->base)
128  d *= p->base;
129  while (d != 0) {
130  int dgt = num / d;
131  num %= d;
132  d /= p->base;
133  if (n || dgt > 0 || d == 0) {
134  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
135  ++n;
136  }
137  }
138  *bf = 0;
139 }
140 
141 static void li2a(long num, struct param *p)
142 {
143  if (num < 0) {
144  num = -num;
145  p->sign = '-';
146  }
147  uli2a(num, p);
148 }
149 #endif
150 
151 static void ui2a(unsigned int num, struct param *p)
152 {
153  int n = 0;
154  unsigned int d = 1;
155  char *bf = p->bf;
156  while (num / d >= p->base)
157  d *= p->base;
158  while (d != 0) {
159  int dgt = num / d;
160  num %= d;
161  d /= p->base;
162  if (n || dgt > 0 || d == 0) {
163  *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
164  ++n;
165  }
166  }
167  *bf = 0;
168 }
169 
170 static void i2a(int num, struct param *p)
171 {
172  if (num < 0) {
173  num = -num;
174  p->sign = '-';
175  }
176  ui2a(num, p);
177 }
178 
179 static int a2d(char ch)
180 {
181  if (ch >= '0' && ch <= '9')
182  return ch - '0';
183  else if (ch >= 'a' && ch <= 'f')
184  return ch - 'a' + 10;
185  else if (ch >= 'A' && ch <= 'F')
186  return ch - 'A' + 10;
187  else
188  return -1;
189 }
190 
191 static char a2u(char ch, const char **src, int base, unsigned int *nump)
192 {
193  const char *p = *src;
194  unsigned int num = 0;
195  int digit;
196  while ((digit = a2d(ch)) >= 0) {
197  if (digit > base)
198  break;
199  num = num * base + digit;
200  ch = *p++;
201  }
202  *src = p;
203  *nump = num;
204  return ch;
205 }
206 
207 static void putchw(void *putp, putcf putf, struct param *p)
208 {
209  char ch;
210  int n = p->width;
211  char *bf = p->bf;
212 
213  /* Number of filling characters */
214  while (*bf++ && n > 0)
215  n--;
216  if (p->sign)
217  n--;
218  if (p->alt && p->base == 16)
219  n -= 2;
220  else if (p->alt && p->base == 8)
221  n--;
222 
223  /* Fill with space to align to the right, before alternate or sign */
224  if (!p->lz && !p->align_left) {
225  while (n-- > 0)
226  putf(putp, ' ');
227  }
228 
229  /* print sign */
230  if (p->sign)
231  putf(putp, p->sign);
232 
233  /* Alternate */
234  if (p->alt && p->base == 16) {
235  putf(putp, '0');
236  putf(putp, (p->uc ? 'X' : 'x'));
237  } else if (p->alt && p->base == 8) {
238  putf(putp, '0');
239  }
240 
241  /* Fill with zeros, after alternate or sign */
242  if (p->lz) {
243  while (n-- > 0)
244  putf(putp, '0');
245  }
246 
247  /* Put actual buffer */
248  bf = p->bf;
249  while ((ch = *bf++))
250  putf(putp, ch);
251 
252  /* Fill with space to align to the left, after string */
253  if (!p->lz && p->align_left) {
254  while (n-- > 0)
255  putf(putp, ' ');
256  }
257 }
258 
259 void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
260 {
261  struct param p;
262 #ifdef PRINTF_LONG_SUPPORT
263  char bf[23]; /* long = 64b on some architectures */
264 #else
265  char bf[12]; /* int = 32b on some architectures */
266 #endif
267  char ch;
268  p.bf = bf;
269 
270  while ((ch = *(fmt++))) {
271  if (ch != '%') {
272  putf(putp, ch);
273  } else {
274 #ifdef PRINTF_LONG_SUPPORT
275  char lng = 0; /* 1 for long, 2 for long long */
276 #endif
277  /* Init parameter struct */
278  p.lz = 0;
279  p.alt = 0;
280  p.width = 0;
281  p.align_left = 0;
282  p.sign = 0;
283 
284  /* Flags */
285  while ((ch = *(fmt++))) {
286  switch (ch) {
287  case '-':
288  p.align_left = 1;
289  continue;
290  case '0':
291  p.lz = 1;
292  continue;
293  case '#':
294  p.alt = 1;
295  continue;
296  default:
297  break;
298  }
299  break;
300  }
301 
302  /* Width */
303  if (ch >= '0' && ch <= '9') {
304  ch = a2u(ch, &fmt, 10, &(p.width));
305  }
306 
307  /* We accept 'x.y' format but don't support it completely:
308  * we ignore the 'y' digit => this ignores 0-fill
309  * size and makes it == width (ie. 'x') */
310  if (ch == '.') {
311  p.lz = 1; /* zero-padding */
312  /* ignore actual 0-fill size: */
313  do {
314  ch = *(fmt++);
315  } while ((ch >= '0') && (ch <= '9'));
316  }
317 
318 #ifdef PRINTF_SIZE_T_SUPPORT
319 # ifdef PRINTF_LONG_SUPPORT
320  if (ch == 'z') {
321  ch = *(fmt++);
322  if (sizeof(size_t) == sizeof(unsigned long int))
323  lng = 1;
324 # ifdef PRINTF_LONG_LONG_SUPPORT
325  else if (sizeof(size_t) == sizeof(unsigned long long int))
326  lng = 2;
327 # endif
328  } else
329 # endif
330 #endif
331 
332 #ifdef PRINTF_LONG_SUPPORT
333  if (ch == 'l') {
334  ch = *(fmt++);
335  lng = 1;
336 #ifdef PRINTF_LONG_LONG_SUPPORT
337  if (ch == 'l') {
338  ch = *(fmt++);
339  lng = 2;
340  }
341 #endif
342  }
343 #endif
344  switch (ch) {
345  case 0:
346  goto abort;
347  case 'u':
348  p.base = 10;
349 #ifdef PRINTF_LONG_SUPPORT
350 #ifdef PRINTF_LONG_LONG_SUPPORT
351  if (2 == lng)
352  ulli2a(va_arg(va, unsigned long long int), &p);
353  else
354 #endif
355  if (1 == lng)
356  uli2a(va_arg(va, unsigned long int), &p);
357  else
358 #endif
359  ui2a(va_arg(va, unsigned int), &p);
360  putchw(putp, putf, &p);
361  break;
362  case 'd':
363  case 'i':
364  p.base = 10;
365 #ifdef PRINTF_LONG_SUPPORT
366 #ifdef PRINTF_LONG_LONG_SUPPORT
367  if (2 == lng)
368  lli2a(va_arg(va, long long int), &p);
369  else
370 #endif
371  if (1 == lng)
372  li2a(va_arg(va, long int), &p);
373  else
374 #endif
375  i2a(va_arg(va, int), &p);
376  putchw(putp, putf, &p);
377  break;
378 #ifdef SIZEOF_POINTER
379  case 'p':
380  p.alt = 1;
381 # if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
382  lng = 0;
383 # elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
384  lng = 1;
385 # elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
386  lng = 2;
387 # endif
388 #endif
389  case 'x':
390  case 'X':
391  p.base = 16;
392  p.uc = (ch == 'X')?1:0;
393 #ifdef PRINTF_LONG_SUPPORT
394 #ifdef PRINTF_LONG_LONG_SUPPORT
395  if (2 == lng)
396  ulli2a(va_arg(va, unsigned long long int), &p);
397  else
398 #endif
399  if (1 == lng)
400  uli2a(va_arg(va, unsigned long int), &p);
401  else
402 #endif
403  ui2a(va_arg(va, unsigned int), &p);
404  putchw(putp, putf, &p);
405  break;
406  case 'o':
407  p.base = 8;
408  ui2a(va_arg(va, unsigned int), &p);
409  putchw(putp, putf, &p);
410  break;
411  case 'c':
412  putf(putp, (char)(va_arg(va, int)));
413  break;
414  case 's':
415  p.bf = va_arg(va, char *);
416  putchw(putp, putf, &p);
417  p.bf = bf;
418  break;
419  case '%':
420  putf(putp, ch);
421  default:
422  break;
423  }
424  }
425  }
426  abort:;
427 }
428 
429 #if TINYPRINTF_DEFINE_TFP_PRINTF
430 static putcf stdout_putf;
431 static void *stdout_putp;
432 
433 void init_printf(void *putp, putcf putf)
434 {
435  stdout_putf = putf;
436  stdout_putp = putp;
437 }
438 
439 void tfp_printf(char *fmt, ...)
440 {
441  va_list va;
442  va_start(va, fmt);
443  tfp_format(stdout_putp, stdout_putf, fmt, va);
444  //To inform that the printf line is done
445  stdout_putf((void *)START_TX,0);
446  va_end(va);
447 }
448 #endif
449 
450 #if TINYPRINTF_DEFINE_TFP_SPRINTF
451 struct _vsnprintf_putcf_data
452 {
453  size_t dest_capacity;
454  char *dest;
455  size_t num_chars;
456 };
457 
458 static void _vsnprintf_putcf(void *p, char c)
459 {
460  struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
461  if (data->num_chars < data->dest_capacity)
462  data->dest[data->num_chars] = c;
463  data->num_chars ++;
464 }
465 
466 int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
467 {
468  struct _vsnprintf_putcf_data data;
469 
470  if (size < 1)
471  return 0;
472 
473  data.dest = str;
474  data.dest_capacity = size-1;
475  data.num_chars = 0;
476  tfp_format(&data, _vsnprintf_putcf, format, ap);
477 
478  if (data.num_chars < data.dest_capacity)
479  data.dest[data.num_chars] = '\0';
480  else
481  data.dest[data.dest_capacity] = '\0';
482 
483  return data.num_chars;
484 }
485 
486 int tfp_snprintf(char *str, size_t size, const char *format, ...)
487 {
488  va_list ap;
489  int retval;
490 
491  va_start(ap, format);
492  retval = tfp_vsnprintf(str, size, format, ap);
493  va_end(ap);
494  return retval;
495 }
496 
497 struct _vsprintf_putcf_data
498 {
499  char *dest;
500  size_t num_chars;
501 };
502 
503 static void _vsprintf_putcf(void *p, char c)
504 {
505  struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
506  data->dest[data->num_chars++] = c;
507 }
508 
509 int tfp_vsprintf(char *str, const char *format, va_list ap)
510 {
511  struct _vsprintf_putcf_data data;
512  data.dest = str;
513  data.num_chars = 0;
514  tfp_format(&data, _vsprintf_putcf, format, ap);
515  data.dest[data.num_chars] = '\0';
516  return data.num_chars;
517 }
518 
519 int tfp_sprintf(char *str, const char *format, ...)
520 {
521  va_list ap;
522  int retval;
523 
524  va_start(ap, format);
525  retval = tfp_vsprintf(str, format, ap);
526  va_end(ap);
527  return retval;
528 }
529 #endif