SayoriOS  0.3.3
sprintf.c
1 #include <stdarg.h>
2 #include "common.h"
3 #include "lib/math.h"
4 #include "mem/vmm.h"
5 #include "io/ports.h"
6 #include "drv/fpu.h"
7 #include "lib/stdlib.h"
8 
9 size_t measure_vsprintf(const char *format, va_list args) {
10  ON_NULLPTR(format, {
11  qemu_log("Format is nullptr!");
12  return 0;
13  });
14 
15  char* fmt = (char*)format;
16  size_t size = 0;
17 
18  while (*fmt) {
19  if (*fmt == '%') {
20  size_t width = 0;
21  bool left_align = false;
22 
23  bool is_precision = false;
24 
25  fmt++;
26 
27  if(*fmt == '.') {
28  is_precision = true;
29 
30  fmt++;
31  }
32 
33  if(*fmt == '-') {
34  left_align = true;
35  fmt++;
36  }
37 
38  while(isdigit(*fmt)) {
39  width = width * 10 + (*fmt - '0');
40  fmt++;
41  }
42 
43  if(*fmt == '*') {
44  width = va_arg(args, int);
45  fmt++;
46  }
47 
48  switch (*fmt) {
49  case 's': {
50  char* arg = va_arg(args, char*);
51  arg = arg ? arg : "(nullptr)";
52 
53  if(is_precision) {
54  size += width;
55  break;
56  }
57 
58  int length = strlen(arg);
59 
60  int space = (int)width - length;
61 
62  if(space > 0)
63  size += space;
64 
65  size += length;
66 
67  break;
68  }
69  case 'c': {
70  (void)va_arg(args, int);
71 
72  size++;
73 
74  break;
75  }
76  case 'f': {
77  double a = va_arg(args, double);
78 
79  if(!fpu_isInitialized()) {
80  size += 7;
81  break;
82  }
83 
84  if(a < 0) {
85  a = -a;
86  size++;
87  }
88 
89  if(a == NAN || a == INFINITY) {
90  size += 3;
91  break;
92  }
93 
94  size_t prec = is_precision ? width : 5;
95 
96  size += digit_count((int)a) + 1 + prec; // xxxx.xxxx
97 
98  break;
99  }
100  case 'i':
101  case 'd': {
102  int num = va_arg(args, int);
103 
104  if(num < 0) {
105  num = -num;
106  size++;
107  }
108 
109  int space = width - digit_count(num);
110 
111  if(left_align)
112  size += digit_count(num);
113 
114  if(space > 0) {
115  size += space;
116  }
117 
118  if(!left_align)
119  size += digit_count(num);
120 
121  break;
122  }
123  case 'u': {
124  unsigned int num = va_arg(args, unsigned int);
125  int space = width - digit_count((int)num);
126 
127  if(space > 0) {
128  size += space;
129  }
130 
131  size += digit_count(num);
132  }
133  case 'p':
134  case 'x': {
135  int num = va_arg(args, int);
136  int space = width - hex_count(num) - 2;
137 
138  if(space > 0) {
139  size += space;
140  }
141 
142  size += hex_count(num) + 2;
143 
144  break;
145  }
146  case 'v': {
147  int num = va_arg(args, int);
148  int space = width - hex_count(num);
149 
150  if(left_align)
151  size += hex_count(num);
152 
153  if(space > 0) {
154  size += space;
155  }
156 
157  if(!left_align)
158  size += hex_count(num);
159 
160  break;
161  }
162  default: {
163  size++;
164  }
165  }
166  } else {
167  size++;
168  }
169 
170  fmt++;
171  }
172 
173  return size + 1;
174 }
175 
176 int vsprintf(char* buffer, const char *format, va_list args) {
177  char* fmt = (char*)format;
178  size_t size = measure_vsprintf(format, args);
179 
180  while (*fmt) {
181  if (*fmt == '%') {
182  // NOTE: If is_precision == true, width is a precision.
183 
184  size_t width = 0;
185  bool left_align = false;
186  bool is_precision = false;
187  bool zero_padding = false;
188 
189  fmt++;
190 
191  if(*fmt == '.') {
192  is_precision = true;
193  fmt++;
194  }
195 
196  if(*fmt == '-') {
197  left_align = true;
198  fmt++;
199  }
200 
201  if(*fmt == '0') {
202  zero_padding = true;
203  fmt++;
204  }
205 
206  while(isdigit(*fmt)) {
207  width = width * 10 + (*fmt - '0');
208  fmt++;
209  }
210 
211  if(*fmt == '*') {
212  width = va_arg(args, int);
213  fmt++;
214  }
215 
216  switch (*fmt) {
217  case 's': {
218  char* arg = va_arg(args, char*);
219  arg = arg ? arg : "(nullptr)";
220 
221  size_t length = strlen(arg);
222  int space = (int)width - (int)length;
223 
224  if(!is_precision && left_align) {
225  memcpy(buffer, arg, length);
226 
227  buffer += length;
228  }
229 
230  if(!is_precision) {
231  if(space > 0) {
232  while(space--)
233  *buffer++ = ' ';
234  }
235  }
236 
237  if(!is_precision && !left_align) {
238  memcpy(buffer, arg, length);
239 
240  buffer += length;
241  }
242 
243  if(is_precision) {
244  for(int i = 0; *arg != '\0' && i < width; i++) {
245  *buffer++ = *arg++;
246  }
247  }
248 
249  break;
250  }
251 
252  case 'c': {
253  *buffer++ = (char)va_arg(args, int); // Standard says that we need int instead of char
254  break;
255  }
256 
257  case 'f': {
258  // FIXME: IMPLEMENT PRECISION HERE!
259 
260  double a = va_arg(args, double);
261  if(!fpu_isInitialized()) {
262  memcpy(buffer, "0.00000", 7);
263 
264  buffer += 7;
265  break;
266  }
267 
268  if(a < 0.0) {
269  *buffer++ = '-';
270  a = -a;
271  }
272 
273 // if(is_nan((float)a)) {
274 // *buffer++ = 'n';
275 // *buffer++ = 'a';
276 // *buffer++ = 'n';
277 //
278 // break;
279 // }
280 //
281 // if(is_inf((float)a)) {
282 // *buffer++ = 'i';
283 // *buffer++ = 'n';
284 // *buffer++ = 'f';
285 //
286 // break;
287 // }
288 
289  double intpart;
290  double floatpart = modf(a, &intpart);
291 
292  itoa((int)intpart, buffer);
293 
294  buffer += digit_count((int)intpart);
295 
296  *buffer++ = '.';
297 
298  size_t prec = is_precision ? width : 5;
299 
300  for(int i = 0; i < prec; i++) {
301  *buffer++ = '0' + (char)((int)(floatpart * pow(10.0, i + 1)) % 10);
302  }
303 
304  break;
305  }
306 
307  case 'i':
308  case 'd': {
309  // FIXME: IMPLEMENT PRECISION HERE!
310  int num = va_arg(args, int);
311 
312  if(num < 0) {
313  num = -num;
314  *buffer++ = '-';
315  }
316 
317  int space = width - digit_count(num);
318 
319  if(left_align) {
320  itoa(num, buffer);
321 
322  buffer += digit_count(num);
323  }
324 
325  if(space > 0) {
326  if(!zero_padding)
327  while(space--)
328  *buffer++ = ' ';
329  else
330  while(space--)
331  *buffer++ = '0';
332  }
333 
334  if(!left_align) {
335  itoa(num, buffer);
336 
337  buffer += digit_count(num);
338  }
339 
340  break;
341  }
342  case 'u': {
343  unsigned int num = va_arg(args, unsigned int);
344  int space = width - digit_count((size_t)num);
345 
346  if(left_align) {
347  itou(num, buffer);
348  buffer += digit_count((size_t)num);
349  }
350 
351  if(space > 0) {
352  if(!zero_padding)
353  while(space--)
354  *buffer++ = ' ';
355  else
356  while(space--)
357  *buffer++ = '0';
358  }
359 
360  if(!left_align) {
361  itou(num, buffer);
362  buffer += digit_count((size_t)num);
363  }
364 
365  break;
366  }
367  case 'p':
368  case 'x': {
369  // TODO: IMPLEMENT PRECISION HERE!
370 
371  unsigned int num = va_arg(args, unsigned int);
372  int space = (int)width - hex_count(num) - 2;
373 
374  if(left_align) {
375  *buffer++ = '0';
376  *buffer++ = 'x';
377 
378  itoh(num, buffer);
379 
380  buffer += hex_count(num);
381  }
382 
383  if(space > 0) {
384  if(!zero_padding)
385  while(space--)
386  *buffer++ = ' ';
387  else
388  while(space--)
389  *buffer++ = '0';
390  }
391 
392  if(!left_align) {
393  *buffer++ = '0';
394  *buffer++ = 'x';
395 
396  itoh(num, buffer);
397 
398  buffer += hex_count(num);
399  }
400 
401  break;
402  }
403  case 'v': {
404  // FIXME: IMPLEMENT PRECISION HERE!
405 
406  int num = va_arg(args, int);
407  int space = width - hex_count(num);
408 
409  if(left_align) {
410  itoh(num, buffer);
411 
412  buffer += hex_count(num);
413  }
414 
415  if(space > 0) {
416  if(!zero_padding)
417  while(space--)
418  *buffer++ = ' ';
419  else
420  while(space--)
421  *buffer++ = '0';
422  }
423 
424  if(!left_align) {
425  itoh(num, buffer);
426 
427  buffer += hex_count(num);
428  }
429 
430  break;
431  }
432  }
433  } else {
434  *buffer++ = *fmt;
435  }
436 
437  fmt++;
438  }
439 
440  return (int)size - 1;
441 }
442 
443 size_t measure_sprintf(const char* format, ...) {
444  va_list args;
445  va_start(args, format);
446 
447  size_t size = measure_vsprintf(format, args);
448 
449  va_end(args);
450 
451  return size;
452 }
453 
454 int sprintf(char* buffer, const char* format, ...) {
455  va_list args;
456  va_start(args, format);
457 
458  size_t size = (int)(measure_vsprintf(format, args)) - 1;
459 
460  vsprintf(buffer, format, args);
461 
462  va_end(args);
463 
464  return size;
465 }
466 
467 int vasprintf(char** buffer, const char* format, va_list args) {
468  size_t size = measure_vsprintf(format, args);
469 
470  *buffer = kcalloc(size, 1);
471 
472  vsprintf(*buffer, format, args);
473 
474  return (int)size - 1;
475 }
476 
477 int asprintf(char** buffer, const char* format, ...) {
478  va_list args;
479  va_start(args, format);
480 
481  vasprintf(buffer, format, args);
482 
483  size_t size = measure_vsprintf(format, args) - 1;
484 
485  va_end(args);
486 
487  return (int)size;
488 }
489 
490 int vsnprintf(char* buffer, size_t n, const char* format, va_list args) {
491  size_t size = measure_vsprintf(format, args);
492 
493  if(buffer == 0 || n == 0) {
494  return size;
495  }
496 
497  char* temp = kcalloc(size + 1, 1);
498 
499  vsprintf(temp, format, args);
500 
501  memcpy(buffer, temp, (size > n ? n : size) - 1);
502 
503  kfree(temp);
504 
505  return size;
506 }
507 
508 int snprintf(char* buffer, size_t n, const char* format, ...) {
509  va_list args;
510  va_start(args, format);
511 
512  size_t res = vsnprintf(buffer, n, format, args);
513 
514  va_end(args);
515 
516  return res;
517 }
Основные определения ядра
bool fpu_isInitialized()
Возвращает статус FPU.
Definition: fpu.c:15
size_t strlen(const char *str)
Возращает длину строки
Definition: string.c:88
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173
size_t itoa(int32_t n, char *buffer)
Конвертируем число в символы
Definition: string.c:623
Definition: stdarg.h:9