feat: kill(2) implementation
[lunaix-os.git] / lunaix-os / libs / klibc / stdio / sprintf.c
1 #define __LUNAIX_LIBC
2 #include <klibc/stdio.h>
3 #include <klibc/stdlib.h>
4 #include <klibc/string.h>
5 #include <stdint.h>
6
7 #define NUMBUFSIZ 24
8
9 static const char flag_chars[] = "#0- +";
10
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)
21
22
23 // FIXME: use something like IO_FILE to abstract this into a more flexible, stream based, vprintf
24 void
25 __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
26 {
27     // This sprintf just a random implementation I found it on Internet . lol.
28     //      Of course, with some modifications for porting to LunaixOS :)
29
30     char numbuf[NUMBUFSIZ];
31     uint32_t ptr = 0;
32     for (; *fmt; ++fmt) {
33         if (max_len && ptr >= max_len - 1) {
34             break;
35         }
36         
37         if (*fmt != '%') {
38             buffer[ptr++] = *fmt;
39             continue;
40         }
41
42         // process flags
43         int flags = 0;
44         for (++fmt; *fmt; ++fmt) {
45             const char* flagc = strchr(flag_chars, *fmt);
46             if (flagc) {
47                 flags |= 1 << (flagc - flag_chars);
48             } else {
49                 break;
50             }
51         }
52
53         // process width
54         int width = -1;
55         if (*fmt >= '1' && *fmt <= '9') {
56             for (width = 0; *fmt >= '0' && *fmt <= '9'; ) {
57                 width = 10 * width + *fmt++ - '0';
58             }
59         } else if (*fmt == '*') {
60             width = va_arg(vargs, int);
61             ++fmt;
62         }
63
64         // process precision
65         int precision = -1;
66         if (*fmt == '.') {
67             ++fmt;
68             if (*fmt >= '0' && *fmt <= '9') {
69                 for (precision = 0; *fmt >= '0' && *fmt <= '9'; ) {
70                     precision = 10 * precision + *fmt++ - '0';
71                 }
72             } else if (*fmt == '*') {
73                 precision = va_arg(vargs, int);
74                 ++fmt;
75             }
76             if (precision < 0) {
77                 precision = 0;
78             }
79         }
80
81         // process main conversion character
82         int base = 10;
83         unsigned long num = 0;
84         int length = 0;
85         char* data = "";
86     again:
87         switch (*fmt) {
88         case 'l':
89         case 'z':
90             length = 1;
91             ++fmt;
92             goto again;
93         case 'd':
94         case 'i': {
95             long x = length ? va_arg(vargs, long) : va_arg(vargs, int);
96             int negative = x < 0 ? FLAG_NEGATIVE : 0;
97             num = negative ? -x : x;
98             flags |= FLAG_NUMERIC | FLAG_SIGNED | negative;
99             break;
100         }
101         case 'u':
102         format_unsigned:
103             num = length ? va_arg(vargs, unsigned long) : va_arg(vargs, unsigned);
104             flags |= FLAG_NUMERIC;
105             break;
106         case 'x':
107             base = 16;
108             goto format_unsigned;
109         case 'X':
110             flags = flags | FLAG_CAPS;
111             base = 16;
112             goto format_unsigned;
113         case 'p':
114             num = (uintptr_t) va_arg(vargs, void*);
115             base = 16;
116             flags |= FLAG_ALT | FLAG_ALT2 | FLAG_NUMERIC;
117             break;
118         case 's':
119             data = va_arg(vargs, char*);
120             break;
121         case 'c':
122             data = numbuf;
123             numbuf[0] = va_arg(vargs, int);
124             numbuf[1] = '\0';
125             break;
126         default:
127             data = numbuf;
128             numbuf[0] = (*fmt ? *fmt : '%');
129             numbuf[1] = '\0';
130             if (!*fmt) {
131                 fmt--;
132             }
133             break;
134         }
135
136         if (flags & FLAG_NUMERIC) {
137             data = itoa(num, numbuf, base);
138             int i = 0;
139             char c;
140             while ((flags & FLAG_CAPS) && (c = data[i]))
141             {
142                 data[i] = c & ~((c & 0x40) >> 1);
143                 i++;
144             }
145         }
146
147         const char* prefix = "";
148         if ((flags & FLAG_NUMERIC) && (flags & FLAG_SIGNED)) {
149             if (flags & FLAG_NEGATIVE) {
150                 prefix = "-";
151             } else if (flags & FLAG_PLUSPOSITIVE) {
152                 prefix = "+";
153             } else if (flags & FLAG_SPACEPOSITIVE) {
154                 prefix = " ";
155             }
156         } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ALT)
157                    && (base == 16 || base == -16)
158                    && (num || (flags & FLAG_ALT2))) {
159             prefix = "0x";
160         }
161
162         int len;
163         if (precision >= 0 && !(flags & FLAG_NUMERIC)) {
164             len = strnlen(data, precision);
165         } else {
166             len = strlen(data);
167         }
168         int zeros;
169         if ((flags & FLAG_NUMERIC) && precision >= 0) {
170             zeros = precision > len ? precision - len : 0;
171         } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ZERO)
172                    && !(flags & FLAG_LEFTJUSTIFY)
173                    && len + (int) strlen(prefix) < width) {
174             zeros = width - len - strlen(prefix);
175         } else {
176             zeros = 0;
177         }
178         width -= len + zeros + strlen(prefix);
179         for (; !(flags & FLAG_LEFTJUSTIFY) && width > 0; --width) {
180             buffer[ptr++] = ' ';
181         }
182         for (; *prefix; ++prefix) {
183             buffer[ptr++] = *prefix;
184         }
185         for (; zeros > 0; --zeros) {
186             buffer[ptr++] = '0';
187         }
188         for (; len > 0; ++data, --len) {
189             buffer[ptr++] = *data;
190         }
191         for (; width > 0; --width) {
192             buffer[ptr++] = ' ';
193         }
194     }
195     buffer[ptr++] = '\0';
196 }
197
198 void
199 sprintf(char* buffer, char* fmt, ...)
200 {
201     va_list args;
202     va_start(args, fmt);
203     __sprintf_internal(buffer, fmt, 0, args);
204     va_end(args);
205 }
206
207 void
208 snprintf(char* buffer, size_t n, char* fmt, ...)
209 {
210     va_list args;
211     va_start(args, fmt);
212     __sprintf_internal(buffer, fmt, n, args);
213     va_end(args);
214 }