summaryrefslogtreecommitdiff
path: root/src/stdio/vsnprintf_s.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdio/vsnprintf_s.c')
-rw-r--r--src/stdio/vsnprintf_s.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/stdio/vsnprintf_s.c b/src/stdio/vsnprintf_s.c
new file mode 100644
index 00000000..48fbe425
--- /dev/null
+++ b/src/stdio/vsnprintf_s.c
@@ -0,0 +1,216 @@
+#include "internal_vsnprintf.c"
+#include <inttypes.h>
+
+int vsnprintf_s(char * restrict s, rsize_t n, const char * restrict format, va_list arg)
+{
+ __C_EXT(1, 201112L);
+ int nout = 0;
+
+ intmax_t argint = 0;
+ void *argptr = NULL;
+ char numbuf[NUMBUFLEN];
+
+ for (size_t i = 0; format[i] != 0; i++) {
+ if (format[i] != '%') {
+ if (nout < (int)n) {
+ s[nout] = format[i];
+ }
+ nout++;
+ continue;
+ }
+
+ //__asm int 3;
+ // zero of more flags "-+ #0"
+ // optional width "*" or decimal integer
+ // optional precision ".*" or ".[decimal]"
+ // optional length modifier "hh", "h", "l", "ll", "j",
+ // "z", "t", "L"
+ // conversion specifier "diouxXfFeEgGaAcspn%"
+ int flags = 0;
+ uintmax_t width = 0;
+ int step = 0;
+ int precision = 0;
+ int base = 10;
+ enum { def, hh, h, l, ll, j, z, t, L } length = def;
+
+ while (step == 0) {
+ i++;
+ switch (format[i]) {
+ case '-': flags |= LEFT; break;
+ case '+': flags |= SIGN; break;
+ case ' ': flags |= SPACE; break;
+ case '#': flags |= ALT; break;
+ case '0': flags |= ZERO; break;
+ default: step = 1; break;
+ }
+ }
+
+ if (format[i] == '*') {
+ i++;
+ } else if (isdigit(format[i])) {
+ char *end;
+ width = strtoumax(format + i, &end, 10);
+ i = end - format;
+ }
+
+ if (format[i] == '.') {
+ i++;
+ if (format[i] == '*') {
+ i++;
+ } else if (isdigit(format[i])) {
+ char *end;
+ precision = (int)strtoumax(format + i, &end, 10);
+ i = end - format;
+ } else {
+ // invalid precision
+ return -nout;
+ }
+ }
+
+ if (format[i] == 'h') {
+ i++;
+ if (format[i] == 'h') {
+ i++;
+ length = hh;
+ } else {
+ length = h;
+ }
+ } else if (format[i] == 'l') {
+ i++;
+ if (format[i] == 'l') {
+ i++;
+ length = ll;
+ } else {
+ length = l;
+ }
+ } else if (format[i] == 'j') {
+ i++;
+ length = j;
+ } else if (format[i] == 'z') {
+ i++;
+ length = z;
+ } else if (format[i] == 't') {
+ i++;
+ length = t;
+ } else if (format[i] == 'L') {
+ i++;
+ length = L;
+ }
+
+ if (isupper(format[i])) {
+ flags |= UPPER;
+ }
+
+ switch (format[i]) {
+ case 'o': // unsigned int
+ case 'u':
+ case 'x':
+ case 'X':
+ flags |= UNSIGNED;
+
+ case 'd': // int
+ case 'i':
+ switch (length) {
+ case hh: argint = (signed char)va_arg(arg, int); break;
+ case h: argint = (short int)va_arg(arg, int); break;
+ case l: argint = va_arg(arg, long int); break;
+ case ll: argint = va_arg(arg, long long int); break;
+ case j: argint = va_arg(arg, intmax_t); break;
+ case z: argint = va_arg(arg, size_t); break;
+ case t: argint = va_arg(arg, ptrdiff_t); break;
+ case L: return -nout;
+ default: argint = va_arg(arg, int); break;
+ }
+ if (format[i] == 'o') {
+ base = 8;
+ } else if (format[i] == 'x') {
+ base = 16;
+ } else if (format[i] == 'X') {
+ base = 16;
+ flags |= UPPER;
+ } else {
+ base = 10;
+ }
+ itos(numbuf, (long int)argint, flags, precision, base);
+ nout = append(s, numbuf, nout, n);
+ break;
+
+
+ case 'f': // double [-]ddd.ddd
+ case 'F':
+ break;
+
+ case 'e': // double [-]d.ddde+/-dd
+ case 'E':
+ break;
+
+ case 'g': // double f or e see docs
+ case 'G':
+ break;
+
+ case 'a': // double as hex
+ case 'A':
+ break;
+
+ case 'c': // char
+ if (length == def) {
+ char c = va_arg(arg, int);
+ if (nout < (int)n) {
+ s[nout] = c;
+ }
+ nout++;
+ } else if (length == l) {
+ //wint_t wc = va_arg(arg, wint_t);
+ //char mb[MB_CUR_MAX + 1] = "WC";
+ //wctomb(mb, wc);
+ //nout = append(s, mb, nout, n);
+ } else {
+ return -nout;
+ }
+ break;
+
+ case 's': // string
+ if (length == def) {
+ char *string = va_arg(arg, char *);
+ nout = append(s, string, nout, n);
+ } else if (length == l) {
+ //wchar_t *ws = va_arg(arg, wchar_t *);
+ //char *mbs = malloc(wcslen(ws) * MB_CUR_MAX + 1);
+ //wcstombs(mbs, ws, wcslen(ws) * MB_CUR_MAX + 1);
+ //nout = append(s, mbs, nout, n);
+ //free(mbs);
+ nout = append(s, "WIDE STRING", nout, n);
+ } else {
+ return -nout;
+ }
+
+ break;
+
+ case 'p': // pointer
+ argptr = va_arg(arg, void *);
+ nout = append(s, "0x", nout, n);
+ itos(numbuf, (intptr_t)argptr, ZERO, sizeof(argptr) * 2, 16);
+ nout = append(s, numbuf, nout, n);
+ break;
+
+ case 'n': // write-back
+ break;
+
+ case '%': // literal '%'
+ if (nout < (int)n) {
+ s[nout] = '%';
+ }
+ nout++;
+ break;
+
+ default: // undefined
+ return -nout;
+ }
+ }
+
+ return nout;
+}
+
+/*
+CEXT1(201112)
+*/