ia64/xen-unstable

view extras/mini-os/lib/printf.c @ 6806:4ad19fe76d50

Store dom0 store ring-ref in store.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:32:38 2005 +0000 (2005-09-13)
parents cdfa7dd00c44
children b2f4823b6ff0 b35215021b32 9af349b055e5 3233e7ecfa9f
line source
1 /*
2 ****************************************************************************
3 * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
4 ****************************************************************************
5 *
6 * File: printf.c
7 * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
8 * Changes: Grzegorz Milos (gm281@cam.ac.uk)
9 *
10 * Date: Aug 2003, Aug 2005
11 *
12 * Environment: Xen Minimal OS
13 * Description: Library functions for printing
14 * (freebsd port, mainly sys/subr_prf.c)
15 *
16 ****************************************************************************
17 *
18 *-
19 * Copyright (c) 1992, 1993
20 * The Regents of the University of California. All rights reserved.
21 *
22 * This software was developed by the Computer Systems Engineering group
23 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
24 * contributed to Berkeley.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
55 */
57 #include <os.h>
58 #include <types.h>
59 #include <hypervisor.h>
60 #include <lib.h>
61 #include <mm.h>
62 #include <ctype.h>
64 /**
65 * simple_strtoul - convert a string to an unsigned long
66 * @cp: The start of the string
67 * @endp: A pointer to the end of the parsed string will be placed here
68 * @base: The number base to use
69 */
70 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
71 {
72 unsigned long result = 0,value;
74 if (!base) {
75 base = 10;
76 if (*cp == '0') {
77 base = 8;
78 cp++;
79 if ((*cp == 'x') && isxdigit(cp[1])) {
80 cp++;
81 base = 16;
82 }
83 }
84 }
85 while (isxdigit(*cp) &&
86 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
87 result = result*base + value;
88 cp++;
89 }
90 if (endp)
91 *endp = (char *)cp;
92 return result;
93 }
95 /**
96 * simple_strtol - convert a string to a signed long
97 * @cp: The start of the string
98 * @endp: A pointer to the end of the parsed string will be placed here
99 * @base: The number base to use
100 */
101 long simple_strtol(const char *cp,char **endp,unsigned int base)
102 {
103 if(*cp=='-')
104 return -simple_strtoul(cp+1,endp,base);
105 return simple_strtoul(cp,endp,base);
106 }
108 /**
109 * simple_strtoull - convert a string to an unsigned long long
110 * @cp: The start of the string
111 * @endp: A pointer to the end of the parsed string will be placed here
112 * @base: The number base to use
113 */
114 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
115 {
116 unsigned long long result = 0,value;
118 if (!base) {
119 base = 10;
120 if (*cp == '0') {
121 base = 8;
122 cp++;
123 if ((*cp == 'x') && isxdigit(cp[1])) {
124 cp++;
125 base = 16;
126 }
127 }
128 }
129 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
130 ? toupper(*cp) : *cp)-'A'+10) < base) {
131 result = result*base + value;
132 cp++;
133 }
134 if (endp)
135 *endp = (char *)cp;
136 return result;
137 }
139 /**
140 * simple_strtoll - convert a string to a signed long long
141 * @cp: The start of the string
142 * @endp: A pointer to the end of the parsed string will be placed here
143 * @base: The number base to use
144 */
145 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
146 {
147 if(*cp=='-')
148 return -simple_strtoull(cp+1,endp,base);
149 return simple_strtoull(cp,endp,base);
150 }
152 static int skip_atoi(const char **s)
153 {
154 int i=0;
156 while (isdigit(**s))
157 i = i*10 + *((*s)++) - '0';
158 return i;
159 }
161 #define ZEROPAD 1 /* pad with zero */
162 #define SIGN 2 /* unsigned/signed long */
163 #define PLUS 4 /* show plus */
164 #define SPACE 8 /* space if plus */
165 #define LEFT 16 /* left justified */
166 #define SPECIAL 32 /* 0x */
167 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
169 static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
170 {
171 char c,sign,tmp[66];
172 const char *digits;
173 const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
174 const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
175 int i;
177 digits = (type & LARGE) ? large_digits : small_digits;
178 if (type & LEFT)
179 type &= ~ZEROPAD;
180 if (base < 2 || base > 36)
181 return buf;
182 c = (type & ZEROPAD) ? '0' : ' ';
183 sign = 0;
184 if (type & SIGN) {
185 if (num < 0) {
186 sign = '-';
187 num = -num;
188 size--;
189 } else if (type & PLUS) {
190 sign = '+';
191 size--;
192 } else if (type & SPACE) {
193 sign = ' ';
194 size--;
195 }
196 }
197 if (type & SPECIAL) {
198 if (base == 16)
199 size -= 2;
200 else if (base == 8)
201 size--;
202 }
203 i = 0;
204 if (num == 0)
205 tmp[i++]='0';
206 else
207 {
208 /* XXX KAF: force unsigned mod and div. */
209 unsigned long long num2=(unsigned long long)num;
210 unsigned int base2=(unsigned int)base;
211 while (num2 != 0) { tmp[i++] = digits[num2%base2]; num2 /= base2; }
212 }
213 if (i > precision)
214 precision = i;
215 size -= precision;
216 if (!(type&(ZEROPAD+LEFT))) {
217 while(size-->0) {
218 if (buf <= end)
219 *buf = ' ';
220 ++buf;
221 }
222 }
223 if (sign) {
224 if (buf <= end)
225 *buf = sign;
226 ++buf;
227 }
228 if (type & SPECIAL) {
229 if (base==8) {
230 if (buf <= end)
231 *buf = '0';
232 ++buf;
233 } else if (base==16) {
234 if (buf <= end)
235 *buf = '0';
236 ++buf;
237 if (buf <= end)
238 *buf = digits[33];
239 ++buf;
240 }
241 }
242 if (!(type & LEFT)) {
243 while (size-- > 0) {
244 if (buf <= end)
245 *buf = c;
246 ++buf;
247 }
248 }
249 while (i < precision--) {
250 if (buf <= end)
251 *buf = '0';
252 ++buf;
253 }
254 while (i-- > 0) {
255 if (buf <= end)
256 *buf = tmp[i];
257 ++buf;
258 }
259 while (size-- > 0) {
260 if (buf <= end)
261 *buf = ' ';
262 ++buf;
263 }
264 return buf;
265 }
267 /**
268 * vsnprintf - Format a string and place it in a buffer
269 * @buf: The buffer to place the result into
270 * @size: The size of the buffer, including the trailing null space
271 * @fmt: The format string to use
272 * @args: Arguments for the format string
273 *
274 * Call this function if you are already dealing with a va_list.
275 * You probably want snprintf instead.
276 */
277 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
278 {
279 int len;
280 unsigned long long num;
281 int i, base;
282 char *str, *end, c;
283 const char *s;
285 int flags; /* flags to number() */
287 int field_width; /* width of output field */
288 int precision; /* min. # of digits for integers; max
289 number of chars for from string */
290 int qualifier; /* 'h', 'l', or 'L' for integer fields */
291 /* 'z' support added 23/7/1999 S.H. */
292 /* 'z' changed to 'Z' --davidm 1/25/99 */
294 str = buf;
295 end = buf + size - 1;
297 if (end < buf - 1) {
298 end = ((void *) -1);
299 size = end - buf + 1;
300 }
302 for (; *fmt ; ++fmt) {
303 if (*fmt != '%') {
304 if (str <= end)
305 *str = *fmt;
306 ++str;
307 continue;
308 }
310 /* process flags */
311 flags = 0;
312 repeat:
313 ++fmt; /* this also skips first '%' */
314 switch (*fmt) {
315 case '-': flags |= LEFT; goto repeat;
316 case '+': flags |= PLUS; goto repeat;
317 case ' ': flags |= SPACE; goto repeat;
318 case '#': flags |= SPECIAL; goto repeat;
319 case '0': flags |= ZEROPAD; goto repeat;
320 }
322 /* get field width */
323 field_width = -1;
324 if (isdigit(*fmt))
325 field_width = skip_atoi(&fmt);
326 else if (*fmt == '*') {
327 ++fmt;
328 /* it's the next argument */
329 field_width = va_arg(args, int);
330 if (field_width < 0) {
331 field_width = -field_width;
332 flags |= LEFT;
333 }
334 }
336 /* get the precision */
337 precision = -1;
338 if (*fmt == '.') {
339 ++fmt;
340 if (isdigit(*fmt))
341 precision = skip_atoi(&fmt);
342 else if (*fmt == '*') {
343 ++fmt;
344 /* it's the next argument */
345 precision = va_arg(args, int);
346 }
347 if (precision < 0)
348 precision = 0;
349 }
351 /* get the conversion qualifier */
352 qualifier = -1;
353 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
354 qualifier = *fmt;
355 ++fmt;
356 if (qualifier == 'l' && *fmt == 'l') {
357 qualifier = 'L';
358 ++fmt;
359 }
360 }
361 if (*fmt == 'q') {
362 qualifier = 'L';
363 ++fmt;
364 }
366 /* default base */
367 base = 10;
369 switch (*fmt) {
370 case 'c':
371 if (!(flags & LEFT)) {
372 while (--field_width > 0) {
373 if (str <= end)
374 *str = ' ';
375 ++str;
376 }
377 }
378 c = (unsigned char) va_arg(args, int);
379 if (str <= end)
380 *str = c;
381 ++str;
382 while (--field_width > 0) {
383 if (str <= end)
384 *str = ' ';
385 ++str;
386 }
387 continue;
389 case 's':
390 s = va_arg(args, char *);
391 if (!s)
392 s = "<NULL>";
394 len = strnlen(s, precision);
396 if (!(flags & LEFT)) {
397 while (len < field_width--) {
398 if (str <= end)
399 *str = ' ';
400 ++str;
401 }
402 }
403 for (i = 0; i < len; ++i) {
404 if (str <= end)
405 *str = *s;
406 ++str; ++s;
407 }
408 while (len < field_width--) {
409 if (str <= end)
410 *str = ' ';
411 ++str;
412 }
413 continue;
415 case 'p':
416 if (field_width == -1) {
417 field_width = 2*sizeof(void *);
418 flags |= ZEROPAD;
419 }
420 str = number(str, end,
421 (unsigned long) va_arg(args, void *),
422 16, field_width, precision, flags);
423 continue;
426 case 'n':
427 /* FIXME:
428 * What does C99 say about the overflow case here? */
429 if (qualifier == 'l') {
430 long * ip = va_arg(args, long *);
431 *ip = (str - buf);
432 } else if (qualifier == 'Z') {
433 size_t * ip = va_arg(args, size_t *);
434 *ip = (str - buf);
435 } else {
436 int * ip = va_arg(args, int *);
437 *ip = (str - buf);
438 }
439 continue;
441 case '%':
442 if (str <= end)
443 *str = '%';
444 ++str;
445 continue;
447 /* integer number formats - set up the flags and "break" */
448 case 'o':
449 base = 8;
450 break;
452 case 'X':
453 flags |= LARGE;
454 case 'x':
455 base = 16;
456 break;
458 case 'd':
459 case 'i':
460 flags |= SIGN;
461 case 'u':
462 break;
464 default:
465 if (str <= end)
466 *str = '%';
467 ++str;
468 if (*fmt) {
469 if (str <= end)
470 *str = *fmt;
471 ++str;
472 } else {
473 --fmt;
474 }
475 continue;
476 }
477 if (qualifier == 'L')
478 num = va_arg(args, long long);
479 else if (qualifier == 'l') {
480 num = va_arg(args, unsigned long);
481 if (flags & SIGN)
482 num = (signed long) num;
483 } else if (qualifier == 'Z') {
484 num = va_arg(args, size_t);
485 } else if (qualifier == 'h') {
486 num = (unsigned short) va_arg(args, int);
487 if (flags & SIGN)
488 num = (signed short) num;
489 } else {
490 num = va_arg(args, unsigned int);
491 if (flags & SIGN)
492 num = (signed int) num;
493 }
495 str = number(str, end, num, base,
496 field_width, precision, flags);
497 }
498 if (str <= end)
499 *str = '\0';
500 else if (size > 0)
501 /* don't write out a null byte if the buf size is zero */
502 *end = '\0';
503 /* the trailing null byte doesn't count towards the total
504 * ++str;
505 */
506 return str-buf;
507 }
509 /**
510 * snprintf - Format a string and place it in a buffer
511 * @buf: The buffer to place the result into
512 * @size: The size of the buffer, including the trailing null space
513 * @fmt: The format string to use
514 * @...: Arguments for the format string
515 */
516 int snprintf(char * buf, size_t size, const char *fmt, ...)
517 {
518 va_list args;
519 int i;
521 va_start(args, fmt);
522 i=vsnprintf(buf,size,fmt,args);
523 va_end(args);
524 return i;
525 }
527 /**
528 * vsprintf - Format a string and place it in a buffer
529 * @buf: The buffer to place the result into
530 * @fmt: The format string to use
531 * @args: Arguments for the format string
532 *
533 * Call this function if you are already dealing with a va_list.
534 * You probably want sprintf instead.
535 */
536 int vsprintf(char *buf, const char *fmt, va_list args)
537 {
538 return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
539 }
542 /**
543 * sprintf - Format a string and place it in a buffer
544 * @buf: The buffer to place the result into
545 * @fmt: The format string to use
546 * @...: Arguments for the format string
547 */
548 int sprintf(char * buf, const char *fmt, ...)
549 {
550 va_list args;
551 int i;
553 va_start(args, fmt);
554 i=vsprintf(buf,fmt,args);
555 va_end(args);
556 return i;
557 }
560 void printf(const char *fmt, ...)
561 {
562 static char buf[1024];
563 va_list args;
565 va_start(args, fmt);
566 (void)vsnprintf(buf, sizeof(buf), fmt, args);
567 va_end(args);
569 (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf);
570 }
572 /**
573 * vsscanf - Unformat a buffer into a list of arguments
574 * @buf: input buffer
575 * @fmt: format of buffer
576 * @args: arguments
577 */
578 int vsscanf(const char * buf, const char * fmt, va_list args)
579 {
580 const char *str = buf;
581 char *next;
582 char digit;
583 int num = 0;
584 int qualifier;
585 int base;
586 int field_width;
587 int is_sign = 0;
589 while(*fmt && *str) {
590 /* skip any white space in format */
591 /* white space in format matchs any amount of
592 * white space, including none, in the input.
593 */
594 if (isspace(*fmt)) {
595 while (isspace(*fmt))
596 ++fmt;
597 while (isspace(*str))
598 ++str;
599 }
601 /* anything that is not a conversion must match exactly */
602 if (*fmt != '%' && *fmt) {
603 if (*fmt++ != *str++)
604 break;
605 continue;
606 }
608 if (!*fmt)
609 break;
610 ++fmt;
612 /* skip this conversion.
613 * advance both strings to next white space
614 */
615 if (*fmt == '*') {
616 while (!isspace(*fmt) && *fmt)
617 fmt++;
618 while (!isspace(*str) && *str)
619 str++;
620 continue;
621 }
623 /* get field width */
624 field_width = -1;
625 if (isdigit(*fmt))
626 field_width = skip_atoi(&fmt);
628 /* get conversion qualifier */
629 qualifier = -1;
630 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
631 *fmt == 'Z' || *fmt == 'z') {
632 qualifier = *fmt++;
633 if (unlikely(qualifier == *fmt)) {
634 if (qualifier == 'h') {
635 qualifier = 'H';
636 fmt++;
637 } else if (qualifier == 'l') {
638 qualifier = 'L';
639 fmt++;
640 }
641 }
642 }
643 base = 10;
644 is_sign = 0;
646 if (!*fmt || !*str)
647 break;
649 switch(*fmt++) {
650 case 'c':
651 {
652 char *s = (char *) va_arg(args,char*);
653 if (field_width == -1)
654 field_width = 1;
655 do {
656 *s++ = *str++;
657 } while (--field_width > 0 && *str);
658 num++;
659 }
660 continue;
661 case 's':
662 {
663 char *s = (char *) va_arg(args, char *);
664 if(field_width == -1)
665 field_width = INT_MAX;
666 /* first, skip leading white space in buffer */
667 while (isspace(*str))
668 str++;
670 /* now copy until next white space */
671 while (*str && !isspace(*str) && field_width--) {
672 *s++ = *str++;
673 }
674 *s = '\0';
675 num++;
676 }
677 continue;
678 case 'n':
679 /* return number of characters read so far */
680 {
681 int *i = (int *)va_arg(args,int*);
682 *i = str - buf;
683 }
684 continue;
685 case 'o':
686 base = 8;
687 break;
688 case 'x':
689 case 'X':
690 base = 16;
691 break;
692 case 'i':
693 base = 0;
694 case 'd':
695 is_sign = 1;
696 case 'u':
697 break;
698 case '%':
699 /* looking for '%' in str */
700 if (*str++ != '%')
701 return num;
702 continue;
703 default:
704 /* invalid format; stop here */
705 return num;
706 }
708 /* have some sort of integer conversion.
709 * first, skip white space in buffer.
710 */
711 while (isspace(*str))
712 str++;
714 digit = *str;
715 if (is_sign && digit == '-')
716 digit = *(str + 1);
718 if (!digit
719 || (base == 16 && !isxdigit(digit))
720 || (base == 10 && !isdigit(digit))
721 || (base == 8 && (!isdigit(digit) || digit > '7'))
722 || (base == 0 && !isdigit(digit)))
723 break;
725 switch(qualifier) {
726 case 'H': /* that's 'hh' in format */
727 if (is_sign) {
728 signed char *s = (signed char *) va_arg(args,signed char *);
729 *s = (signed char) simple_strtol(str,&next,base);
730 } else {
731 unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
732 *s = (unsigned char) simple_strtoul(str, &next, base);
733 }
734 break;
735 case 'h':
736 if (is_sign) {
737 short *s = (short *) va_arg(args,short *);
738 *s = (short) simple_strtol(str,&next,base);
739 } else {
740 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
741 *s = (unsigned short) simple_strtoul(str, &next, base);
742 }
743 break;
744 case 'l':
745 if (is_sign) {
746 long *l = (long *) va_arg(args,long *);
747 *l = simple_strtol(str,&next,base);
748 } else {
749 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
750 *l = simple_strtoul(str,&next,base);
751 }
752 break;
753 case 'L':
754 if (is_sign) {
755 long long *l = (long long*) va_arg(args,long long *);
756 *l = simple_strtoll(str,&next,base);
757 } else {
758 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
759 *l = simple_strtoull(str,&next,base);
760 }
761 break;
762 case 'Z':
763 case 'z':
764 {
765 size_t *s = (size_t*) va_arg(args,size_t*);
766 *s = (size_t) simple_strtoul(str,&next,base);
767 }
768 break;
769 default:
770 if (is_sign) {
771 int *i = (int *) va_arg(args, int*);
772 *i = (int) simple_strtol(str,&next,base);
773 } else {
774 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
775 *i = (unsigned int) simple_strtoul(str,&next,base);
776 }
777 break;
778 }
779 num++;
781 if (!next)
782 break;
783 str = next;
784 }
785 return num;
786 }
788 /**
789 * sscanf - Unformat a buffer into a list of arguments
790 * @buf: input buffer
791 * @fmt: formatting of buffer
792 * @...: resulting arguments
793 */
794 int sscanf(const char * buf, const char * fmt, ...)
795 {
796 va_list args;
797 int i;
799 va_start(args,fmt);
800 i = vsscanf(buf,fmt,args);
801 va_end(args);
802 return i;
803 }