1// See LICENSE for license details.
2
3#include <stdint.h>
4#include <string.h>
5#include <stdarg.h>
6#include <stdbool.h>
7
8int vsnprintf(char* out, size_t n, const char* s, va_list vl)
9{
10  bool format = false;
11  bool longarg = false;
12  size_t pos = 0;
13  for( ; *s; s++)
14  {
15    if(format)
16    {
17      switch(*s)
18      {
19        case 'l':
20          longarg = true;
21          break;
22        case 'p':
23          longarg = true;
24          if (++pos < n) out[pos-1] = '0';
25          if (++pos < n) out[pos-1] = 'x';
26        case 'x':
27        {
28          long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
29          for(int i = 2*(longarg ? sizeof(long) : sizeof(int))-1; i >= 0; i--) {
30            int d = (num >> (4*i)) & 0xF;
31            if (++pos < n) out[pos-1] = (d < 10 ? '0'+d : 'a'+d-10);
32          }
33          longarg = false;
34          format = false;
35          break;
36        }
37        case 'd':
38        {
39          long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
40          if (num < 0) {
41            num = -num;
42            if (++pos < n) out[pos-1] = '-';
43          }
44          long digits = 1;
45          for (long nn = num; nn /= 10; digits++)
46            ;
47          for (int i = digits-1; i >= 0; i--) {
48            if (pos + i + 1 < n) out[pos + i] = '0' + (num % 10);
49            num /= 10;
50          }
51          pos += digits;
52          longarg = false;
53          format = false;
54          break;
55        }
56        case 's':
57        {
58          const char* s2 = va_arg(vl, const char*);
59          while (*s2) {
60            if (++pos < n)
61              out[pos-1] = *s2;
62            s2++;
63          }
64          longarg = false;
65          format = false;
66          break;
67        }
68        case 'c':
69        {
70          if (++pos < n) out[pos-1] = (char)va_arg(vl,int);
71          longarg = false;
72          format = false;
73          break;
74        }
75        default:
76          break;
77      }
78    }
79    else if(*s == '%')
80      format = true;
81    else
82      if (++pos < n) out[pos-1] = *s;
83  }
84  if (pos < n)
85    out[pos] = 0;
86  else if (n)
87    out[n-1] = 0;
88  return pos;
89}
90
91int snprintf(char* out, size_t n, const char* s, ...)
92{
93  va_list vl;
94  va_start(vl, s);
95  int res = vsnprintf(out, n, s, vl);
96  va_end(vl);
97  return res;
98}
99