Contiki 3.x
stdio.c
1 /*
2  File: printf.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 "stdio.h"
23 #include "string.h"
24 
25 typedef void (*putcf) (void *, char);
26 static putcf stdout_putf;
27 static void *stdout_putp;
28 static char stdout_inited = 0;
29 
30 #ifdef PRINTF_LONG_SUPPORT
31 
32 static void
33 uli2a(unsigned long num, unsigned long base, int uc, char *bf_out)
34 {
35  int n = 0;
36  unsigned long d = 1;
37  char bf_tmp[12];
38  char *bf = bf_tmp;
39 
40  while(num / d >= base)
41  d *= base;
42  while(d != 0L) {
43  int dgt = num / d;
44  num %= d;
45  d /= base;
46  if(n || dgt > 0 || d == 0) {
47  *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
48  ++n;
49  }
50  }
51  *bf = 0;
52  while(n++ < 8 && base == 16) {
53  *bf_out++ = '0';
54  }
55  strcpy(bf_out, bf_tmp);
56 }
57 static void
58 li2a(long num, char *bf)
59 {
60  if(num < 0L) {
61  num = -num;
62  *bf++ = '-';
63  }
64  uli2a(num, 10, 0, bf);
65 }
66 #endif
67 
68 #ifdef PRINTF_FLOAT_SUPPORT
69 unsigned long decimal_array[6] = { 0, 10, 100, 1000, 10000, 100000 };
70 static void
71 f2a(double num, int decimals, char *bf)
72 {
73  int i;
74  int length;
75  char prev = '.';
76  int small = 0;
77 
78  if(num < 0) {
79  num = num * -1;
80  *bf++ = '-';
81  }
82 
83  if(num < 1) {
84  small = 1;
85  num += 1;
86  }
87 
88  num = num * decimal_array[decimals % 6];
89  uli2a((unsigned long)num, 10, 0, bf);
90  length = strlen(bf);
91  if(small) {
92  bf[0] = '0';
93  }
94  for(i = length - decimals; i < length; ++i) {
95  char tmp = bf[i];
96  bf[i] = prev;
97  prev = tmp;
98  }
99  bf[i] = prev;
100  bf[i + 1] = 0;
101 }
102 #endif /* PRINTF_FLOAT_SUPPORT */
103 
104 static void
105 ui2a(unsigned int num, unsigned int base, int uc, char *bf_out)
106 {
107  int n = 0;
108  unsigned int d = 1;
109  char bf_tmp[12];
110  char *bf = bf_tmp;
111  while(num / d >= base)
112  d *= base;
113  while(d != 0) {
114  int dgt = num / d;
115  num %= d;
116  d /= base;
117  if(n || dgt > 0 || d == 0) {
118  *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
119  ++n;
120  }
121  }
122  *bf = 0;
123  while(n++ < 4 && base == 16) {
124  *bf_out++ = '0';
125  }
126  strcpy(bf_out, bf_tmp);
127 }
128 static void
129 i2a(int num, char *bf)
130 {
131  if(num < 0) {
132  num = -num;
133  *bf++ = '-';
134  }
135  ui2a(num, 10, 0, bf);
136 }
137 static int
138 a2d(char ch)
139 {
140  if(ch >= '0' && ch <= '9') {
141  return ch - '0';
142  } else if(ch >= 'a' && ch <= 'f') {
143  return ch - 'a' + 10;
144  } else if(ch >= 'A' && ch <= 'F') {
145  return ch - 'A' + 10;
146  } else { return -1;
147  }
148 }
149 static char
150 a2i(char ch, const char **src, int base, int *nump)
151 {
152  const char *p = *src;
153  int num = 0;
154  int digit;
155  while((digit = a2d(ch)) >= 0) {
156  if(digit > base) {
157  break;
158  }
159  num = num * base + digit;
160  ch = *p++;
161  }
162  *src = p;
163  *nump = num;
164  return ch;
165 }
166 static void
167 putchw(void *putp, putcf putf, int n, char z, char *bf)
168 {
169  char fc = z ? '0' : ' ';
170  char ch;
171  char *p = bf;
172  while(*p++ && n > 0)
173  n--;
174  while(n-- > 0)
175  putf(putp, fc);
176  while((ch = *bf++))
177  putf(putp, ch);
178 }
179 void
180 tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
181 {
182  char bf[12];
183 
184  char ch;
185 
186  while((ch = *(fmt++))) {
187  if(ch != '%') {
188  putf(putp, ch);
189  } else {
190  char lz = 0;
191 #ifdef PRINTF_LONG_SUPPORT
192  char lng = 0;
193 #endif
194  int w = 0;
195  ch = *(fmt++);
196  if(ch == '0') {
197  ch = *(fmt++);
198  lz = 1;
199  }
200  if(ch >= '0' && ch <= '9') {
201  ch = a2i(ch, &fmt, 10, &w);
202  }
203 #ifdef PRINTF_LONG_SUPPORT
204  if(ch == 'l') {
205  ch = *(fmt++);
206  lng = 1;
207  }
208 #endif
209  switch(ch) {
210  case 0:
211  goto abort;
212  case 'u': {
213 #ifdef PRINTF_LONG_SUPPORT
214  if(lng) {
215  uli2a(va_arg(va, unsigned long), 10, 0, bf);
216  } else
217 #endif
218  ui2a(va_arg(va, unsigned int), 10, 0, bf);
219  putchw(putp, putf, w, lz, bf);
220  break;
221  }
222  case 'i':
223  case 'd': {
224 #ifdef PRINTF_LONG_SUPPORT
225  if(lng) {
226  li2a(va_arg(va, unsigned long), bf);
227  } else
228 #endif
229  { i2a(va_arg(va, int), bf);
230  }
231  putchw(putp, putf, w, lz, bf);
232  break;
233  }
234  case 'x': case 'X':
235 #ifdef PRINTF_LONG_SUPPORT
236  if(lng) {
237  uli2a(va_arg(va, unsigned long), 16, (ch == 'X'), bf);
238  } else
239 #endif
240  ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf);
241  putchw(putp, putf, w, lz, bf);
242  break;
243 #ifdef PRINTF_FLOAT_SUPPORT
244  case 'f':
245  f2a(va_arg(va, double), 2, bf);
246  putchw(putp, putf, w, lz, bf);
247  break;
248 #endif
249  case 'c':
250  putf(putp, (char)(va_arg(va, int)));
251  break;
252  case 's':
253  putchw(putp, putf, w, 0, va_arg(va, char *));
254  break;
255  case '%':
256  putf(putp, ch);
257  default:
258  break;
259  }
260  }
261  }
262 abort:;
263 }
264 void
265 init_printf(void *putp, void (*putf) (void *, char))
266 {
267  stdout_inited = 1;
268  stdout_putf = putf;
269  stdout_putp = putp;
270 }
271 int
272 tfp_printf(const char *fmt, ...)
273 {
274  va_list va;
275  static int inited = 0;
276  if(!stdout_inited) {
277  return 0;
278  }
279  va_start(va, fmt);
280  tfp_format(stdout_putp, stdout_putf, fmt, va);
281  va_end(va);
282  return 1;
283 }
284 static void
285 putcp(void *p, char c)
286 {
287  *(*((char **)p))++ = c;
288 }
289 int
290 tfp_sprintf(char *s, const char *fmt, ...)
291 {
292  va_list va;
293  char *tmp = s;
294  va_start(va, fmt);
295  tfp_format(&s, putcp, fmt, va);
296  putcp(&s, 0);
297  va_end(va);
298  return strlen(tmp);
299 }