ChibiOS/HAL  7.2.0
chprintf.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /*
18  Concepts and parts of this file have been contributed by Fabio Utzig,
19  chvprintf() added by Brent Roman.
20  */
21 
22 /**
23  * @file chprintf.c
24  * @brief Mini printf-like functionality.
25  *
26  * @addtogroup HAL_CHPRINTF
27  * @details Mini printf-like functionality.
28  * @{
29  */
30 
31 #include "hal.h"
32 #include "chprintf.h"
33 #include "memstreams.h"
34 
35 #define MAX_FILLER 11
36 #define FLOAT_PRECISION 9
37 
38 static char *long_to_string_with_divisor(char *p,
39  long num,
40  unsigned radix,
41  long divisor) {
42  int i;
43  char *q;
44  long l, ll;
45 
46  l = num;
47  if (divisor == 0) {
48  ll = num;
49  } else {
50  ll = divisor;
51  }
52 
53  q = p + MAX_FILLER;
54  do {
55  i = (int)(l % radix);
56  i += '0';
57  if (i > '9') {
58  i += 'A' - '0' - 10;
59  }
60  *--q = i;
61  l /= radix;
62  } while ((ll /= radix) != 0);
63 
64  i = (int)(p + MAX_FILLER - q);
65  do
66  *p++ = *q++;
67  while (--i);
68 
69  return p;
70 }
71 
72 static char *ch_ltoa(char *p, long num, unsigned radix) {
73 
74  return long_to_string_with_divisor(p, num, radix, 0);
75 }
76 
77 #if CHPRINTF_USE_FLOAT
78 static const long pow10[FLOAT_PRECISION] = {
79  10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
80 };
81 
82 static char *ftoa(char *p, double num, unsigned long precision) {
83  long l;
84 
85  if ((precision == 0) || (precision > FLOAT_PRECISION)) {
86  precision = FLOAT_PRECISION;
87  }
88  precision = pow10[precision - 1];
89 
90  l = (long)num;
91  p = long_to_string_with_divisor(p, l, 10, 0);
92  *p++ = '.';
93  l = (long)((num - l) * precision);
94 
95  return long_to_string_with_divisor(p, l, 10, precision / 10);
96 }
97 #endif
98 
99 /**
100  * @brief System formatted output function.
101  * @details This function implements a minimal @p vprintf()-like functionality
102  * with output on a @p BaseSequentialStream.
103  * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
104  * The following parameter types (p) are supported:
105  * - <b>x</b> hexadecimal integer.
106  * - <b>X</b> hexadecimal long.
107  * - <b>o</b> octal integer.
108  * - <b>O</b> octal long.
109  * - <b>d</b> decimal signed integer.
110  * - <b>D</b> decimal signed long.
111  * - <b>u</b> decimal unsigned integer.
112  * - <b>U</b> decimal unsigned long.
113  * - <b>c</b> character.
114  * - <b>s</b> string.
115  * .
116  *
117  * @param[in] chp pointer to a @p BaseSequentialStream implementing object
118  * @param[in] fmt formatting string
119  * @param[in] ap list of parameters
120  * @return The number of bytes that would have been
121  * written to @p chp if no stream error occurs
122  *
123  * @api
124  */
125 int chvprintf(BaseSequentialStream *chp, const char *fmt, va_list ap) {
126  char *p, *s, c, filler;
127  int i, precision, width;
128  int n = 0;
129  bool is_long, left_align, do_sign;
130  long l;
131 #if CHPRINTF_USE_FLOAT
132  float f;
133  char tmpbuf[2*MAX_FILLER + 1];
134 #else
135  char tmpbuf[MAX_FILLER + 1];
136 #endif
137 
138  while (true) {
139  c = *fmt++;
140  if (c == 0) {
141  return n;
142  }
143 
144  if (c != '%') {
145  streamPut(chp, (uint8_t)c);
146  n++;
147  continue;
148  }
149 
150  p = tmpbuf;
151  s = tmpbuf;
152 
153  /* Alignment mode.*/
154  left_align = false;
155  if (*fmt == '-') {
156  fmt++;
157  left_align = true;
158  }
159 
160  /* Sign mode.*/
161  do_sign = false;
162  if (*fmt == '+') {
163  fmt++;
164  do_sign = true;
165  }
166 
167  /* Filler mode.*/
168  filler = ' ';
169  if (*fmt == '0') {
170  fmt++;
171  filler = '0';
172  }
173 
174  /* Width modifier.*/
175  if ( *fmt == '*') {
176  width = va_arg(ap, int);
177  ++fmt;
178  c = *fmt++;
179  }
180  else {
181  width = 0;
182  while (true) {
183  c = *fmt++;
184  if (c == 0) {
185  return n;
186  }
187  if (c >= '0' && c <= '9') {
188  c -= '0';
189  width = width * 10 + c;
190  }
191  else {
192  break;
193  }
194  }
195  }
196 
197  /* Precision modifier.*/
198  precision = 0;
199  if (c == '.') {
200  c = *fmt++;
201  if (c == 0) {
202  return n;
203  }
204  if (c == '*') {
205  precision = va_arg(ap, int);
206  c = *fmt++;
207  }
208  else {
209  while (c >= '0' && c <= '9') {
210  c -= '0';
211  precision = precision * 10 + c;
212  c = *fmt++;
213  if (c == 0) {
214  return n;
215  }
216  }
217  }
218  }
219 
220  /* Long modifier.*/
221  if (c == 'l' || c == 'L') {
222  is_long = true;
223  c = *fmt++;
224  if (c == 0) {
225  return n;
226  }
227  }
228  else {
229  is_long = (c >= 'A') && (c <= 'Z');
230  }
231 
232  /* Command decoding.*/
233  switch (c) {
234  case 'c':
235  filler = ' ';
236  *p++ = va_arg(ap, int);
237  break;
238  case 's':
239  filler = ' ';
240  if ((s = va_arg(ap, char *)) == 0) {
241  s = "(null)";
242  }
243  if (precision == 0) {
244  precision = 32767;
245  }
246  for (p = s; *p && (--precision >= 0); p++)
247  ;
248  break;
249  case 'D':
250  case 'd':
251  case 'I':
252  case 'i':
253  if (is_long) {
254  l = va_arg(ap, long);
255  }
256  else {
257  l = va_arg(ap, int);
258  }
259  if (l < 0) {
260  *p++ = '-';
261  l = -l;
262  }
263  else
264  if (do_sign) {
265  *p++ = '+';
266  }
267  p = ch_ltoa(p, l, 10);
268  break;
269 #if CHPRINTF_USE_FLOAT
270  case 'f':
271  f = (float) va_arg(ap, double);
272  if (f < 0) {
273  *p++ = '-';
274  f = -f;
275  }
276  else {
277  if (do_sign) {
278  *p++ = '+';
279  }
280  }
281  p = ftoa(p, f, precision);
282  break;
283 #endif
284  case 'X':
285  case 'x':
286  case 'P':
287  case 'p':
288  c = 16;
289  goto unsigned_common;
290  case 'U':
291  case 'u':
292  c = 10;
293  goto unsigned_common;
294  case 'O':
295  case 'o':
296  c = 8;
297 unsigned_common:
298  if (is_long) {
299  l = va_arg(ap, unsigned long);
300  }
301  else {
302  l = va_arg(ap, unsigned int);
303  }
304  p = ch_ltoa(p, l, c);
305  break;
306  default:
307  *p++ = c;
308  break;
309  }
310  i = (int)(p - s);
311  if ((width -= i) < 0) {
312  width = 0;
313  }
314  if (left_align == false) {
315  width = -width;
316  }
317  if (width < 0) {
318  if ((*s == '-' || *s == '+') && filler == '0') {
319  streamPut(chp, (uint8_t)*s++);
320  n++;
321  i--;
322  }
323  do {
324  streamPut(chp, (uint8_t)filler);
325  n++;
326  } while (++width != 0);
327  }
328  while (--i >= 0) {
329  streamPut(chp, (uint8_t)*s++);
330  n++;
331  }
332 
333  while (width) {
334  streamPut(chp, (uint8_t)filler);
335  n++;
336  width--;
337  }
338  }
339 }
340 
341 /**
342  * @brief System formatted output function.
343  * @details This function implements a minimal @p printf() like functionality
344  * with output on a @p BaseSequentialStream.
345  * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
346  * The following parameter types (p) are supported:
347  * - <b>x</b> hexadecimal integer.
348  * - <b>X</b> hexadecimal long.
349  * - <b>o</b> octal integer.
350  * - <b>O</b> octal long.
351  * - <b>d</b> decimal signed integer.
352  * - <b>D</b> decimal signed long.
353  * - <b>u</b> decimal unsigned integer.
354  * - <b>U</b> decimal unsigned long.
355  * - <b>c</b> character.
356  * - <b>s</b> string.
357  * .
358  *
359  * @param[in] chp pointer to a @p BaseSequentialStream implementing object
360  * @param[in] fmt formatting string
361  * @return The number of bytes that would have been
362  * written to @p chp if no stream error occurs
363  *
364  * @api
365  */
366 int chprintf(BaseSequentialStream *chp, const char *fmt, ...) {
367  va_list ap;
368  int formatted_bytes;
369 
370  va_start(ap, fmt);
371  formatted_bytes = chvprintf(chp, fmt, ap);
372  va_end(ap);
373 
374  return formatted_bytes;
375 }
376 
377 /**
378  * @brief System formatted output function.
379  * @details This function implements a minimal @p snprintf()-like functionality.
380  * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
381  * The following parameter types (p) are supported:
382  * - <b>x</b> hexadecimal integer.
383  * - <b>X</b> hexadecimal long.
384  * - <b>o</b> octal integer.
385  * - <b>O</b> octal long.
386  * - <b>d</b> decimal signed integer.
387  * - <b>D</b> decimal signed long.
388  * - <b>u</b> decimal unsigned integer.
389  * - <b>U</b> decimal unsigned long.
390  * - <b>c</b> character.
391  * - <b>s</b> string.
392  * .
393  * @post @p str is NUL-terminated, unless @p size is 0.
394  *
395  * @param[in] str pointer to a buffer
396  * @param[in] size maximum size of the buffer
397  * @param[in] fmt formatting string
398  * @return The number of characters (excluding the
399  * terminating NUL byte) that would have been
400  * stored in @p str if there was room.
401  *
402  * @api
403  */
404 int chsnprintf(char *str, size_t size, const char *fmt, ...) {
405  va_list ap;
406  int retval;
407 
408  /* Performing the print operation.*/
409  va_start(ap, fmt);
410  retval = chvsnprintf(str, size, fmt, ap);
411  va_end(ap);
412 
413  /* Return number of bytes that would have been written.*/
414  return retval;
415 }
416 
417 /**
418  * @brief System formatted output function.
419  * @details This function implements a minimal @p vsnprintf()-like functionality.
420  * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
421  * The following parameter types (p) are supported:
422  * - <b>x</b> hexadecimal integer.
423  * - <b>X</b> hexadecimal long.
424  * - <b>o</b> octal integer.
425  * - <b>O</b> octal long.
426  * - <b>d</b> decimal signed integer.
427  * - <b>D</b> decimal signed long.
428  * - <b>u</b> decimal unsigned integer.
429  * - <b>U</b> decimal unsigned long.
430  * - <b>c</b> character.
431  * - <b>s</b> string.
432  * .
433  * @post @p str is NUL-terminated, unless @p size is 0.
434  *
435  * @param[in] str pointer to a buffer
436  * @param[in] size maximum size of the buffer
437  * @param[in] fmt formatting string
438  * @param[in] ap list of parameters
439  * @return The number of characters (excluding the
440  * terminating NUL byte) that would have been
441  * stored in @p str if there was room.
442  *
443  * @api
444  */
445 int chvsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
446  MemoryStream ms;
448  size_t size_wo_nul;
449  int retval;
450 
451  if (size > 0)
452  size_wo_nul = size - 1;
453  else
454  size_wo_nul = 0;
455 
456  /* Memory stream object to be used as a string writer, reserving one
457  byte for the final zero.*/
458  msObjectInit(&ms, (uint8_t *)str, size_wo_nul, 0);
459 
460  /* Performing the print operation using the common code.*/
461  chp = (BaseSequentialStream *)(void *)&ms;
462  retval = chvprintf(chp, fmt, ap);
463 
464  /* Terminate with a zero, unless size==0.*/
465  if (ms.eos < size) {
466  str[ms.eos] = 0;
467  }
468 
469  /* Return number of bytes that would have been written.*/
470  return retval;
471 }
472 
473 /** @} */
msObjectInit
void msObjectInit(MemoryStream *msp, uint8_t *buffer, size_t size, size_t eos)
Memory stream object initialization.
Definition: memstreams.c:116
streamPut
#define streamPut(ip, b)
Sequential Stream blocking byte write.
Definition: hal_streams.h:137
BaseSequentialStream
Base stream class.
Definition: hal_streams.h:83
hal.h
HAL subsystem header.
MemoryStream
Memory stream object.
Definition: memstreams.h:70
chprintf
int chprintf(BaseSequentialStream *chp, const char *fmt,...)
System formatted output function.
Definition: chprintf.c:366
chvprintf
int chvprintf(BaseSequentialStream *chp, const char *fmt, va_list ap)
System formatted output function.
Definition: chprintf.c:125
chvsnprintf
int chvsnprintf(char *str, size_t size, const char *fmt, va_list ap)
System formatted output function.
Definition: chprintf.c:445
chsnprintf
int chsnprintf(char *str, size_t size, const char *fmt,...)
System formatted output function.
Definition: chprintf.c:404
memstreams.h
Memory streams structures and macros.
chprintf.h
Mini printf-like functionality.