revert between 56095 -> 55830 in arch
[AROS.git] / rom / devs / ahci / subr_prf.c
blob6d0132dd83d3e9614e05f77735bce397ba9457aa
1 /*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
39 * $FreeBSD: src/sys/kern/subr_prf.c,v 1.61.2.5 2002/08/31 18:22:08 dwmalone Exp $
40 * $DragonFly: src/sys/kern/subr_prf.c,v 1.21 2008/07/17 23:56:23 dillon Exp $
42 * Modified for use with the AROS AHCI subsystem, 2012/01/03
45 #include <stdarg.h>
46 #include <sys/types.h>
48 #include "ahci.h"
50 typedef unsigned char u_char;
51 typedef unsigned short u_short;
52 typedef unsigned long u_long;
54 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
55 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
57 struct snprintf_arg {
58 char *str;
59 size_t remain;
62 static char *ksprintn (char *nbuf, uintmax_t num, int base, int *lenp,
63 int upper);
64 static void snprintf_func (int ch, void *arg);
67 * Scaled down version of sprintf(3).
69 int
70 ksprintf(char *buf, const char *cfmt, ...)
72 int retval;
73 va_list ap;
75 va_start(ap, cfmt);
76 retval = kvcprintf(cfmt, NULL, (void *)buf, 10, ap);
77 buf[retval] = '\0';
78 va_end(ap);
79 return (retval);
83 * Scaled down version of vsprintf(3).
85 int
86 kvsprintf(char *buf, const char *cfmt, va_list ap)
88 int retval;
90 retval = kvcprintf(cfmt, NULL, (void *)buf, 10, ap);
91 buf[retval] = '\0';
92 return (retval);
96 * Scaled down version of snprintf(3).
98 int
99 ksnprintf(char *str, size_t size, const char *format, ...)
101 int retval;
102 va_list ap;
104 va_start(ap, format);
105 retval = kvsnprintf(str, size, format, ap);
106 va_end(ap);
107 return(retval);
111 * Scaled down version of vsnprintf(3).
114 kvsnprintf(char *str, size_t size, const char *format, va_list ap)
116 struct snprintf_arg info;
117 int retval;
119 info.str = str;
120 info.remain = size;
121 retval = kvcprintf(format, snprintf_func, &info, 10, ap);
122 if (info.remain >= 1)
123 *info.str++ = '\0';
124 return (retval);
128 ksnrprintf(char *str, size_t size, int radix, const char *format, ...)
130 int retval;
131 va_list ap;
133 va_start(ap, format);
134 retval = kvsnrprintf(str, size, radix, format, ap);
135 va_end(ap);
136 return(retval);
140 kvsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
142 struct snprintf_arg info;
143 int retval;
145 info.str = str;
146 info.remain = size;
147 retval = kvcprintf(format, snprintf_func, &info, radix, ap);
148 if (info.remain >= 1)
149 *info.str++ = '\0';
150 return (retval);
154 kvasnrprintf(char **strp, size_t size, int radix,
155 const char *format, va_list ap)
157 struct snprintf_arg info;
158 int retval;
160 *strp = kmalloc(size, M_TEMP, M_WAITOK);
161 info.str = *strp;
162 info.remain = size;
163 retval = kvcprintf(format, snprintf_func, &info, radix, ap);
164 if (info.remain >= 1)
165 *info.str++ = '\0';
166 return (retval);
169 void
170 kvasfree(char **strp)
172 if (*strp) {
173 kfree(*strp, M_TEMP);
174 *strp = NULL;
178 static void
179 snprintf_func(int ch, void *arg)
181 struct snprintf_arg *const info = arg;
183 if (info->remain >= 2) {
184 *info->str++ = ch;
185 info->remain--;
189 static inline char hex2ascii(int n)
191 return "0123456789abcdef"[n & 0xf];
194 static inline int toupper(int c)
196 if (c >= 'a' && c <= 'z')
197 return (c - 'a') + 'A';
199 return c;
203 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
204 * order; return an optional length and a pointer to the last character
205 * written in the buffer (i.e., the first character of the string).
206 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
208 static char *
209 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
211 char *p, c;
213 p = nbuf;
214 *p = '\0';
215 do {
216 c = hex2ascii(num % base);
217 *++p = upper ? toupper(c) : c;
218 } while (num /= base);
219 if (lenp)
220 *lenp = p - nbuf;
221 return (p);
225 * Scaled down version of printf(3).
227 * Two additional formats:
229 * The format %b is supported to decode error registers.
230 * Its usage is:
232 * kprintf("reg=%b\n", regval, "<base><arg>*");
234 * where <base> is the output base expressed as a control character, e.g.
235 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
236 * the first of which gives the bit number to be inspected (origin 1), and
237 * the next characters (up to a control character, i.e. a character <= 32),
238 * give the name of the register. Thus:
240 * kvcprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
242 * would produce output:
244 * reg=3<BITTWO,BITONE>
246 * XXX: %D -- Hexdump, takes pointer and separator string:
247 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
248 * ("%*D", len, ptr, " " -> XX XX XX XX ...
251 #define PCHAR(c) {int cc=(c); if(func) (*func)(cc,arg); else *d++=cc; retval++;}
254 kvcprintf(char const *fmt, void (*func)(int, void*), void *arg,
255 int radix, va_list ap)
257 char nbuf[MAXNBUF];
258 char *d;
259 const char *p, *percent, *q;
260 u_char *up;
261 int ch, n;
262 uintmax_t num;
263 int base, tmp, width, ladjust, sharpflag, neg, sign, dot;
264 int cflag, hflag, jflag, lflag, qflag, tflag, zflag;
265 int dwidth, upper;
266 char padc;
267 int retval = 0, stop = 0;
269 num = 0;
270 if (!func)
271 d = (char *) arg;
272 else
273 d = NULL;
275 if (fmt == NULL)
276 fmt = "(fmt null)\n";
278 if (radix < 2 || radix > 36)
279 radix = 10;
281 for (;;) {
282 padc = ' ';
283 width = 0;
284 while ((ch = (u_char)*fmt++) != '%' || stop) {
285 if (ch == '\0')
286 goto done;
287 PCHAR(ch);
289 percent = fmt - 1;
290 dot = dwidth = ladjust = neg = sharpflag = sign = upper = 0;
291 cflag = hflag = jflag = lflag = qflag = tflag = zflag = 0;
293 reswitch:
294 switch (ch = (u_char)*fmt++) {
295 case '.':
296 dot = 1;
297 goto reswitch;
298 case '#':
299 sharpflag = 1;
300 goto reswitch;
301 case '+':
302 sign = 1;
303 goto reswitch;
304 case '-':
305 ladjust = 1;
306 goto reswitch;
307 case '%':
308 PCHAR(ch);
309 break;
310 case '*':
311 if (!dot) {
312 width = va_arg(ap, int);
313 if (width < 0) {
314 ladjust = !ladjust;
315 width = -width;
317 } else {
318 dwidth = va_arg(ap, int);
320 goto reswitch;
321 case '0':
322 if (!dot) {
323 padc = '0';
324 goto reswitch;
326 case '1': case '2': case '3': case '4':
327 case '5': case '6': case '7': case '8': case '9':
328 for (n = 0;; ++fmt) {
329 n = n * 10 + ch - '0';
330 ch = *fmt;
331 if (ch < '0' || ch > '9')
332 break;
334 if (dot)
335 dwidth = n;
336 else
337 width = n;
338 goto reswitch;
339 case 'b':
340 num = (u_int)va_arg(ap, int);
341 p = va_arg(ap, char *);
342 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
343 PCHAR(*q--);
345 if (num == 0)
346 break;
348 for (tmp = 0; *p;) {
349 n = *p++;
350 if (num & (1 << (n - 1))) {
351 PCHAR(tmp ? ',' : '<');
352 for (; (n = *p) > ' '; ++p)
353 PCHAR(n);
354 tmp = 1;
355 } else
356 for (; *p > ' '; ++p)
357 continue;
359 if (tmp)
360 PCHAR('>');
361 break;
362 case 'c':
363 PCHAR(va_arg(ap, int));
364 break;
365 case 'D':
366 up = va_arg(ap, u_char *);
367 p = va_arg(ap, char *);
368 if (!width)
369 width = 16;
370 while(width--) {
371 PCHAR(hex2ascii(*up >> 4));
372 PCHAR(hex2ascii(*up & 0x0f));
373 up++;
374 if (width)
375 for (q=p;*q;q++)
376 PCHAR(*q);
378 break;
379 case 'd':
380 case 'i':
381 base = 10;
382 sign = 1;
383 goto handle_sign;
384 case 'h':
385 if (hflag) {
386 hflag = 0;
387 cflag = 1;
388 } else
389 hflag = 1;
390 goto reswitch;
391 case 'j':
392 jflag = 1;
393 goto reswitch;
394 case 'l':
395 if (lflag) {
396 lflag = 0;
397 qflag = 1;
398 } else
399 lflag = 1;
400 goto reswitch;
401 case 'n':
402 if (cflag)
403 *(va_arg(ap, char *)) = retval;
404 else if (hflag)
405 *(va_arg(ap, short *)) = retval;
406 else if (jflag)
407 *(va_arg(ap, intmax_t *)) = retval;
408 else if (lflag)
409 *(va_arg(ap, long *)) = retval;
410 else if (qflag)
411 *(va_arg(ap, quad_t *)) = retval;
412 else
413 *(va_arg(ap, int *)) = retval;
414 break;
415 case 'o':
416 base = 8;
417 goto handle_nosign;
418 case 'p':
419 base = 16;
420 sharpflag = (width == 0);
421 sign = 0;
422 num = (uintptr_t)va_arg(ap, void *);
423 goto number;
424 case 'q':
425 qflag = 1;
426 goto reswitch;
427 case 'r':
428 base = radix;
429 if (sign)
430 goto handle_sign;
431 goto handle_nosign;
432 case 's':
433 p = va_arg(ap, char *);
434 if (p == NULL)
435 p = "(null)";
436 if (!dot)
437 n = strlen (p);
438 else
439 for (n = 0; n < dwidth && p[n]; n++)
440 continue;
442 width -= n;
444 if (!ladjust && width > 0)
445 while (width--)
446 PCHAR(padc);
447 while (n--)
448 PCHAR(*p++);
449 if (ladjust && width > 0)
450 while (width--)
451 PCHAR(padc);
452 break;
453 case 't':
454 tflag = 1;
455 goto reswitch;
456 case 'u':
457 base = 10;
458 goto handle_nosign;
459 case 'X':
460 upper = 1;
461 /* FALLTHROUGH */
462 case 'x':
463 base = 16;
464 goto handle_nosign;
465 case 'z':
466 zflag = 1;
467 goto reswitch;
468 handle_nosign:
469 sign = 0;
470 if (cflag)
471 num = (u_char)va_arg(ap, int);
472 else if (hflag)
473 num = (u_short)va_arg(ap, int);
474 else if (jflag)
475 num = va_arg(ap, uintmax_t);
476 else if (lflag)
477 num = va_arg(ap, u_long);
478 else if (qflag)
479 num = va_arg(ap, u_quad_t);
480 else if (tflag)
481 num = va_arg(ap, ptrdiff_t);
482 else if (zflag)
483 num = va_arg(ap, size_t);
484 else
485 num = va_arg(ap, u_int);
486 goto number;
487 handle_sign:
488 if (cflag)
489 num = (char)va_arg(ap, int);
490 else if (hflag)
491 num = (short)va_arg(ap, int);
492 else if (jflag)
493 num = va_arg(ap, intmax_t);
494 else if (lflag)
495 num = va_arg(ap, long);
496 else if (qflag)
497 num = va_arg(ap, quad_t);
498 else if (tflag)
499 num = va_arg(ap, ptrdiff_t);
500 else if (zflag)
501 num = va_arg(ap, ssize_t);
502 else
503 num = va_arg(ap, int);
504 number:
505 if (sign && (intmax_t)num < 0) {
506 neg = 1;
507 num = -(intmax_t)num;
509 p = ksprintn(nbuf, num, base, &tmp, upper);
510 if (sharpflag && num != 0) {
511 if (base == 8)
512 tmp++;
513 else if (base == 16)
514 tmp += 2;
516 if (neg)
517 tmp++;
519 if (!ladjust && padc != '0' && width &&
520 (width -= tmp) > 0) {
521 while (width--)
522 PCHAR(padc);
524 if (neg)
525 PCHAR('-');
526 if (sharpflag && num != 0) {
527 if (base == 8) {
528 PCHAR('0');
529 } else if (base == 16) {
530 PCHAR('0');
531 PCHAR('x');
534 if (!ladjust && width && (width -= tmp) > 0)
535 while (width--)
536 PCHAR(padc);
538 while (*p)
539 PCHAR(*p--);
541 if (ladjust && width && (width -= tmp) > 0)
542 while (width--)
543 PCHAR(padc);
545 break;
546 default:
547 while (percent < fmt)
548 PCHAR(*percent++);
550 * Since we ignore an formatting argument it is no
551 * longer safe to obey the remaining formatting
552 * arguments as the arguments will no longer match
553 * the format specs.
555 stop = 1;
556 break;
559 done:
560 return (retval);
563 #undef PCHAR