1 /* adapted from http://www.efgh.com/software/gprintf.htm */
11 #define BITS_PER_BYTE 8
13 #define F_THOUSANDS 0x1
14 #define F_LEFTJUSTIFY 0x2
17 #define F_ALTERNATE 0x10
18 #define F_ZEROPAD 0x20
19 #define F_CAPITAL 0x40
20 /* F_PRECISION set if precision specified in format */
21 #define F_PRECISION 0x80
24 static unsigned char digits[17] = "01234567890abcdef";
25 static unsigned char capdigits[17] = "01234567890ABCDEF";
29 int n; /* number of output chars */
36 int (*output_function)(void *, int);
39 char buf[BITS_PER_BYTE * sizeof(uintmax_t) + 1];
42 static int strlenk(char *s) {
50 static void output(struct parameters *p, char *s) {
51 int justify = p->width - p->len;
58 if (justify && p->flags & F_ZEROPAD) {
62 if (justify && !(p->flags & F_LEFTJUSTIFY)) {
70 terminal.putchar(*s++);
74 while (justify-- > 0) {
75 terminal.putchar(' ');
80 static inline int get_decimal(const char *str, int *val) {
92 while (digit = *str++) {
93 if (digit >= '0' && digit <= '9') {
108 int printk(const char *fmt, ...) {
112 n = printkv(fmt, ap);
117 int printkv(const char *fmt, va_list ap) {
118 struct parameters p = { 0 };
119 struct parameters z = { 0 };
123 while (fc = *fmt++) {
125 terminal.putchar(fc);
131 /* it's a conversion, get flags */
138 /* this is an error though */
142 p.flags |= F_ALTERNATE;
145 p.flags |= F_ZEROPAD;
148 p.flags |= F_LEFTJUSTIFY;
154 p.flags |= F_USESIGN;
156 /* posix, not C, so maybe need a define */
158 p.flags |= F_THOUSANDS;
167 /* get minimum field width */
168 if (fc >= '1' && fc <= '9') {
169 fmt += get_decimal(fmt, &p.width);
170 } else if (*fmt == '*') {
172 if (*fmt >= '1' && *fmt <= '9') {
174 fmt += get_decimal(fmt, &lenarg);
178 fmt++; /* skip past the $ */
180 p.width = va_arg(ap, int);
183 p.flags |= F_LEFTJUSTIFY;
192 p.flags |= F_PRECISION;
194 if (fc >= '0' && fc <= '9') {
195 fmt += get_decimal(fmt, &p.width);
196 } else if (*fmt == '*') {
198 if (*fmt >= '1' && *fmt <= '9') {
200 fmt += get_decimal(fmt, &arg);
204 fmt++; /* skip past the $ */
206 p.precision = va_arg(ap, int);
207 if (p.precision < 0) {
209 p.flags &= ~F_PRECISION;
215 /* get length modifier */
241 /* conversion specifier */
252 unsigned long long ull;
259 terminal.putchar('%');
264 if (p.modifier == 'l') {
265 /* wide int wint_t */
268 arg.i = va_arg(ap, int);
269 p.buf[0] = (unsigned char) arg.i;
275 p.str = va_arg(ap, char *);
276 /* TODO may not be properly terminated if precision is given */
277 p.len = strlenk(p.str);
278 /* precision, if given, is maximum characters
279 * for an 's' conversion */
280 if (p.flags & F_PRECISION && p.len > p.precision) {
283 /* TODO don't zero pad strings */
288 p.flags |= F_CAPITAL;
295 switch (p.modifier) {
297 arg.u = va_arg(ap, unsigned int);
298 i = (uintmax_t) (unsigned char) arg.uc;
301 arg.u = va_arg(ap, unsigned int);
302 i = (uintmax_t) (unsigned short) arg.us;
305 arg.ul = va_arg(ap, unsigned long);
306 i = (uintmax_t) arg.ul;
309 arg.ull = va_arg(ap, unsigned long long);
310 i = (uintmax_t) arg.ull;
313 i = va_arg(ap, uintmax_t);
316 arg.size = va_arg(ap, size_t);
317 i = (uintmax_t) arg.size;
320 arg.pd = va_arg(ap, ptrdiff_t);
321 i = (uintmax_t) arg.pd;
324 arg.u = va_arg(ap, unsigned);
325 i = (uintmax_t) arg.u;
328 p.str = p.buf + sizeof(p.buf) - 1;
335 if (p.flags & F_CAPITAL)
342 } while ( i /= base);
353 /* output number here ? */
356 terminal.update_cursor();