PatchworkOS
Loading...
Searching...
No Matches
print.c
Go to the documentation of this file.
1#include "print.h"
2
3#include "common/digits.h"
4
5#include <inttypes.h>
6#include <limits.h>
7#include <stdarg.h>
8#include <stddef.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#ifndef __KERNEL__
15#include "user/common/file.h"
16#endif
17
18#define _DBL_SIGN(bytes) (((unsigned)bytes[7] & 0x80) >> 7)
19#define _DBL_DEC(bytes) ((_DBL_EXP(bytes) > 0) ? 1 : 0)
20#define _DBL_EXP(bytes) ((((unsigned)bytes[7] & 0x7f) << 4) | (((unsigned)bytes[6] & 0xf0) >> 4))
21#define _DBL_BIAS 1023
22#define _DBL_MANT_START(bytes) (bytes + 6)
23
24#if __LDBL_MANT_DIG__ == 64
25
26/* Intel "Extended Precision" format, using 80 bits (64bit mantissa) */
27#define _LDBL_SIGN(bytes) (((unsigned)bytes[9] & 0x80) >> 7)
28#define _LDBL_DEC(bytes) (((unsigned)bytes[7] & 0x80) >> 7)
29#define _LDBL_EXP(bytes) ((((unsigned)bytes[9] & 0x7f) << 8) | (unsigned)bytes[8])
30#define _LDBL_BIAS 16383
31#define _LDBL_MANT_START(bytes) (bytes + 7)
32
33#elif __LDBL_MANT_DIG__ == 113
34
35/* IEEE "Quadruple Precision" format, using 128 bits (113bit mantissa) */
36#define _LDBL_SIGN(bytes) (((unsigned)bytes[15] & 0x80) >> 7)
37#define _LDBL_DEC(bytes) ((_LDBL_EXP(bytes) > 0) ? 1 : 0)
38#define _LDBL_EXP(bytes) ((((unsigned)bytes[15] & 0x7f) << 8) | (unsigned)bytes[14])
39#define _LDBL_BIAS 16383
40#define _LDBL_MANT_START(bytes) (bytes + 13)
41
42#else
43/* IEEE "Double Precision" format, using 64 bits (53bit mantissa,
44 same as DBL above) */
45#define _LDBL_SIGN(bytes) (((unsigned)bytes[7] & 0x80) >> 7)
46#define _LDBL_DEC(bytes) ((_LDBL_EXP(bytes) > 0) ? 1 : 0)
47#define _LDBL_EXP(bytes) ((((unsigned)bytes[7] & 0x7f) << 4) | (((unsigned)bytes[6] & 0xf0) >> 4))
48#define _LDBL_BIAS 1023
49#define _LDBL_MANT_START(bytes) (bytes + 6)
50#endif
51
52#ifndef __KERNEL__
53#define _PRINT_PUT(ctx, x) \
54 ({ \
55 int character = x; \
56 if ((ctx)->totalChars < (ctx)->maxChars) \
57 { \
58 if ((ctx)->stream != NULL) \
59 { \
60 putc(character, (ctx)->stream); \
61 } \
62 else \
63 { \
64 (ctx)->buffer[(ctx)->totalChars] = character; \
65 } \
66 } \
67 ++((ctx)->totalChars); \
68 })
69#else
70#define _PRINT_PUT(ctx, x) \
71 ({ \
72 int character = x; \
73 if ((ctx)->totalChars < (ctx)->maxChars) \
74 { \
75 if ((ctx)->buffer != NULL) \
76 { \
77 (ctx)->buffer[(ctx)->totalChars] = character; \
78 } \
79 } \
80 ++((ctx)->totalChars); \
81 })
82#endif
83
84#ifndef __KERNEL__
85
86static void _print_hexa(int sign, int exp, int dec, unsigned char const* mant, size_t mant_dig, _format_ctx_t* ctx)
87{
88 size_t excess_bits;
89 char value = '\0';
90
91 unsigned char mantissa[32] = {0};
92 size_t m = 0;
93
94 char exponent[32];
95 size_t e = 0;
96
97 size_t i;
98
99 char const* digit_chars = (ctx->flags & FORMAT_LOWER) ? _digits : _xdigits;
100
101 int index_offset = 0;
102
103 //_static_assert(__FLT_RADIX__ == 2, "Assuming 2-based FP");
104 //_static_assert(__CHAR_BIT__ == 8, "Assuming 8-bit bytes");
105
106 /* Mantissa */
107 /* -------- */
108
109 /* Handle the most significant byte (which might need masking) */
110 excess_bits = (mant_dig - 1) % 8;
111
112 if (excess_bits > 0)
113 {
114 value = *mant & ((1 << excess_bits) - 1);
115
116 if (excess_bits >= 4)
117 {
118 mantissa[1] = value & 0x0f;
119 value >>= 4;
120 excess_bits -= 4;
121 ++m;
122 }
123
124 index_offset = 1;
125 }
126
127 mantissa[0] = (dec << excess_bits) | (value & ((1 << excess_bits) - 1));
128
129 /* Now handle the remaining bytes. */
130 /* This is doing a little trick: m is the highest valid index
131 (or a count of *fractional* digits, if you like), not a count
132 of elements (0..1, not 1..2), so it can double as an index
133 into the mant[] array (when divided by 2).
134 */
135 while (m < ((mant_dig + 3) / 4 - 1))
136 {
137 value = *(mant - ((m / 2) + index_offset));
138 mantissa[++m] = (value & 0xf0) >> 4;
139 mantissa[++m] = (value & 0x0f);
140 }
141
142 /* Roll back trailing zeroes */
143 while (m > 0 && mantissa[m] == 0)
144 {
145 --m;
146 }
147
148 /* Exponent */
149 /* -------- */
150
151 exp -= excess_bits;
152
153 if ((m == 0 && dec == 0) || exp == 0)
154 {
155 /* All zero */
156 exponent[0] = '+';
157 exponent[1] = '0';
158 e = 2;
159 }
160 else
161 {
162 if (dec == 0)
163 {
164 /* Subnormal */
165 ++exp;
166 }
167
168 if (exp >= 0)
169 {
170 exponent[0] = '+';
171 }
172 else
173 {
174 exponent[0] = '-';
175 exp *= -1;
176 }
177
178 for (e = 1; exp > 0; ++e)
179 {
180 div_t d = div(exp, 10);
181 exponent[e] = digit_chars[d.rem];
182 exp = d.quot;
183 }
184 }
185
186 exponent[e] = '\0';
187
188 /* Rounding */
189 /* -------- */
190
191 if ((ctx->precision >= 0) && (m > (size_t)ctx->precision))
192 {
193 i = ctx->precision;
194
195 if ((mantissa[i + 1] > 8) || ((mantissa[i + 1] == 8) && ((m >= i + 2) || (mantissa[i] % 2))))
196 {
197 while ((++mantissa[i]) > 0xf)
198 {
199 mantissa[i--] = 0;
200 }
201 }
202
203 m = i;
204 }
205
206 /* Padding */
207 /* ------- */
208
209 ctx->currentChars = m + 4 + (sign != '\0') + ((m > 0) || (ctx->precision > 0) || (ctx->flags & FORMAT_ALT)) + e;
210
211 if (!(ctx->flags & (FORMAT_ZERO | FORMAT_MINUS)))
212 {
213 for (i = ctx->currentChars; i < ctx->width; ++i)
214 {
215 _PRINT_PUT(ctx, ' ');
216 }
217 }
218
219 if (sign != '\0')
220 {
221 _PRINT_PUT(ctx, sign);
222 }
223
224 /* Output */
225 /* ------ */
226
227 _PRINT_PUT(ctx, '0');
228 _PRINT_PUT(ctx, (ctx->flags & FORMAT_LOWER) ? 'x' : 'X');
229
230 _PRINT_PUT(ctx, digit_chars[mantissa[0]]);
231
232 if (((m > 0) && (ctx->precision != 0)) || (ctx->precision > 0) || (ctx->flags & FORMAT_ALT))
233 {
234 _PRINT_PUT(ctx, '.');
235 }
236
237 if ((ctx->flags & FORMAT_ZERO) && !(ctx->flags & FORMAT_MINUS))
238 {
239 for (i = ctx->currentChars; i < ctx->width; ++i)
240 {
241 _PRINT_PUT(ctx, '0');
242 }
243 }
244
245 for (i = 1; i <= m; ++i)
246 {
247 _PRINT_PUT(ctx, digit_chars[mantissa[i]]);
248 }
249
250 while ((int)i <= ctx->precision)
251 {
252 _PRINT_PUT(ctx, '0');
253 ++i;
254 }
255
256 _PRINT_PUT(ctx, (ctx->flags & FORMAT_LOWER) ? 'p' : 'P');
257 _PRINT_PUT(ctx, exponent[0]);
258
259 for (i = e - 1; i > 0; --i)
260 {
261 _PRINT_PUT(ctx, exponent[i]);
262 }
263}
264
265/* dec: 1 - normalized, 0 - subnormal
266exp: INT_MAX - infinity, INT_MIN - Not a Number
267mant: MSB of the mantissa
268mant_dig: base FLT_RADIX digits in the mantissa, including the decimal
269*/
270static void _print_fp(int sign, int exp, int dec, unsigned char const* mant, size_t mant_dig, _format_ctx_t* ctx)
271{
272 /* Turning sign bit into sign character. */
273 if (sign)
274 {
275 sign = '-';
276 }
277 else if (ctx->flags & FORMAT_PLUS)
278 {
279 sign = '+';
280 }
281 else if (ctx->flags & FORMAT_SPACE)
282 {
283 sign = ' ';
284 }
285 else
286 {
287 sign = '\0';
288 }
289
290 if (exp == INT_MIN || exp == INT_MAX)
291 {
292 /* "nan" / "inf" */
293 char const* s =
294 (ctx->flags & FORMAT_LOWER) ? ((exp == INT_MIN) ? "nan" : "inf") : ((exp == INT_MIN) ? "NAN" : "INF");
295
296 ctx->currentChars = (sign == '\0') ? 3 : 4;
297
298 if (!(ctx->flags & FORMAT_MINUS))
299 {
300 while (ctx->currentChars < ctx->width)
301 {
302 _PRINT_PUT(ctx, ' ');
303 ++ctx->currentChars;
304 }
305 }
306
307 if (sign != '\0')
308 {
309 _PRINT_PUT(ctx, sign);
310 }
311
312 while (*s)
313 {
314 _PRINT_PUT(ctx, *s++);
315 }
316
317 return;
318 }
319
321 {
322 case FORMAT_HEXA:
323 _print_hexa(sign, exp, dec, mant, mant_dig, ctx);
324 break;
325 case FORMAT_DECIMAL:
326 case FORMAT_EXPONENT:
327 case FORMAT_GENERIC:
328 default:
329 break;
330 }
331}
332
333static void _print_double(double value, _format_ctx_t* ctx)
334{
335 unsigned char bytes[sizeof(double)];
336 int exp;
337 memcpy(bytes, &value, sizeof(double));
338 exp = _DBL_EXP(bytes) - _DBL_BIAS;
339
340 if (exp == __DBL_MAX_EXP__)
341 {
342 /* NAN INF */
343 exp = (value != value) ? INT_MIN : INT_MAX;
344 }
345
346 _print_fp(_DBL_SIGN(bytes), exp, _DBL_DEC(bytes), _DBL_MANT_START(bytes), __DBL_MANT_DIG__, ctx);
347}
348
349static void _print_ldouble(long double value, _format_ctx_t* ctx)
350{
351 unsigned char bytes[sizeof(long double)];
352 int exp;
353 memcpy(bytes, &value, sizeof(long double));
354 exp = _LDBL_EXP(bytes) - _LDBL_BIAS;
355
356 if (exp == __LDBL_MAX_EXP__)
357 {
358 /* NAN INF */
359 exp = (value != value) ? INT_MIN : INT_MAX;
360 }
361
362 _print_fp(_LDBL_SIGN(bytes), exp, _LDBL_DEC(bytes), _LDBL_MANT_START(bytes), __LDBL_MANT_DIG__, ctx);
363}
364
365#endif
366
367static void _int_format(intmax_t value, _format_ctx_t* ctx)
368{
369 /* At worst, we need two prefix characters (hex prefix). */
370 char preface[3] = "\0";
371 size_t preidx = 0;
372
373 if (ctx->precision < 0)
374 {
375 ctx->precision = 1;
376 }
377
378 if ((ctx->flags & FORMAT_ALT) && (ctx->base == 16 || ctx->base == 8) && (value != 0))
379 {
380 /* Octal / hexadecimal prefix for "%#" conversions */
381 preface[preidx++] = '0';
382
383 if (ctx->base == 16)
384 {
385 preface[preidx++] = (ctx->flags & FORMAT_LOWER) ? 'x' : 'X';
386 }
387 }
388
389 if (value < 0)
390 {
391 /* Negative sign for negative values - at all times. */
392 preface[preidx++] = '-';
393 }
394 else if (!(ctx->flags & FORMAT_UNSIGNED))
395 {
396 /* plus sign / extra space are only for signed conversions */
397 if (ctx->flags & FORMAT_PLUS)
398 {
399 preface[preidx++] = '+';
400 }
401 else
402 {
403 if (ctx->flags & FORMAT_SPACE)
404 {
405 preface[preidx++] = ' ';
406 }
407 }
408 }
409
410 {
411 /* At this point, ctx->currentChars has the number of digits queued up.
412 Determine if we have a precision requirement to pad those.
413 */
414 size_t prec_pads =
415 ((size_t)ctx->precision > ctx->currentChars) ? ((size_t)ctx->precision - ctx->currentChars) : 0;
416
417 if (!(ctx->flags & (FORMAT_MINUS | FORMAT_ZERO)))
418 {
419 /* Space padding is only done if no zero padding or left alignment
420 is requested. Calculate the number of characters that WILL be
421 printed, including any prefixes determined above.
422 */
423 /* The number of characters to be printed, plus prefixes if any. */
424 /* This line contained probably the most stupid, time-wasting bug
425 I've ever perpetrated. Greetings to Samface, DevL, and all
426 sceners at Breakpoint 2006.
427 */
428 size_t characters =
429 preidx + ((ctx->currentChars > (size_t)ctx->precision) ? ctx->currentChars : (size_t)ctx->precision);
430
431 if (ctx->width > characters)
432 {
433 size_t i;
434
435 for (i = 0; i < ctx->width - characters; ++i)
436 {
437 _PRINT_PUT(ctx, ' ');
438 ++(ctx->currentChars);
439 }
440 }
441 }
442
443 /* Now we did the padding, do the prefixes (if any). */
444 preidx = 0;
445
446 while (preface[preidx] != '\0')
447 {
448 _PRINT_PUT(ctx, preface[preidx++]);
449 ++(ctx->currentChars);
450 }
451
452 /* Do the precision padding if necessary. */
453 while (prec_pads-- > 0)
454 {
455 _PRINT_PUT(ctx, '0');
456 ++(ctx->currentChars);
457 }
458
459 if ((!(ctx->flags & FORMAT_MINUS)) && (ctx->flags & FORMAT_ZERO))
460 {
461 /* If field is not left aligned, and zero padding is requested, do
462 so.
463 */
464 while (ctx->currentChars < ctx->width)
465 {
466 _PRINT_PUT(ctx, '0');
467 ++(ctx->currentChars);
468 }
469 }
470 }
471}
472
474{
475 if (ctx->currentChars == 0 && div.quot == 0 && div.rem == 0 && ctx->precision == 0)
476 {
477 _int_format(0, ctx);
478 }
479 else
480 {
481 ++(ctx->currentChars);
482
483 if (div.quot != 0)
484 {
485 _print_integer(imaxdiv(div.quot, ctx->base), ctx);
486 }
487 else
488 {
489 _int_format(div.rem, ctx);
490 }
491
492 if (div.rem < 0)
493 {
494 div.rem *= -1;
495 }
496
497 if (ctx->flags & FORMAT_LOWER)
498 {
499 _PRINT_PUT(ctx, _digits[div.rem]);
500 }
501 else
502 {
503 _PRINT_PUT(ctx, _xdigits[div.rem]);
504 }
505 }
506}
507
508static void _print_string(const char* s, _format_ctx_t* ctx)
509{
510 if (ctx->flags & FORMAT_CHAR)
511 {
512 ctx->precision = 1;
513 }
514 else
515 {
516 if (ctx->precision < 0)
517 {
518 ctx->precision = strlen(s);
519 }
520 else
521 {
522 int i;
523
524 for (i = 0; i < ctx->precision; ++i)
525 {
526 if (s[i] == 0)
527 {
528 ctx->precision = i;
529 break;
530 }
531 }
532 }
533 }
534
535 if (!(ctx->flags & FORMAT_MINUS) && (ctx->width > (size_t)ctx->precision))
536 {
537 while (ctx->currentChars < (ctx->width - ctx->precision))
538 {
539 _PRINT_PUT(ctx, ' ');
540 ++(ctx->currentChars);
541 }
542 }
543
544 while (ctx->precision > 0)
545 {
546 _PRINT_PUT(ctx, *(s++));
547 --(ctx->precision);
548 ++(ctx->currentChars);
549 }
550
551 if (ctx->flags & FORMAT_MINUS)
552 {
553 while (ctx->width > ctx->currentChars)
554 {
555 _PRINT_PUT(ctx, ' ');
556 ++(ctx->currentChars);
557 }
558 }
559}
560
561const char* _print(const char* spec, _format_ctx_t* ctx)
562{
563 const char* orig_spec = spec;
564
565 if (*(++spec) == '%')
566 {
567 /* %% -> print single '%' */
568 _PRINT_PUT(ctx, *spec);
569 return ++spec;
570 }
571
572 /* Initializing ctx structure */
573 ctx->flags = 0;
574 ctx->base = 0;
575 ctx->currentChars = 0;
576 ctx->width = 0;
577 ctx->precision = EOF;
578
579 /* First come 0..n flags */
580 do
581 {
582 switch (*spec)
583 {
584 case '-':
585 /* left-aligned output */
586 ctx->flags |= FORMAT_MINUS;
587 ++spec;
588 break;
589
590 case '+':
591 /* positive numbers prefixed with '+' */
592 ctx->flags |= FORMAT_PLUS;
593 ++spec;
594 break;
595
596 case '#':
597 /* alternative format (leading 0x for hex, 0 for octal) */
598 ctx->flags |= FORMAT_ALT;
599 ++spec;
600 break;
601
602 case ' ':
603 /* positive numbers prefixed with ' ' */
604 ctx->flags |= FORMAT_SPACE;
605 ++spec;
606 break;
607
608 case '0':
609 /* right-aligned padding done with '0' instead of ' ' */
610 ctx->flags |= FORMAT_ZERO;
611 ++spec;
612 break;
613
614 default:
615 /* not a flag, exit flag parsing */
616 ctx->flags |= FORMAT_DONE;
617 break;
618 }
619 } while (!(ctx->flags & FORMAT_DONE));
620
621 /* Optional field width */
622 if (*spec == '*')
623 {
624 /* Retrieve width value from argument stack */
625 int width = va_arg(ctx->arg, int);
626
627 if (width < 0)
628 {
629 ctx->flags |= FORMAT_MINUS;
630 ctx->width = abs(width);
631 }
632 else
633 {
634 ctx->width = width;
635 }
636
637 ++spec;
638 }
639 else
640 {
641 /* If a width is given, strtol() will return its value. If not given,
642 strtol() will return zero. In both cases, endptr will point to the
643 rest of the conversion specifier - just what we need.
644 */
645 ctx->width = (int)strtol(spec, (char**)&spec, 10);
646 }
647
648 /* Optional precision */
649 if (*spec == '.')
650 {
651 ++spec;
652
653 if (*spec == '*')
654 {
655 /* Retrieve precision value from argument stack. A negative value
656 is as if no precision is given - as precision is initalized to
657 EOF (negative), there is no need for testing for negative here.
658 */
659 ctx->precision = va_arg(ctx->arg, int);
660 ++spec;
661 }
662 else
663 {
664 char* endptr;
665 ctx->precision = (int)strtol(spec, &endptr, 10);
666
667 if (spec == endptr)
668 {
669 /* Decimal point but no number - equals zero */
670 ctx->precision = 0;
671 }
672
673 spec = endptr;
674 }
675
676 /* Having a precision cancels out any zero flag. */
677 ctx->flags &= ~FORMAT_ZERO;
678 }
679
680 /* Optional length modifier
681 We step one character ahead in any case, and step back only if we find
682 there has been no length modifier (or step ahead another character if it
683 has been "hh" or "ll").
684 */
685 switch (*(spec++))
686 {
687 case 'h':
688 if (*spec == 'h')
689 {
690 /* hh -> char */
691 ctx->flags |= FORMAT_CHAR;
692 ++spec;
693 }
694 else
695 {
696 /* h -> short */
697 ctx->flags |= FORMAT_SHORT;
698 }
699
700 break;
701
702 case 'l':
703 if (*spec == 'l')
704 {
705 /* ll -> long long */
706 ctx->flags |= FORMAT_LLONG;
707 ++spec;
708 }
709 else
710 {
711 /* k -> long */
712 ctx->flags |= FORMAT_LONG;
713 }
714
715 break;
716
717 case 'j':
718 /* j -> intmax_t, which might or might not be long long */
719 ctx->flags |= FORMAT_INTMAX;
720 break;
721
722 case 'z':
723 /* z -> size_t, which might or might not be unsigned int */
724 ctx->flags |= FORMAT_SIZE;
725 break;
726
727 case 't':
728 /* t -> ptrdiff_t, which might or might not be long */
729 ctx->flags |= FORMAT_PTRDIFF;
730 break;
731
732 case 'L':
733 /* L -> long double */
734 ctx->flags |= FORMAT_LDOUBLE;
735 break;
736
737 default:
738 --spec;
739 break;
740 }
741
742 /* Conversion specifier */
743 switch (*spec)
744 {
745 case 'd':
746 /* FALLTHROUGH */
747
748 case 'i':
749 ctx->base = 10;
750 break;
751
752 case 'o':
753 ctx->base = 8;
754 ctx->flags |= FORMAT_UNSIGNED;
755 break;
756
757 case 'u':
758 ctx->base = 10;
759 ctx->flags |= FORMAT_UNSIGNED;
760 break;
761
762 case 'x':
763 ctx->base = 16;
765 break;
766
767 case 'X':
768 ctx->base = 16;
769 ctx->flags |= FORMAT_UNSIGNED;
770 break;
771
772 case 'f':
773 ctx->base = 2;
775 break;
776
777 case 'F':
778 ctx->base = 2;
780 break;
781
782 case 'e':
783 ctx->base = 2;
785 break;
786
787 case 'E':
788 ctx->base = 2;
790 break;
791
792 case 'g':
793 ctx->base = 2;
795 break;
796
797 case 'G':
798 ctx->base = 2;
800 break;
801
802 case 'a':
803 ctx->base = 2;
805 break;
806
807 case 'A':
808 ctx->base = 2;
809 ctx->flags |= (FORMAT_HEXA | FORMAT_DOUBLE);
810 break;
811
812 case 'c':
813 /* TODO: wide chars. */
814 {
815 char c[1];
816 c[0] = (char)va_arg(ctx->arg, int);
817 ctx->flags |= FORMAT_CHAR;
818 _print_string(c, ctx);
819 return ++spec;
820 }
821
822 case 's':
823 /* TODO: wide chars. */
824 _print_string(va_arg(ctx->arg, char*), ctx);
825 return ++spec;
826
827 case 'p':
828 ctx->base = 16;
830 break;
831
832 case 'n':
833 {
834 int* val = va_arg(ctx->arg, int*);
835 *val = ctx->totalChars;
836 return ++spec;
837 }
838
839 default:
840 /* No conversion specifier. Bad conversion. */
841 return orig_spec;
842 }
843
844 /* Do the actual output based on our findings */
845 if (ctx->base != 0)
846 {
847 /* TODO: Check for invalid flag combinations. */
848 if (ctx->flags & FORMAT_DOUBLE)
849 {
850 /* Floating Point conversions */
851#ifndef __KERNEL__
852 if (ctx->flags & FORMAT_LDOUBLE)
853 {
854 long double value = va_arg(ctx->arg, long double);
855 _print_ldouble(value, ctx);
856 }
857 else
858 {
859 double value = va_arg(ctx->arg, double);
860 _print_double(value, ctx);
861 }
862#endif
863 }
864 else
865 {
866 if (ctx->flags & FORMAT_UNSIGNED)
867 {
868 /* Integer conversions (unsigned) */
869 uintmax_t value;
871
872 switch (ctx->flags &
875 {
876 case FORMAT_CHAR:
877 value = (uintmax_t)(unsigned char)va_arg(ctx->arg, int);
878 break;
879
880 case FORMAT_SHORT:
881 value = (uintmax_t)(unsigned short)va_arg(ctx->arg, int);
882 break;
883
884 case 0:
885 value = (uintmax_t)va_arg(ctx->arg, unsigned int);
886 break;
887
888 case FORMAT_LONG:
889 value = (uintmax_t)va_arg(ctx->arg, unsigned long);
890 break;
891
892 case FORMAT_LLONG:
893 value = (uintmax_t)va_arg(ctx->arg, unsigned long long);
894 break;
895
896 case FORMAT_SIZE:
897 value = (uintmax_t)va_arg(ctx->arg, size_t);
898 break;
899
900 case FORMAT_POINTER:
901 value = (uintmax_t)(uintptr_t)va_arg(ctx->arg, void*);
902 break;
903
904 case FORMAT_INTMAX:
905 value = va_arg(ctx->arg, uintmax_t);
906 break;
907
908 default:
909 // puts("UNSUPPORTED PRINTF FLAG COMBINATION");
910 return NULL;
911 }
912
913 div.quot = value / ctx->base;
914 div.rem = value % ctx->base;
915 _print_integer(div, ctx);
916 }
917 else
918 {
919 /* Integer conversions (signed) */
920 intmax_t value;
921
923 {
924 case FORMAT_CHAR:
925 value = (intmax_t)(char)va_arg(ctx->arg, int);
926 break;
927
928 case FORMAT_SHORT:
929 value = (intmax_t)(short)va_arg(ctx->arg, int);
930 break;
931
932 case 0:
933 value = (intmax_t)va_arg(ctx->arg, int);
934 break;
935
936 case FORMAT_LONG:
937 value = (intmax_t)va_arg(ctx->arg, long);
938 break;
939
940 case FORMAT_LLONG:
941 value = (intmax_t)va_arg(ctx->arg, long long);
942 break;
943
944 case FORMAT_PTRDIFF:
945 value = (intmax_t)va_arg(ctx->arg, ptrdiff_t);
946 break;
947
948 case FORMAT_INTMAX:
949 value = va_arg(ctx->arg, intmax_t);
950 break;
951
952 default:
953 // puts("UNSUPPORTED PRINTF FLAG COMBINATION");
954 return NULL;
955 }
956
957 _print_integer(imaxdiv(value, ctx->base), ctx);
958 }
959 }
960
961 if (ctx->flags & FORMAT_MINUS)
962 {
963 /* Left-aligned filling */
964 while (ctx->currentChars < ctx->width)
965 {
966 _PRINT_PUT(ctx, ' ');
967 ++(ctx->currentChars);
968 }
969 }
970
971 if (ctx->totalChars >= ctx->maxChars && ctx->maxChars > 0)
972 {
973 ctx->buffer[ctx->maxChars - 1] = '\0';
974 }
975 }
976
977 return ++spec;
978}
const char _digits[]
Definition digits.c:3
const char _xdigits[]
Definition digits.c:5
@ FORMAT_DECIMAL
Definition format.h:28
@ FORMAT_INTMAX
Definition format.h:20
@ FORMAT_LOWER
Definition format.h:26
@ FORMAT_DOUBLE
Definition format.h:24
@ FORMAT_SPACE
Definition format.h:12
@ FORMAT_DONE
Definition format.h:14
@ FORMAT_ZERO
Definition format.h:13
@ FORMAT_PLUS
Definition format.h:10
@ FORMAT_SIZE
Definition format.h:21
@ FORMAT_LDOUBLE
Definition format.h:25
@ FORMAT_CHAR
Definition format.h:16
@ FORMAT_UNSIGNED
Definition format.h:27
@ FORMAT_POINTER
Definition format.h:23
@ FORMAT_EXPONENT
Definition format.h:29
@ FORMAT_ALT
Definition format.h:11
@ FORMAT_MINUS
Definition format.h:9
@ FORMAT_SHORT
Definition format.h:17
@ FORMAT_LONG
Definition format.h:18
@ FORMAT_GENERIC
Definition format.h:30
@ FORMAT_HEXA
Definition format.h:31
@ FORMAT_LLONG
Definition format.h:19
@ FORMAT_PTRDIFF
Definition format.h:22
#define NULL
Pointer error value.
Definition NULL.h:23
_PUBLIC imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom)
Definition imaxdiv.c:3
__UINTMAX_TYPE__ uintmax_t
Definition inttypes.h:12
__INTMAX_TYPE__ intmax_t
Definition inttypes.h:11
#define INT_MIN
Definition limits.h:27
#define INT_MAX
Definition limits.h:26
double exp(double x)
static void _print_double(double value, _format_ctx_t *ctx)
Definition print.c:333
static void _print_fp(int sign, int exp, int dec, unsigned char const *mant, size_t mant_dig, _format_ctx_t *ctx)
Definition print.c:270
static void _print_string(const char *s, _format_ctx_t *ctx)
Definition print.c:508
#define _LDBL_EXP(bytes)
Definition print.c:47
#define _LDBL_DEC(bytes)
Definition print.c:46
#define _DBL_EXP(bytes)
Definition print.c:20
static void _print_hexa(int sign, int exp, int dec, unsigned char const *mant, size_t mant_dig, _format_ctx_t *ctx)
Definition print.c:86
#define _LDBL_SIGN(bytes)
Definition print.c:45
#define _DBL_BIAS
Definition print.c:21
#define _DBL_SIGN(bytes)
Definition print.c:18
#define _DBL_MANT_START(bytes)
Definition print.c:22
#define _LDBL_BIAS
Definition print.c:48
#define _PRINT_PUT(ctx, x)
Definition print.c:53
const char * _print(const char *spec, _format_ctx_t *ctx)
Definition print.c:561
static void _print_ldouble(long double value, _format_ctx_t *ctx)
Definition print.c:349
#define _DBL_DEC(bytes)
Definition print.c:19
static void _print_integer(imaxdiv_t div, _format_ctx_t *ctx)
Definition print.c:473
static void _int_format(intmax_t value, _format_ctx_t *ctx)
Definition print.c:367
#define _LDBL_MANT_START(bytes)
Definition print.c:49
__PTRDIFF_TYPE__ ptrdiff_t
Definition ptrdiff_t.h:4
__SIZE_TYPE__ size_t
Definition size_t.h:4
#define va_arg(ap, type)
Definition stdarg.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
#define EOF
Definition stdio.h:25
_PUBLIC div_t div(int numer, int denom)
Definition div.c:3
_PUBLIC int abs(int j)
Definition abs.c:3
#define strtol(nptr, endptr, base)
Definition stdlib.h:27
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
va_list arg
Definition format.h:45
int64_t precision
Definition format.h:43
uint64_t maxChars
Definition format.h:38
uint64_t width
Definition format.h:42
_format_flags_t flags
Definition format.h:37
int32_t base
Definition format.h:36
uint64_t currentChars
Definition format.h:40
char * buffer
Definition format.h:41
uint64_t totalChars
Definition format.h:39
Definition stdlib.h:75
int quot
Definition stdlib.h:76
int rem
Definition stdlib.h:77