2 #include <libc/stdio.h>
3 #include <libc/stdlib.h>
4 #include <libc/string.h>
9 static const char flag_chars[] = "#0- +";
11 #define FLAG_ALT (1<<0)
12 #define FLAG_ZERO (1<<1)
13 #define FLAG_LEFTJUSTIFY (1<<2)
14 #define FLAG_SPACEPOSITIVE (1<<3)
15 #define FLAG_PLUSPOSITIVE (1<<4)
16 #define FLAG_NUMERIC (1<<5)
17 #define FLAG_SIGNED (1<<6)
18 #define FLAG_NEGATIVE (1<<7)
19 #define FLAG_ALT2 (1<<8)
20 #define FLAG_CAPS (1<<9)
23 // FIXME: use something like IO_FILE to abstract this into a more flexible, stream based, vprintf
25 __sprintf_internal(char* buffer, char* fmt, va_list vargs)
27 // This sprintf just a random implementation I found it on Internet . lol.
28 // Of course, with some modifications for porting to LunaixOS :)
30 // TODO: support floating point.
32 char numbuf[NUMBUFSIZ];
42 for (++fmt; *fmt; ++fmt) {
43 const char* flagc = strchr(flag_chars, *fmt);
45 flags |= 1 << (flagc - flag_chars);
53 if (*fmt >= '1' && *fmt <= '9') {
54 for (width = 0; *fmt >= '0' && *fmt <= '9'; ) {
55 width = 10 * width + *fmt++ - '0';
57 } else if (*fmt == '*') {
58 width = va_arg(vargs, int);
66 if (*fmt >= '0' && *fmt <= '9') {
67 for (precision = 0; *fmt >= '0' && *fmt <= '9'; ) {
68 precision = 10 * precision + *fmt++ - '0';
70 } else if (*fmt == '*') {
71 precision = va_arg(vargs, int);
79 // process main conversion character
81 unsigned long num = 0;
93 long x = length ? va_arg(vargs, long) : va_arg(vargs, int);
94 int negative = x < 0 ? FLAG_NEGATIVE : 0;
95 num = negative ? -x : x;
96 flags |= FLAG_NUMERIC | FLAG_SIGNED | negative;
101 num = length ? va_arg(vargs, unsigned long) : va_arg(vargs, unsigned);
102 flags |= FLAG_NUMERIC;
106 goto format_unsigned;
108 flags = flags | FLAG_CAPS;
110 goto format_unsigned;
112 num = (uintptr_t) va_arg(vargs, void*);
114 flags |= FLAG_ALT | FLAG_ALT2 | FLAG_NUMERIC;
117 data = va_arg(vargs, char*);
121 numbuf[0] = va_arg(vargs, int);
126 numbuf[0] = (*fmt ? *fmt : '%');
134 if (flags & FLAG_NUMERIC) {
135 data = itoa(num, numbuf, base);
138 while ((flags & FLAG_CAPS) && (c = data[i]))
140 data[i] = c & ~((c & 0x40) >> 1);
145 const char* prefix = "";
146 if ((flags & FLAG_NUMERIC) && (flags & FLAG_SIGNED)) {
147 if (flags & FLAG_NEGATIVE) {
149 } else if (flags & FLAG_PLUSPOSITIVE) {
151 } else if (flags & FLAG_SPACEPOSITIVE) {
154 } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ALT)
155 && (base == 16 || base == -16)
156 && (num || (flags & FLAG_ALT2))) {
161 if (precision >= 0 && !(flags & FLAG_NUMERIC)) {
162 len = strnlen(data, precision);
167 if ((flags & FLAG_NUMERIC) && precision >= 0) {
168 zeros = precision > len ? precision - len : 0;
169 } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ZERO)
170 && !(flags & FLAG_LEFTJUSTIFY)
171 && len + (int) strlen(prefix) < width) {
172 zeros = width - len - strlen(prefix);
176 width -= len + zeros + strlen(prefix);
177 for (; !(flags & FLAG_LEFTJUSTIFY) && width > 0; --width) {
180 for (; *prefix; ++prefix) {
181 buffer[ptr++] = *prefix;
183 for (; zeros > 0; --zeros) {
186 for (; len > 0; ++data, --len) {
187 buffer[ptr++] = *data;
189 for (; width > 0; --width) {
193 buffer[ptr++] = '\0';
197 sprintf(char* buffer, char* fmt, ...)
201 __sprintf_internal(buffer, fmt, args);