Contiki 2.5
strformat.c
1 #include <strformat.h>
2 
3 #define HAVE_DOUBLE
4 
5 #define HAVE_LONGLONG
6 #ifndef LARGEST_SIGNED
7 #ifdef HAVE_LONGLONG
8 #define LARGEST_SIGNED long long int
9 #else
10 #define LARGEST_UNSIGNED long int
11 #endif
12 #endif
13 
14 #ifndef LARGEST_UNSIGNED
15 #ifdef HAVE_LONGLONG
16 #define LARGEST_UNSIGNED unsigned long long int
17 #else
18 #define LARGEST_UNSIGNED unsigned long int
19 #endif
20 #endif
21 
22 #ifndef POINTER_INT
23 #define POINTER_INT unsigned long
24 #endif
25 
26 typedef unsigned int FormatFlags;
27 
28 #define MAKE_MASK(shift,size) (((1 << size) - 1) << (shift))
29 
30 #define JUSTIFY_SHIFT 0
31 #define JUSTIFY_SIZE 1
32 #define JUSTIFY_RIGHT 0x0000
33 #define JUSTIFY_LEFT 0x0001
34 #define JUSTIFY_MASK MAKE_MASK(JUSTIFY_SHIFT,JUSTIFY_SIZE)
35 
36 
37 /* How a positive number is prefixed */
38 #define POSITIVE_SHIFT (JUSTIFY_SHIFT + JUSTIFY_SIZE)
39 #define POSITIVE_NONE (0x0000 << POSITIVE_SHIFT)
40 #define POSITIVE_SPACE (0x0001 << POSITIVE_SHIFT)
41 #define POSITIVE_PLUS (0x0003 << POSITIVE_SHIFT)
42 #define POSITIVE_MASK MAKE_MASK(POSITIVE_SHIFT, POSITIVE_SIZE)
43 
44 #define POSITIVE_SIZE 2
45 
46 #define ALTERNATE_FORM_SHIFT (POSITIVE_SHIFT + POSITIVE_SIZE)
47 #define ALTERNATE_FORM_SIZE 1
48 #define ALTERNATE_FORM (0x0001 << ALTERNATE_FORM_SHIFT)
49 
50 
51 #define PAD_SHIFT (ALTERNATE_FORM_SHIFT + ALTERNATE_FORM_SIZE)
52 #define PAD_SIZE 1
53 #define PAD_SPACE (0x0000 << PAD_SHIFT)
54 #define PAD_ZERO (0x0001 << PAD_SHIFT)
55 
56 #define SIZE_SHIFT (PAD_SHIFT + PAD_SIZE)
57 #define SIZE_SIZE 3
58 #define SIZE_CHAR (0x0001 << SIZE_SHIFT)
59 #define SIZE_SHORT (0x0002 << SIZE_SHIFT)
60 #define SIZE_INT (0x0000 << SIZE_SHIFT)
61 #define SIZE_LONG (0x0003 << SIZE_SHIFT)
62 #define SIZE_LONGLONG (0x0004 << SIZE_SHIFT)
63 #define SIZE_MASK MAKE_MASK(SIZE_SHIFT,SIZE_SIZE)
64 
65 #define CONV_SHIFT (SIZE_SHIFT + SIZE_SIZE)
66 #define CONV_SIZE 3
67 #define CONV_INTEGER (0x0001 << CONV_SHIFT)
68 #define CONV_FLOAT (0x0002 << CONV_SHIFT)
69 #define CONV_POINTER (0x0003 << CONV_SHIFT)
70 #define CONV_STRING (0x0004 << CONV_SHIFT)
71 #define CONV_CHAR (0x0005 << CONV_SHIFT)
72 #define CONV_PERCENT (0x0006 << CONV_SHIFT)
73 #define CONV_WRITTEN (0x0007 << CONV_SHIFT)
74 #define CONV_MASK MAKE_MASK(CONV_SHIFT, CONV_SIZE)
75 
76 #define RADIX_SHIFT (CONV_SHIFT + CONV_SIZE)
77 #define RADIX_SIZE 2
78 #define RADIX_DECIMAL (0x0001 << RADIX_SHIFT)
79 #define RADIX_OCTAL (0x0002 << RADIX_SHIFT)
80 #define RADIX_HEX (0x0003 << RADIX_SHIFT)
81 #define RADIX_MASK MAKE_MASK(RADIX_SHIFT,RADIX_SIZE)
82 
83 #define SIGNED_SHIFT (RADIX_SHIFT + RADIX_SIZE)
84 #define SIGNED_SIZE 1
85 #define SIGNED_NO (0x0000 << SIGNED_SHIFT)
86 #define SIGNED_YES (0x0001 << SIGNED_SHIFT)
87 #define SIGNED_MASK MAKE_MASK(SIGNED_SHIFT,SIGNED_SIZE)
88 
89 #define CAPS_SHIFT (SIGNED_SHIFT + SIGNED_SIZE)
90 #define CAPS_SIZE 1
91 #define CAPS_NO (0x0000 << CAPS_SHIFT)
92 #define CAPS_YES (0x0001 << CAPS_SHIFT)
93 #define CAPS_MASK MAKE_MASK(CAPS_SHIFT,CAPS_SIZE)
94 
95 #define FLOAT_SHIFT (CAPS_SHIFT + CAPS_SIZE)
96 #define FLOAT_SIZE 2
97 #define FLOAT_NORMAL (0x0000 << FLOAT_SHIFT)
98 #define FLOAT_EXPONENT (0x0001 << FLOAT_SHIFT)
99 #define FLOAT_DEPENDANT (0x0002 << FLOAT_SHIFT)
100 #define FLOAT_HEX (0x0003 << FLOAT_SHIFT)
101 #define FLOAT_MASK MAKE_MASK(FLOAT_SHIFT, FLOAT_SIZE)
102 
103 static FormatFlags
104 parse_flags(const char **posp)
105 {
106  FormatFlags flags = 0;
107  const char *pos = *posp;
108  while (1) {
109  switch(*pos) {
110  case '-':
111  flags |= JUSTIFY_LEFT;
112  break;
113  case '+':
114  flags |= POSITIVE_PLUS;
115  break;
116  case ' ':
117  flags |= POSITIVE_SPACE;
118  break;
119  case '#':
120  flags |= ALTERNATE_FORM;
121  break;
122  case '0':
123  flags |= PAD_ZERO;
124  break;
125  default:
126  *posp = pos;
127  return flags;
128  }
129  pos++;
130  }
131 
132 }
133 
134 static unsigned int
135 parse_uint(const char **posp)
136 {
137  unsigned v = 0;
138  const char *pos = *posp;
139  char ch;
140  while((ch = *pos) >= '0' && ch <= '9') {
141  v = v * 10 + (ch - '0');
142  pos++;
143  }
144  *posp = pos;
145  return v;
146 }
147 
148 #define MAXCHARS_HEX ((sizeof(LARGEST_UNSIGNED) * 8) / 4 )
149 
150 /* Largest number of characters needed for converting an unsigned integer.
151  */
152 #define MAXCHARS ((sizeof(LARGEST_UNSIGNED) * 8 + 2) / 3 )
153 
154 static unsigned int
155 output_uint_decimal(char **posp, LARGEST_UNSIGNED v)
156 {
157  unsigned int len;
158  char *pos = *posp;
159  while (v > 0) {
160  *--pos = (v % 10) + '0';
161  v /= 10;
162  }
163  len = *posp - pos;
164  *posp = pos;
165  return len;
166 }
167 
168 static unsigned int
169 output_uint_hex(char **posp, LARGEST_UNSIGNED v, unsigned int flags)
170 {
171  unsigned int len;
172  const char *hex = (flags & CAPS_YES) ?"0123456789ABCDEF":"0123456789abcdef";
173  char *pos = *posp;
174  while (v > 0) {
175  *--pos = hex[(v % 16)];
176  v /= 16;
177  }
178  len = *posp - pos;
179  *posp = pos;
180  return len;
181 }
182 
183 static unsigned int
184 output_uint_octal(char **posp, LARGEST_UNSIGNED v)
185 {
186  unsigned int len;
187  char *pos = *posp;
188  while (v > 0) {
189  *--pos = (v % 8) + '0';
190  v /= 8;
191  }
192  len = *posp - pos;
193  *posp = pos;
194  return len;
195 }
196 
197 static StrFormatResult
198 fill_space(const StrFormatContext *ctxt, unsigned int len)
199 {
200  StrFormatResult res;
201  static const char buffer[16] = " ";
202  while(len > 16) {
203  res = ctxt->write_str(ctxt->user_data, buffer, 16);
204  if (res != STRFORMAT_OK) return res;
205  len -= 16;
206  }
207  if (len == 0) return STRFORMAT_OK;
208  return ctxt->write_str(ctxt->user_data, buffer, len);
209 }
210 
211 static StrFormatResult
212 fill_zero(const StrFormatContext *ctxt, unsigned int len)
213 {
214  StrFormatResult res;
215  static const char buffer[16] = "0000000000000000";
216  while(len > 16) {
217  res = ctxt->write_str(ctxt->user_data, buffer, 16);
218  if (res != STRFORMAT_OK) return res;
219  len -= 16;
220  }
221  if (len == 0) return STRFORMAT_OK;
222  return ctxt->write_str(ctxt->user_data, buffer, len);
223 }
224 
225 #define CHECKCB(res) {if ((res) != STRFORMAT_OK) {va_end(ap); return -1;}}
226 
227 int
228 format_str(const StrFormatContext *ctxt, const char *format, ...)
229 {
230  int ret;
231  va_list ap;
232  va_start(ap, format);
233  ret = format_str_v(ctxt, format, ap);
234  va_end(ap);
235  return ret;
236 }
237 
238 int
239 format_str_v(const StrFormatContext *ctxt, const char *format, va_list ap)
240 {
241  unsigned int written = 0;
242  const char *pos = format;
243  while(*pos != '\0') {
244  FormatFlags flags;
245  unsigned int minwidth = 0;
246  int precision = -1; /* Negative means no precision */
247  char ch;
248  const char *start = pos;
249  while( (ch = *pos) != '\0' && ch != '%') pos++;
250  if (pos != start) {
251  CHECKCB(ctxt->write_str(ctxt->user_data, start, pos - start));
252  written += pos - start;
253  }
254  if (*pos == '\0') {
255  va_end(ap);
256  return written;
257  }
258  pos++;
259  if (*pos == '\0') {
260  va_end(ap);
261  return written;
262  }
263  flags = parse_flags(&pos);
264 
265  /* parse width */
266  if (*pos >= '1' && *pos <= '9') {
267  minwidth = parse_uint(&pos);
268  } else if (*pos == '*') {
269  int w = va_arg(ap,int);
270  if (w < 0) {
271  flags |= JUSTIFY_LEFT;
272  minwidth = w;
273  } else {
274  minwidth = w;
275  }
276  pos ++;
277  }
278 
279  /* parse precision */
280  if (*pos == '.') {
281  pos++;
282  if (*pos >= '0' && *pos <= '9') {
283  precision = parse_uint(&pos);
284  } else if (*pos == '*') {
285  pos++;
286  precision = va_arg(ap,int);
287  }
288  }
289  if (*pos == 'l') {
290  pos++;
291  if (*pos == 'l') {
292  flags |= SIZE_LONGLONG;
293  pos++;
294  } else {
295  flags |= SIZE_LONG;
296  }
297  } else if (*pos == 'h') {
298  pos++;
299  if (*pos == 'h') {
300  flags |= SIZE_CHAR;
301  pos++;
302  } else {
303  flags |= SIZE_SHORT;
304  }
305  }
306 
307  /* parse conversion specifier */
308  switch(*pos) {
309  case 'd':
310  case 'i':
311  flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_YES;
312  break;
313  case 'u':
314  flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_NO;
315  break;
316  case 'o':
317  flags |= CONV_INTEGER | RADIX_OCTAL | SIGNED_NO;
318  break;
319  case 'x':
320  flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO;
321  break;
322  case 'X':
323  flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO | CAPS_YES;
324  break;
325 #ifdef HAVE_DOUBLE
326  case 'f':
327  flags |= CONV_FLOAT | FLOAT_NORMAL;
328  break;
329  case 'F':
330  flags |= CONV_FLOAT | FLOAT_NORMAL | CAPS_YES;
331  break;
332  case 'e':
333  flags |= CONV_FLOAT | FLOAT_EXPONENT;
334  break;
335  case 'E':
336  flags |= CONV_FLOAT | FLOAT_EXPONENT | CAPS_YES;
337  break;
338  case 'g':
339  flags |= CONV_FLOAT | FLOAT_DEPENDANT;
340  break;
341  case 'G':
342  flags |= CONV_FLOAT | FLOAT_DEPENDANT | CAPS_YES;
343  break;
344  case 'a':
345  flags |= CONV_FLOAT | FLOAT_HEX;
346  break;
347  case 'A':
348  flags |= CONV_FLOAT | FLOAT_HEX | CAPS_YES;
349  break;
350 #endif
351  case 'c':
352  flags |= CONV_CHAR;
353  break;
354  case 's':
355  flags |= CONV_STRING;
356  break;
357  case 'p':
358  flags |= CONV_POINTER;
359  break;
360  case 'n':
361  flags |= CONV_WRITTEN;
362  break;
363  case '%':
364  flags |= CONV_PERCENT;
365  break;
366  case '\0':
367  va_end(ap);
368  return written;
369  }
370  pos++;
371  switch(flags & CONV_MASK) {
372  case CONV_PERCENT:
373  CHECKCB(ctxt->write_str(ctxt->user_data, "%", 1));
374  written++;
375  break;
376  case CONV_INTEGER:
377  {
378  /* unsigned integers */
379  char *prefix = 0; /* sign, "0x" or "0X" */
380  unsigned int prefix_len = 0;
381  char buffer[MAXCHARS];
382  char *conv_pos = buffer + MAXCHARS;
383  unsigned int conv_len = 0;
384  unsigned int width = 0;
385  unsigned int precision_fill;
386  unsigned int field_fill;
387  LARGEST_UNSIGNED uvalue = 0;
388  int negative = 0;
389 
390  if (precision < 0) precision = 1;
391  else flags &= ~PAD_ZERO;
392 
393  if (flags & SIGNED_YES) {
394  /* signed integers */
395  LARGEST_SIGNED value = 0;
396  switch(flags & SIZE_MASK) {
397  case SIZE_CHAR:
398  value = (signed char)va_arg(ap, int);
399  break;
400  case SIZE_SHORT:
401  value = (short)va_arg(ap, int);
402  break;
403  case SIZE_INT:
404  value = va_arg(ap, int);
405  break;
406 #ifndef HAVE_LONGLONG
407  case SIZE_LONGLONG: /* Treat long long the same as long */
408 #endif
409  case SIZE_LONG:
410  value = va_arg(ap, long);
411  break;
412 #ifdef HAVE_LONGLONG
413  case SIZE_LONGLONG:
414  value = va_arg(ap, long long);
415  break;
416 #endif
417  }
418  if (value < 0) {
419  uvalue = -value;
420  negative = 1;
421  } else {
422  uvalue = value;
423  }
424  } else {
425 
426  switch(flags & SIZE_MASK) {
427  case SIZE_CHAR:
428  uvalue = (unsigned char)va_arg(ap,unsigned int);
429  break;
430  case SIZE_SHORT:
431  uvalue = (unsigned short)va_arg(ap,unsigned int);
432  break;
433  case SIZE_INT:
434  uvalue = va_arg(ap,unsigned int);
435  break;
436 #ifndef HAVE_LONGLONG
437  case SIZE_LONGLONG: /* Treat long long the same as long */
438 #endif
439  case SIZE_LONG:
440  uvalue = va_arg(ap,unsigned long);
441  break;
442 #ifdef HAVE_LONGLONG
443  case SIZE_LONGLONG:
444  uvalue = va_arg(ap,unsigned long long);
445  break;
446 #endif
447  }
448  }
449 
450  switch(flags & (RADIX_MASK)) {
451  case RADIX_DECIMAL:
452  conv_len = output_uint_decimal(&conv_pos,uvalue);
453  break;
454  case RADIX_OCTAL:
455  conv_len = output_uint_octal(&conv_pos,uvalue);
456  break;
457  case RADIX_HEX:
458  conv_len = output_uint_hex(&conv_pos,uvalue, flags);
459  break;
460  }
461 
462  width += conv_len;
463  precision_fill = (precision > conv_len) ? precision - conv_len : 0;
464  if ((flags & (RADIX_MASK | ALTERNATE_FORM))
465  == (RADIX_OCTAL | ALTERNATE_FORM)) {
466  if (precision_fill < 1) precision_fill = 1;
467  }
468 
469  width += precision_fill;
470 
471  if ((flags & (RADIX_MASK | ALTERNATE_FORM))
472  == (RADIX_HEX | ALTERNATE_FORM) && uvalue != 0) {
473  prefix_len = 2;
474  if (flags & CAPS_YES) {
475  prefix = "0X";
476  } else {
477  prefix = "0x";
478  }
479  }
480 
481  if (flags & SIGNED_YES) {
482  if (negative) {
483  prefix = "-";
484  prefix_len = 1;
485  } else {
486  switch(flags & POSITIVE_MASK) {
487  case POSITIVE_SPACE:
488  prefix = " ";
489  prefix_len = 1;
490  break;
491  case POSITIVE_PLUS:
492  prefix = "+";
493  prefix_len = 1;
494  break;
495  }
496  }
497  }
498 
499  width += prefix_len;
500 
501  field_fill = (minwidth > width) ? minwidth - width : 0;
502 
503  if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
504  if (flags & PAD_ZERO) {
505  precision_fill += field_fill;
506  } else {
507  CHECKCB(fill_space(ctxt,field_fill));
508  }
509  }
510 
511  if (prefix_len > 0)
512  CHECKCB(ctxt->write_str(ctxt->user_data, prefix, prefix_len));
513  written += prefix_len;
514 
515  CHECKCB(fill_zero(ctxt,precision_fill));
516  written += precision_fill;
517 
518  CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len));
519  written += conv_len;
520 
521  if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
522  CHECKCB(fill_space(ctxt,field_fill));
523  }
524  written += field_fill;
525  }
526  break;
527  case CONV_STRING:
528  {
529  unsigned int field_fill;
530  unsigned int len;
531  char *str = va_arg(ap,char *);
532  if (str) {
533  char *pos = str;
534  while(*pos != '\0') pos++;
535  len = pos - str;
536  } else {
537  str = "(null)";
538  len = 6;
539  }
540  if (precision >= 0 && precision < len) len = precision;
541  field_fill = (minwidth > len) ? minwidth - len : 0;
542  if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
543  CHECKCB(fill_space(ctxt,field_fill));
544  }
545  CHECKCB(ctxt->write_str(ctxt->user_data, str,len));
546  written += len;
547  if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
548  CHECKCB(fill_space(ctxt,field_fill));
549  }
550  written += field_fill;
551  }
552  break;
553  case CONV_POINTER:
554  {
555  LARGEST_UNSIGNED uvalue =
556  (LARGEST_UNSIGNED)(POINTER_INT)va_arg(ap,void *);
557  char buffer[MAXCHARS_HEX + 3];
558  char *conv_pos = buffer + MAXCHARS_HEX+3;
559  unsigned int conv_len;
560  unsigned int field_fill;
561 
562  conv_len = output_uint_hex(&conv_pos,uvalue,flags);
563  if (conv_len == 0) {
564  *--conv_pos = '0';
565  conv_len++;
566  }
567  *--conv_pos = 'x';
568  *--conv_pos = '0';
569  *--conv_pos = '#';
570  conv_len += 3;
571 
572  field_fill = (minwidth > conv_len) ? minwidth - conv_len : 0;
573 
574  if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
575  CHECKCB(fill_space(ctxt,field_fill));
576  }
577 
578  CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len));
579  written += conv_len;
580 
581  if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
582  CHECKCB(fill_space(ctxt,field_fill));
583  }
584  written += field_fill;
585  }
586  break;
587  case CONV_CHAR:
588  {
589  char ch = va_arg(ap,int);
590  unsigned int field_fill = (minwidth > 1) ? minwidth - 1 : 0;
591  if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
592  CHECKCB(fill_space(ctxt,field_fill));
593  written += field_fill;
594  }
595 
596  CHECKCB(ctxt->write_str(ctxt->user_data, &ch, 1));
597  written++;
598 
599  if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
600  CHECKCB(fill_space(ctxt,field_fill));
601  }
602  written+= field_fill;
603  }
604  break;
605  case CONV_WRITTEN:
606  {
607  int *p = va_arg(ap,int*);
608  *p = written;
609  }
610  break;
611 
612  }
613  }
614 
615  return written;
616 }