CuVoodoo STM32F1 firmware template
print.c
Go to the documentation of this file.
1 /* This program is free software: you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation, either version 3 of the License, or
4  * (at your option) any later version.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program. If not, see <http://www.gnu.org/licenses/>.
13  *
14  */
20 /* standard libraries */
21 #include <stdint.h> // standard integer types
22 #include <stdlib.h> // standard definitions
23 #include <stdbool.h> // boolean types
24 #include <stdarg.h> // variadic utilities
25 
26 /* own libraries */
27 #include "print.h" // printing utilities
28 
32 #define CRLF true
41 static size_t print_char(char** str, size_t* size, char c)
42 {
43  size_t length = 1; // remember how many characters have been printed or should have been added on string (normally just one)
44  if (0==c) { // don't print string termination character
45  length = 0; // remember we didn't print anything
46  } else if (NULL==str || NULL==*str || NULL==size) { // character should not be saved on string
47  length = putc(c); // print on user define output
48  } else if (*size>1) { // // there is enough space in the string to store the character
49  **str = c; // add provided character to string
50  *str += 1; // go to next character on string
51  *size -= 1; // remember we used one character on string
52  } else if (1==*size) { // string is reaching it's end
53  **str = '\0'; // add termination character to string (don't go to next character)
54  *size -= 1; // remember we used one character on string
55  }
56  return length;
57 }
58 
65 static size_t print_string(char** str, size_t* size, const char* s)
66 {
67  size_t length = 0; // number of characters printed
68  while (*s) { // stop at end of string
69  length += print_char(str, size, *(s++)); // print character
70  }
71  return length;
72 }
73 
82 static size_t print_unsigned(char** str, size_t* size, uint64_t u, uint8_t padding, bool sign) {
83  char number[20] = {0}; // construct the number in reverse order (20 chars are required to store UINT64_MAX)
84  uint8_t digits = 0; // to count the number of digits
85  size_t length = 0; // number of characters printed
86  do {
87  number[digits++] = '0'+(u%10); // store digit
88  u /= 10; // go to next digit
89  } while (u>0);
90  if (digits>sizeof(number)) { // prevent buffer underflow
91  return 0;
92  }
93  if (sign) { // print sign
94  length += print_char(str, size, '+'); // we only have positive numbers
95  }
96  for (uint8_t zeros = digits; zeros<padding; zeros++) { // print padding 0's
97  length += print_char(str, size, '0'); // print 0
98  }
99  for (uint8_t digit = 0; digit < digits; digit++) { // go through all digits
100  length += print_char(str, size, number[digits-digit-1]); // print digit (in reverse order)
101  }
102  return length; // return number of characters printed
103 }
104 
113 static size_t print_signed(char** str, size_t* size, int64_t d, uint8_t padding, bool sign) {
114  size_t length = 0; // number of characters printed
115  if (d<0) {
116  length += print_char(str, size, '-'); // print sign
117  length += print_unsigned(str, size, (uint64_t)-d, padding, false); // print number (casting because there is one more negative value then positive value)
118  } else {
119  length += print_unsigned(str, size, d, padding, sign); // print number
120  }
121  return length; // return number of characters printed
122 }
123 
131 static size_t print_nibble(char** str, size_t* size, uint8_t nibble, bool upcase) {
132  size_t length = 0; // number of characters printed
133  nibble &= 0x0f; // ensure we only have a nibble
134  if (nibble<10) {
135  length += print_char(str, size, '0'+nibble);
136  } else if (upcase) {
137  length += print_char(str, size, 'A'+nibble-10);
138  } else {
139  length += print_char(str, size, 'a'+nibble-10);
140  }
141  return length; // return number of characters printed
142 }
143 
153 static size_t print_hex(char** str, size_t* size, uint32_t hex, uint8_t padding, bool prefix, bool upcase) {
154  size_t length = 0; // number of characters printed
155  if (prefix) { // print 0x prefix
156  length += print_char(str, size, '0');
157  length += print_char(str, size, 'x');
158  }
159  uint8_t digits = 0; // number of digits to print
160  // figure out number of digits to print
161  if (hex>0x00ffffff) {
162  digits = 8;
163  } else if (hex>0x0000ffff) {
164  digits = 6;
165  } else if (hex>0x000000ff) {
166  digits = 4;
167  } else {
168  digits = 2;
169  }
170  for (uint8_t zeros = digits; zeros<padding; zeros++) { // print padding 0's
171  length += print_char(str, size, '0'); // print 0
172  }
173  for (uint8_t digit = 0; digit < digits; digit++) { // go through all digits
174  length += print_nibble(str, size, hex>>((digits-digit-1)*4), upcase); // print nibble (in reverse order)
175  }
176  return length; // return number of characters printed
177 }
178 
187 static size_t print_bits(char** str, size_t* size, uint32_t u, uint8_t padding, bool prefix) {
188  char bits[32] = {0}; // construct the bit string in reverse order
189  uint8_t digits = 0; // to count the number of digits
190  size_t length = 0; // number of characters printed
191  do {
192  bits[digits++] = '0'+(u&0x1); // store bit
193  u >>= 1; // go to next bit
194  } while (u>0);
195  if (digits>sizeof(bits)) { // prevent buffer underflow
196  return 0;
197  }
198  if (prefix) { // print prefix
199  length += print_char(str, size, '0');
200  length += print_char(str, size, 'b');
201  }
202  for (uint8_t zeros = digits; zeros<padding; zeros++) { // print padding 0's
203  length += print_char(str, size, '0'); // print 0
204  }
205  for (uint8_t digit = 0; digit < digits; digit++) { // go through all bits
206  length += print_char(str, size, bits[digits-digit-1]); // print bit (in reverse order)
207  }
208  return length; // return number of characters printed
209 }
210 
218 static size_t vsnprintf(char** str, size_t* size, const char *format, va_list va)
219 {
220  size_t length = 0; // number of characters printed
221  uint8_t padding = 0; // number of padding 0's
222  bool sign = false; // if sign needs to be printed
223  while (*format) { // go through format string
224  padding = 0; // reset padding
225  sign = false; // reset sign
226  if ('%'!=*format) { // check for format specifier prefix
227  length += print_char(str, size, *format++); // print character (no interpretation needed)
228  } else {
229  format++; // go to format specifier
230  if (0==*format) { // end of string detected
231  goto end;
232  }
233  // check if sign need to be printed
234  if ('+'==*format) { // sign required
235  sign = true; // remember sign is required
236  format++; // go to padding number
237  if (0==*format) { // end of string detected
238  goto end;
239  }
240  }
241  // check padding
242  if ('0'==*format) { // padding required
243  format++; // go to padding number
244  padding = 0;
245  while (*format>='0' && *format<='9') {
246  padding *= 10; // shift padding digit
247  padding += *format-'0'; // get next padding digit
248  format++; // go to next character
249  }
250  if (0==*format) { // end of string detected
251  goto end;
252  }
253  }
254  // check format specifier
255  switch (*format) {
256  case 'u': // for uint8_t, uint16_t, uint32_t, unsigned int, unsigned long
257  length += print_unsigned(str, size, va_arg(va,uint32_t), padding, sign);
258  break;
259  case 'U': // for uint64_t, unsigned long long
260  length += print_unsigned(str, size, va_arg(va,uint64_t), padding, sign);
261  break;
262  case 'd': // for int8_t, int16_t, int32_t, int, long
263  length += print_signed(str, size, va_arg(va,int32_t), padding, sign);
264  break;
265  case 'D': // for int64_t, long long
266  length += print_signed(str, size, va_arg(va,int64_t), padding, sign);
267  break;
268  case 'c': // for char, unsigned char
269  length += print_char(str, size, (char)(va_arg(va,int))); // needs casting because the returned value is promoted
270  break;
271  case 'x': // for downcase hexadecimal
272  length += print_hex(str, size, va_arg(va,uint32_t), padding, sign, false);
273  break;
274  case 'X': // for upcase hexadecimal
275  length += print_hex(str, size, va_arg(va,uint32_t), padding, sign, true);
276  break;
277  case 'b': // for bits
278  length += print_bits(str, size, va_arg(va,uint32_t), padding, sign);
279  break;
280  case 's': // for strings
281  length += print_string(str, size, va_arg(va,char*));
282  break;
283  default:
284  length += print_char(str, size, *format); // print character (unknown format specifier)
285  }
286  format++; // go to next character
287  }
288  }
289 end:
290  if (NULL!=str && NULL!=*str && NULL!=size) { // when working on a string
291  **str='\0'; // enforce null termination
292  }
293  return length; // return number of characters it should have written
294 }
295 
296 size_t printf(const char *format, ...)
297 {
298  size_t length = 0;
299  va_list arglist;
300  va_start(arglist, format);
301  length = vsnprintf(NULL, NULL, format, arglist);
302  va_end(arglist);
303  return length;
304 }
305 
306 size_t snprintf(char* str, size_t size, const char* format, ...)
307 {
308  size_t length = 0;
309  va_list arglist;
310  va_start(arglist, format);
311  length = vsnprintf(&str, &size, format, arglist);
312  va_end(arglist);
313  return length;
314 }
size_t putc(char c)
print a single character on user output
Definition: main.c:136