UbixOS V2 2.0

kprintf.c
Go to the documentation of this file.
1 /*-
2 * Copyright (c) 2002-2018 The UbixOS Project.
3 * All rights reserved.
4 *
5 * This was developed by Christopher W. Olsen for the UbixOS Project.
6 *
7 * Redistribution and use in source and binary forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1) Redistributions of source code must retain the above copyright notice, this list of
11 * conditions, the following disclaimer and the list of authors.
12 * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
13 * conditions, the following disclaimer and the list of authors in the documentation and/or
14 * other materials provided with the distribution.
15 * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
16 * endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <lib/kprintf.h>
30 #include <string.h>
31 #include <sys/video.h>
32 #include <ubixos/kpanic.h>
33
34 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper);
35
36 static __inline int imax(int a, int b) {
37 return (a > b ? a : b);
38 }
39
40 union uu {
41 quad_t q; /* as a (signed) quad */
42 quad_t uq; /* as an unsigned quad */
43 long sl[2]; /* as two signed longs */
44 u_long ul[2]; /* as two unsigned longs */
45 };
46
47 static void __shl(register digit *p, register int len, register int sh) {
48 register int i;
49
50 for (i = 0; i < len; i++)
51 p[i] = LHALF( p[i] << sh ) | (p[i + 1] >> (HALF_BITS - sh));
52
53 p[i] = LHALF(p[i] << sh);
54 }
55
56 u_quad_t __qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq) {
57 union uu tmp;
58 digit *u, *v, *q;
59 register digit v1, v2;
60 u_long qhat, rhat, t;
61 int m, n, d, j, i;
62 digit uspace[5], vspace[5], qspace[5];
63
64 /*
65 * Take care of special cases: divide by zero, and u < v.
66 */
67 if (vq == 0) {
68 /* divide by zero. */
69 static const volatile unsigned int zero = 0;
70
71 tmp.ul[H] = tmp.ul[L] = 1 / zero;
72 if (arq)
73 *arq = uq;
74 return (tmp.q);
75 }
76 if (uq < vq) {
77 if (arq)
78 *arq = uq;
79 return (0);
80 }
81 u = &uspace[0];
82 v = &vspace[0];
83 q = &qspace[0];
84
85 /*
86 * Break dividend and divisor into digits in base B, then
87 * count leading zeros to determine m and n. When done, we
88 * will have:
89 * u = (u[1]u[2]...u[m+n]) sub B
90 * v = (v[1]v[2]...v[n]) sub B
91 * v[1] != 0
92 * 1 < n <= 4 (if n = 1, we use a different division algorithm)
93 * m >= 0 (otherwise u < v, which we already checked)
94 * m + n = 4
95 * and thus
96 * m = 4 - n <= 2
97 */
98 tmp.uq = uq;
99 u[0] = 0;
100 u[1] = HHALF(tmp.ul[H]);
101 u[2] = LHALF(tmp.ul[H]);
102 u[3] = HHALF(tmp.ul[L]);
103 u[4] = LHALF(tmp.ul[L]);
104 tmp.uq = vq;
105 v[1] = HHALF(tmp.ul[H]);
106 v[2] = LHALF(tmp.ul[H]);
107 v[3] = HHALF(tmp.ul[L]);
108 v[4] = LHALF(tmp.ul[L]);
109 for (n = 4; v[1] == 0; v++) {
110 if (--n == 1) {
111 u_long rbj; /* r*B+u[j] (not root boy jim) */
112 digit q1, q2, q3, q4;
113
114 /*
115 * Change of plan, per exercise 16.
116 * r = 0;
117 * for j = 1..4:
118 * q[j] = floor((r*B + u[j]) / v),
119 * r = (r*B + u[j]) % v;
120 * We unroll this completely here.
121 */
122 t = v[2]; /* nonzero, by definition */
123 q1 = u[1] / t;
124 rbj = COMBINE(u[1] % t, u[2]);
125 q2 = rbj / t;
126 rbj = COMBINE(rbj % t, u[3]);
127 q3 = rbj / t;
128 rbj = COMBINE(rbj % t, u[4]);
129 q4 = rbj / t;
130 if (arq)
131 *arq = rbj % t;
132 tmp.ul[H] = COMBINE(q1, q2);
133 tmp.ul[L] = COMBINE(q3, q4);
134 return (tmp.q);
135 }
136 }
137 /*
138 * By adjusting q once we determine m, we can guarantee that
139 * there is a complete four-digit quotient at &qspace[1] when
140 * we finally stop.
141 */
142 for (m = 4 - n; u[1] == 0; u++)
143 m--;
144 for (i = 4 - m; --i >= 0;)
145 q[i] = 0;
146 q += 4 - m;
147
148 /*
149 * Here we run Program D, translated from MIX to C and acquiring
150 * a few minor changes.
151 *
152 * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
153 */
154 d = 0;
155 for (t = v[1]; t < B / 2; t <<= 1)
156 d++;
157 if (d > 0) {
158 __shl(&u[0], m + n, d); /* u <<= d */
159 __shl(&v[1], n - 1, d); /* v <<= d */
160 }
161 /*
162 * D2: j = 0.
163 */
164 j = 0;
165 v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
166 v2 = v[2]; /* for D3 */
167 do {
168 register digit uj0, uj1, uj2;
169
170 /*
171 * D3: Calculate qhat (\^q, in TeX notation).
172 * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
173 * let rhat = (u[j]*B + u[j+1]) mod v[1].
174 * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
175 * decrement qhat and increase rhat correspondingly.
176 * Note that if rhat >= B, v[2]*qhat < rhat*B.
177 */
178 uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
179 uj1 = u[j + 1]; /* for D3 only */
180 uj2 = u[j + 2]; /* for D3 only */
181 if (uj0 == v1) {
182 qhat = B;
183 rhat = uj1;
184 goto qhat_too_big;
185 }
186 else {
187 u_long nn = COMBINE(uj0, uj1);
188 qhat = nn / v1;
189 rhat = nn % v1;
190 }
191 while (v2 * qhat > COMBINE(rhat, uj2)) {
192 qhat_too_big: qhat--;
193 if ((rhat += v1) >= B)
194 break;
195 }
196 /*
197 * D4: Multiply and subtract.
198 * The variable `t' holds any borrows across the loop.
199 * We split this up so that we do not require v[0] = 0,
200 * and to eliminate a final special case.
201 */
202 for (t = 0, i = n; i > 0; i--) {
203 t = u[i + j] - v[i] * qhat - t;
204 u[i + j] = LHALF(t);
205 t = (B - HHALF(t)) & (B - 1);
206 }
207 t = u[j] - t;
208 u[j] = LHALF(t);
209 /*
210 * D5: test remainder.
211 * There is a borrow if and only if HHALF(t) is nonzero;
212 * in that (rare) case, qhat was too large (by exactly 1).
213 * Fix it by adding v[1..n] to u[j..j+n].
214 */
215 if (HHALF(t)) {
216 qhat--;
217 for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
218 t += u[i + j] + v[i];
219 u[i + j] = LHALF(t);
220 t = HHALF(t);
221 }
222 u[j] = LHALF(u[j] + t);
223 }
224 q[j] = qhat;
225 } while (++j <= m); /* D7: loop on j. */
226
227 /*
228 * If caller wants the remainder, we have to calculate it as
229 * u[m..m+n] >> d (this is at most n digits and thus fits in
230 * u[m+1..m+n], but we may need more source digits).
231 */
232 if (arq) {
233 if (d) {
234 for (i = m + n; i > m; --i)
235 u[i] = (u[i] >> d) | LHALF(u[i - 1] << (HALF_BITS - d));
236 u[i] = 0;
237 }
238 tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
239 tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
240 *arq = tmp.q;
241 }
242
243 tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
244 tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
245 return (tmp.q);
246 }
247
248 u_quad_t __umoddi3(a, b)
249 u_quad_t a, b; {
250 u_quad_t r;
251
252 (void) __qdivrem(a, b, &r);
253 return (r);
254 }
255
256 int printOff = 0x0;
257 int ogprintOff = 0x1;
258
259 int kprintf(const char *fmt, ...) {
260 va_list ap;
261 int retval;
262 char buf[512];
263
264 va_start(ap, fmt);
265
266 retval = kvprintf(fmt, NULL, &buf, 10, ap);
267 buf[retval] = '\0';
268 va_end(ap);
269
270 if (printOff == 0x0)
271 kprint(buf);
272 if (ogprintOff == 0x0)
273 ogPrintf(buf);
274
275 return (retval);
276 }
277
278 int sprintf(char *buf, const char *fmt, ...) {
279 va_list args;
280 int i;
281 va_start(args, fmt);
282 /* i = vsprintf( buf, fmt, args ); */
283 i = kvprintf(fmt, NULL, buf, 10, args);
284 va_end(args);
285 return (i);
286 }
287
288 /*
289 * Scaled down version of printf(3).
290 *
291 * Two additional formats:
292 *
293 * The format %b is supported to decode error registers.
294 * Its usage is:
295 *
296 * printf("reg=%b\n", regval, "<base><arg>*");
297 *
298 * where <base> is the output base expressed as a control character, e.g.
299 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
300 * the first of which gives the bit number to be inspected (origin 1), and
301 * the next characters (up to a control character, i.e. a character <= 32),
302 * give the name of the register. Thus:
303 *
304 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
305 *
306 * would produce output:
307 *
308 * reg=3<BITTWO,BITONE>
309 *
310 * XXX: %D -- Hexdump, takes pointer and separator string:
311 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
312 * ("%*D", len, ptr, " " -> XX XX XX XX ...
313 */
314
315 int kvprintf(const char *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) {
316 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
317 char nbuf[MAXNBUF];
318 char *d;
319 const char *p, *percent, *q;
320 u_char *up;
321 int ch, n;
322 uintmax_t num;
323 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
324 int cflag, hflag, jflag, tflag, zflag;
325 int dwidth, upper;
326 char padc;
327 int stop = 0, retval = 0;
328
329 num = 0;
330 if (!func)
331 d = (char *) arg;
332 else
333 d = NULL;
334
335 if (fmt == NULL)
336 fmt = "(fmt null)\n";
337
338 if (radix < 2 || radix > 36)
339 radix = 10;
340
341 for (;;) {
342 padc = ' ';
343 width = 0;
344 while ((ch = (u_char) *fmt++) != '%' || stop) {
345 if (ch == '\0')
346 return (retval);
347 PCHAR(ch);
348 }
349 percent = fmt - 1;
350 qflag = 0;
351 lflag = 0;
352 ladjust = 0;
353 sharpflag = 0;
354 neg = 0;
355 sign = 0;
356 dot = 0;
357 dwidth = 0;
358 upper = 0;
359 cflag = 0;
360 hflag = 0;
361 jflag = 0;
362 tflag = 0;
363 zflag = 0;
364 reswitch: switch (ch = (u_char) *fmt++) {
365 case '.':
366 dot = 1;
367 goto reswitch;
368 case '#':
369 sharpflag = 1;
370 goto reswitch;
371 case '+':
372 sign = 1;
373 goto reswitch;
374 case '-':
375 ladjust = 1;
376 goto reswitch;
377 case '%':
378 PCHAR(ch)
379 ;
380 break;
381 case '*':
382 if (!dot) {
383 width = va_arg(ap, int);
384 if (width < 0) {
385 ladjust = !ladjust;
386 width = -width;
387 }
388 }
389 else {
390 dwidth = va_arg(ap, int);
391 }
392 goto reswitch;
393 case '0':
394 if (!dot) {
395 padc = '0';
396 goto reswitch;
397 }
398 case '1':
399 case '2':
400 case '3':
401 case '4':
402 case '5':
403 case '6':
404 case '7':
405 case '8':
406 case '9':
407 for (n = 0;; ++fmt) {
408 n = n * 10 + ch - '0';
409 ch = *fmt;
410 if (ch < '0' || ch > '9')
411 break;
412 }
413 if (dot)
414 dwidth = n;
415 else
416 width = n;
417 goto reswitch;
418 case 'b':
419 num = (u_int) va_arg(ap, int);
420 p = va_arg(ap, char *);
421 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
422 PCHAR(*q--)
423 ;
424
425 if (num == 0)
426 break;
427
428 for (tmp = 0; *p;) {
429 n = *p++;
430 if (num & (1 << (n - 1))) {
431 PCHAR(tmp ? ',' : '<');
432 for (; (n = *p) > ' '; ++p)
433 PCHAR(n);
434 tmp = 1;
435 }
436 else
437 for (; *p > ' '; ++p)
438 continue;
439 }
440 if (tmp)
441 PCHAR('>')
442 ;
443 break;
444 case 'c':
445 PCHAR(va_arg(ap, int))
446 ;
447 break;
448 case 'D':
449 up = va_arg(ap, u_char *);
450 p = va_arg(ap, char *);
451 if (!width)
452 width = 16;
453 while (width--) {
454 PCHAR(hex2ascii( *up >> 4 ));
455 PCHAR(hex2ascii( *up & 0x0f ));
456 up++;
457 if (width)
458 for (q = p; *q; q++)
459 PCHAR(*q);
460 }
461 break;
462 case 'd':
463 case 'i':
464 base = 10;
465 sign = 1;
466 goto handle_sign;
467 case 'h':
468 if (hflag) {
469 hflag = 0;
470 cflag = 1;
471 }
472 else
473 hflag = 1;
474 goto reswitch;
475 case 'j':
476 jflag = 1;
477 goto reswitch;
478 case 'l':
479 if (lflag) {
480 lflag = 0;
481 qflag = 1;
482 }
483 else
484 lflag = 1;
485 goto reswitch;
486 case 'n':
487 if (jflag)
488 *(va_arg(ap, intmax_t *)) = retval;
489 else if (qflag)
490 *(va_arg(ap, quad_t *)) = retval;
491 else if (lflag)
492 *(va_arg(ap, long *)) = retval;
493 else if (zflag)
494 *(va_arg(ap, size_t *)) = retval;
495 else if (hflag)
496 *(va_arg(ap, short *)) = retval;
497 else if (cflag)
498 *(va_arg(ap, char *)) = retval;
499 else
500 *(va_arg(ap, int *)) = retval;
501 break;
502 case 'o':
503 base = 8;
504 goto handle_nosign;
505 case 'p':
506 base = 16;
507 sharpflag = (width == 0);
508 sign = 0;
509 num = (uintptr_t) va_arg(ap, void *);
510 goto number;
511 case 'q':
512 qflag = 1;
513 goto reswitch;
514 case 'r':
515 base = radix;
516 if (sign)
517 goto handle_sign;
518 goto handle_nosign;
519 case 's':
520 p = va_arg(ap, char *);
521 if (p == NULL)
522 p = "(null)";
523 if (!dot)
524 n = strlen(p);
525 else
526 for (n = 0; n < dwidth && p[n]; n++)
527 continue;
528
529 width -= n;
530
531 if (!ladjust && width > 0)
532 while (width--)
533 PCHAR(padc)
534 ;
535 while (n--)
536 PCHAR(*p++)
537 ;
538 if (ladjust && width > 0)
539 while (width--)
540 PCHAR(padc)
541 ;
542 break;
543 case 't':
544 tflag = 1;
545 goto reswitch;
546 case 'u':
547 base = 10;
548 goto handle_nosign;
549 case 'X':
550 upper = 1;
551 case 'x':
552 base = 16;
553 goto handle_nosign;
554 case 'y':
555 base = 16;
556 sign = 1;
557 goto handle_sign;
558 case 'z':
559 zflag = 1;
560 goto reswitch;
561 handle_nosign: sign = 0;
562 if (jflag)
563 num = va_arg(ap, uintmax_t);
564 else if (qflag)
565 num = va_arg(ap, u_quad_t);
566 else if (tflag)
567 num = va_arg(ap, ptrdiff_t);
568 else if (lflag)
569 num = va_arg(ap, u_long);
570 else if (zflag)
571 num = va_arg(ap, size_t);
572 else if (hflag)
573 num = (u_short) va_arg(ap, int);
574 else if (cflag)
575 num = (u_char) va_arg(ap, int);
576 else
577 num = va_arg(ap, u_int);
578 goto number;
579 handle_sign: if (jflag)
580 num = va_arg(ap, intmax_t);
581 else if (qflag)
582 num = va_arg(ap, quad_t);
583 else if (tflag)
584 num = va_arg(ap, ptrdiff_t);
585 else if (lflag)
586 num = va_arg(ap, long);
587 else if (zflag)
588 num = va_arg(ap, ssize_t);
589 else if (hflag)
590 num = (short) va_arg(ap, int);
591 else if (cflag)
592 num = (char) va_arg(ap, int);
593 else
594 num = va_arg(ap, int);
595 number: if (sign && (intmax_t) num < 0) {
596 neg = 1;
597 num = -(intmax_t) num;
598 }
599 p = ksprintn(nbuf, num, base, &n, upper);
600 tmp = 0;
601 if (sharpflag && num != 0) {
602 if (base == 8)
603 tmp++;
604 else if (base == 16)
605 tmp += 2;
606 }
607 if (neg)
608 tmp++;
609
610 if (!ladjust && padc == '0')
611 dwidth = width - tmp;
612 width -= tmp + imax(dwidth, n);
613 dwidth -= n;
614 if (!ladjust)
615 while (width-- > 0)
616 PCHAR(' ')
617 ;
618 if (neg)
619 PCHAR('-')
620 ;
621 if (sharpflag && num != 0) {
622 if (base == 8) {
623 PCHAR('0');
624 }
625 else if (base == 16) {
626 PCHAR('0');
627 PCHAR('x');
628 }
629 }
630 while (dwidth-- > 0)
631 PCHAR('0')
632 ;
633
634 while (*p)
635 PCHAR(*p--)
636 ;
637
638 if (ladjust)
639 while (width-- > 0)
640 PCHAR(' ')
641 ;
642
643 break;
644 default:
645 while (percent < fmt)
646 PCHAR(*percent++)
647 ;
648 /*
649 * Since we ignore a formatting argument it is no
650 * longer safe to obey the remaining formatting
651 * arguments as the arguments will no longer match
652 * the format specs.
653 */
654 stop = 1;
655 break;
656 }
657 }
658 #undef PCHAR
659 return (0);
660 }
661
662 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) {
663 char *p, c;
664
665 p = nbuf;
666 *p = '\0';
667
668 do {
669 c = hex2ascii(num % base);
670 *++p = upper ? toupper(c) : c;
671 } while (num /= base);
672
673 if (lenp)
674 *lenp = p - nbuf;
675
676 return (p);
677 }
678
679 /***
680 END
681 ***/
682
u_long
unsigned long u_long
Definition: types.h:73
uu::uq
quad_t uq
Definition: kprintf.c:42
uu::sl
long sl[2]
Definition: kprintf.c:43
MAXNBUF
#define MAXNBUF
Definition: kprintf.h:35
uu::ul
u_long ul[2]
Definition: kprintf.c:44
LHALF
#define LHALF(x)
Definition: types.h:164
__inline
#define __inline
Definition: cdefs.h:179
uu
Definition: kprintf.c:40
string.h
u_quad_t
__uint64_t u_quad_t
Definition: types.h:55
video.h
va_end
#define va_end(ap)
Definition: stdarg.h:50
sprintf
int sprintf(char *buf, const char *fmt,...)
Definition: kprintf.c:278
strlen
int strlen(const char *str)
Definition: strlen.c:55
B
#define B
Definition: types.h:169
va_list
char * va_list
Definition: stdarg.h:32
intmax_t
int32_t intmax_t
Definition: types.h:134
quad_t
__int64_t quad_t
Definition: types.h:57
u_short
unsigned short u_short
Definition: types.h:71
PCHAR
#define PCHAR(c)
kpanic.h
COMBINE
#define COMBINE(a, b)
Definition: types.h:172
va_start
#define va_start(ap, last)
Definition: stdarg.h:41
__qdivrem
u_quad_t __qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq)
Definition: kprintf.c:56
kprintf.h
kprintf
int kprintf(const char *fmt,...)
Definition: kprintf.c:259
buf
Definition: buf.h:35
HALF_BITS
#define HALF_BITS
Definition: types.h:162
__umoddi3
u_quad_t __umoddi3(u_quad_t a, u_quad_t b)
Definition: kprintf.c:248
H
#define H
Definition: types.h:154
digit
unsigned short digit
Definition: types.h:146
ptrdiff_t
int32_t ptrdiff_t
Definition: types.h:135
ogPrintf
int ogPrintf(char *)
Definition: ogprintf.cc:40
kvprintf
int kvprintf(const char *fmt, void(*func)(int, void *), void *arg, int radix, va_list ap)
Definition: kprintf.c:315
uintmax_t
uint32_t uintmax_t
Definition: types.h:133
hex2ascii
#define hex2ascii(hex)
Definition: string.h:53
printOff
int printOff
Definition: kprintf.c:256
toupper
#define toupper(c)
Definition: string.h:55
L
#define L
Definition: types.h:155
va_arg
#define va_arg(ap, type)
Definition: stdarg.h:44
uintptr_t
uint32_t uintptr_t
Definition: types.h:136
HHALF
#define HHALF(x)
Definition: types.h:163
ssize_t
__ssize_t ssize_t
Definition: types.h:117
u_int
unsigned int u_int
Definition: types.h:72
u_char
unsigned char u_char
Definition: types.h:70
uu::q
quad_t q
Definition: kprintf.c:41
kprint
void kprint(char *string)
Definition: video.c:58
ogprintOff
int ogprintOff
Definition: kprintf.c:257
NULL
#define NULL
Definition: fat_string.h:17