embkernel
 All Classes Functions Variables Typedefs Groups Pages
LibStringFormat.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include <string.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 
10 #include "LibStringFormat.hpp"
11 #include "LibStreamOut.hpp"
12 
13 const char LibStringFormat::HEX_CHARS_LOWER_CASE[] = "0123456789abcdef";
14 const char LibStringFormat::HEX_CHARS_UPPER_CASE[] = "0123456789ABCDEF";
15 
16 #include <stdint.h>
17 
18 int LibStringFormat::printf(LibStreamOut& stream, const char* format, ...) {
19  va_list vaList;
20  int len;
21 
22  va_start(vaList, format);
23 
24  len = vprintf(stream, format, vaList);
25 
26  va_end(vaList);
27 
28  return len;
29 }
30 
31 int LibStringFormat::vprintf(LibStreamOut& stream, const char* format, va_list vaList) {
32  int len = 0;
33 
34  while (true) {
35  //Find the first '%' character or end of string, return on '\0'
36  {
37  const char* start = format;
38  while (true) {
39  if (*format == '\0') {
40  size_t segLen = format - start;
41  if (segLen > 0) {
42  len += stream.write(start, segLen);
43  }
44  return len;
45  }
46  if (*format == '%') {
47  size_t segLen = format - start;
48  if (segLen > 0) {
49  len += stream.write(start, segLen);
50  }
51  format++;
52  break;
53  }
54  format++;
55  }
56  }
57 
58  if (*format == '%') {
59  len += stream.write(format++, 1);
60  continue;
61  }
62 
63  FORMAT_PARAMETERS parameters;
64 
65  //Parse flags
66  format = parseFlags(format, parameters.flags);
67 
68  //Parse width
69  format = parseWidth(format, parameters.width);
70 
71  //Parse precision
72  format = parsePrecision(format, parameters.precision);
73 
74  //Parse length
75  format = parseLength(format, parameters.length);
76 
77  switch (*format++) {
78  case 'c':
79  len += writeChar(stream, va_arg(vaList, int), parameters);
80  break;
81  case 'd':
82  case 'i': {
83  int value = va_arg(vaList, int);
84  if (value < 0) {
85  value = -value;
86  parameters.flags.bits.isNegative = true;
87  }
88  parameters.base = 10;
89  len += writeNaturalNumber(stream, value, parameters);
90  break;
91  }
92  case 'f': {
93  double value = va_arg(vaList, double);
94  if (value < 0) {
95  value = -value;
96  parameters.flags.bits.isNegative = true;
97  }
98  parameters.base = 10;
99  len += writeFloat(stream, value, parameters);
100  break;
101 
102  }
103  case 's':
104  len += writeString(stream, va_arg(vaList, char *), parameters);
105  break;
106  case 'u':
107  parameters.base = 10;
108  len += writeNaturalNumber(stream, va_arg(vaList, unsigned int), parameters);
109  break;
110  case 'x':
111  parameters.flags.bits.isLowerCase = true;
112  case 'X':
113  parameters.base = 16;
114  len += writeNaturalNumber(stream, va_arg(vaList, unsigned int), parameters);
115  break;
116  case '%':
117  len += stream.write(format++, 1);
118  break;
119  default:
120  break;
121  }
122  }
123 }
124 
125 int LibStringFormat::writeChar(LibStreamOut& stream, const char c, const FORMAT_PARAMETERS& parameters) {
126  int len = 0;
127 
128  int padLen = parameters.width - 1;
129 
130  if (!parameters.flags.bits.leftJustify) {
131  len += writePad(stream, ' ', padLen);
132  }
133 
134  len += stream.write(&c, 1);
135 
136  len += writePad(stream, ' ', padLen);
137 
138  return len;
139 }
140 
141 int LibStringFormat::writeNaturalNumber(LibStreamOut& stream, unsigned int value, const FORMAT_PARAMETERS& parameters) {
142  char buffer[22];
143 
144  int idx = sizeof(buffer);
145 
146  const char* chars = HEX_CHARS_UPPER_CASE;
147 
148  if (parameters.flags.bits.isLowerCase) {
149  chars = HEX_CHARS_LOWER_CASE;
150  }
151 
152  //Write the number from left to right
153  if (value == 0) {
154  buffer[--idx] = '0';
155  }
156  else {
157  for (; idx > 0 && value > 0;) {
158  buffer[--idx] = chars[value % parameters.base];
159  value /= parameters.base;
160  }
161  }
162 
163  if (parameters.flags.bits.isNegative && (idx >= 1)) {
164  buffer[--idx] = '-';
165  }
166  else if (parameters.flags.bits.forceSign && (idx >= 1)) {
167  buffer[--idx] = '+';
168  }
169  else if (parameters.flags.bits.forceSpace && (idx >= 1)) {
170  buffer[--idx] = ' ';
171  }
172 
173  if (parameters.flags.bits.sharp && (parameters.base == 16) && (idx >= 1)) {
174  buffer[--idx] = '0';
175  if (parameters.flags.bits.isLowerCase) {
176  buffer[--idx] = 'x';
177  }
178  else {
179  buffer[--idx] = 'X';
180  }
181  }
182 
183  int len = (sizeof(buffer) - idx);
184  int padLen = parameters.width - len;
185 
186  if (!parameters.flags.bits.leftJustify) {
187  if (parameters.flags.bits.leftPadWith0) {
188  len += writePad(stream, '0', padLen);
189  }
190  else {
191  len += writePad(stream, ' ', padLen);
192  }
193  }
194 
195  stream.write(&buffer[idx], (int) sizeof(buffer) - idx);
196 
197  len += writePad(stream, ' ', padLen);
198 
199  return len;
200 }
201 
202 int LibStringFormat::writeFloat(LibStreamOut& stream, double value, FORMAT_PARAMETERS& parameters) {
203  int len = 0;
204 
205  int multiplier = 1;
206  for (int i = 0; i < parameters.precision; i++) {
207  multiplier *= 10;
208  }
209 
210  uint32_t intValue = value * multiplier;
211 
212  //Round to the nearest
213  if ((((uint32_t) (value * multiplier * 10)) % 10) >= 5) {
214  intValue++;
215  }
216 
217  uint32_t integerPart = intValue / multiplier;
218  uint32_t decimalPart = intValue % multiplier;
219 
220  len = writeNaturalNumber(stream, integerPart, parameters);
221 
222  if (parameters.precision <= 0) {
223  return len;
224  }
225 
226  char c = '.';
227  len += stream.write(&c, 1);
228 
229  intValue = value;
230  parameters.width = parameters.precision;
231  parameters.flags.bits.leftPadWith0 = true;
232  parameters.flags.bits.isNegative = false;
233  len += writeNaturalNumber(stream, decimalPart, parameters);
234 
235  return len;
236 }
237 
238 int LibStringFormat::writeString(LibStreamOut& stream, const char* string, const FORMAT_PARAMETERS& parameters) {
239  int strLen = 0;
240  const char* parser = string;
241 
242  while (*parser++) {
243  strLen++;
244  }
245 
246  int len = 0;
247 
248  int padLen = parameters.width - strLen;
249 
250  if (!parameters.flags.bits.leftJustify) {
251  len += writePad(stream, ' ', padLen);
252  }
253 
254  len += stream.write(string, strLen);
255 
256  len += writePad(stream, ' ', padLen);
257 
258  return len;
259 }
260 
261 int LibStringFormat::writePad(LibStreamOut& stream, const char c, int& size) {
262  int len = 0;
263  while (size-- > 0) {
264  if (!stream.write(&c, 1)) {
265  return len;
266  }
267  len++;
268  }
269  return len;
270 }
271 
272 const char* LibStringFormat::parseFlags(const char* format, FLAGS& flags) {
273  flags.value = 0;
274  while (true) {
275  switch (*format) {
276  case '-':
277  flags.bits.leftJustify = true;
278  break;
279  case '+':
280  flags.bits.forceSign = true;
281  break;
282  case ' ':
283  flags.bits.forceSpace = true;
284  break;
285  case '#':
286  flags.bits.sharp = true;
287  break;
288  case '0':
289  flags.bits.leftPadWith0 = true;
290  break;
291  default:
292  return format;
293  }
294  format++;
295  }
296 }
297 
298 const char* LibStringFormat::parseWidth(const char* format, int& width) {
299  width = 0;
300  while (true) {
301  if ((*format < '0') || (*format > '9')) {
302  return format;
303  }
304  width *= 10;
305  width += *format++ - '0';
306  }
307 }
308 
309 const char* LibStringFormat::parsePrecision(const char* format, int& precision) {
310  precision = 0;
311  if (*format != '.') {
312  return format;
313  }
314  format++;
315  while (true) {
316  if ((*format < '0') || (*format > '9')) {
317  return format;
318  }
319  precision *= 10;
320  precision += *format++ - '0';
321  }
322 }
323 
324 const char* LibStringFormat::parseLength(const char* format, int& length) {
325  length = 0;
326  switch (*format) {
327  case 'h':
328  length = LENGTH_HALF;
329  break;
330  case 'l':
331  length = LENGTH_LONG;
332  break;
333  case 'L':
334  length = LENGTH_DOUBLE;
335  break;
336  default:
337  return format;
338  }
339  format++;
340  return format;
341 }
342