ia64/xen-unstable

view extras/mini-os/lib/printf.c @ 12244:665a28dffb7d

[XEND] Don't hide the 'type' SXP config item from HVM guests

Should allow network devices to properly initialised in HVM guests.

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Fri Nov 03 11:42:57 2006 +0000 (2006-11-03)
parents b049fb947f2a
children 19f549449cb5
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 #if !defined HAVE_LIBC
59 #include <os.h>
60 #include <types.h>
61 #include <hypervisor.h>
62 #include <lib.h>
63 #include <mm.h>
64 #include <ctype.h>
66 /**
67 * simple_strtoul - convert a string to an unsigned long
68 * @cp: The start of the string
69 * @endp: A pointer to the end of the parsed string will be placed here
70 * @base: The number base to use
71 */
72 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
73 {
74 unsigned long result = 0,value;
76 if (!base) {
77 base = 10;
78 if (*cp == '0') {
79 base = 8;
80 cp++;
81 if ((*cp == 'x') && isxdigit(cp[1])) {
82 cp++;
83 base = 16;
84 }
85 }
86 }
87 while (isxdigit(*cp) &&
88 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
89 result = result*base + value;
90 cp++;
91 }
92 if (endp)
93 *endp = (char *)cp;
94 return result;
95 }
97 /**
98 * simple_strtol - convert a string to a signed long
99 * @cp: The start of the string
100 * @endp: A pointer to the end of the parsed string will be placed here
101 * @base: The number base to use
102 */
103 long simple_strtol(const char *cp,char **endp,unsigned int base)
104 {
105 if(*cp=='-')
106 return -simple_strtoul(cp+1,endp,base);
107 return simple_strtoul(cp,endp,base);
108 }
110 /**
111 * simple_strtoull - convert a string to an unsigned long long
112 * @cp: The start of the string
113 * @endp: A pointer to the end of the parsed string will be placed here
114 * @base: The number base to use
115 */
116 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
117 {
118 unsigned long long result = 0,value;
120 if (!base) {
121 base = 10;
122 if (*cp == '0') {
123 base = 8;
124 cp++;
125 if ((*cp == 'x') && isxdigit(cp[1])) {
126 cp++;
127 base = 16;
128 }
129 }
130 }
131 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
132 ? toupper(*cp) : *cp)-'A'+10) < base) {
133 result = result*base + value;
134 cp++;
135 }
136 if (endp)
137 *endp = (char *)cp;
138 return result;
139 }
141 /**
142 * simple_strtoll - convert a string to a signed long long
143 * @cp: The start of the string
144 * @endp: A pointer to the end of the parsed string will be placed here
145 * @base: The number base to use
146 */
147 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
148 {
149 if(*cp=='-')
150 return -simple_strtoull(cp+1,endp,base);
151 return simple_strtoull(cp,endp,base);
152 }
154 static int skip_atoi(const char **s)
155 {
156 int i=0;
158 while (isdigit(**s))
159 i = i*10 + *((*s)++) - '0';
160 return i;
161 }
163 #define ZEROPAD 1 /* pad with zero */
164 #define SIGN 2 /* unsigned/signed long */
165 #define PLUS 4 /* show plus */
166 #define SPACE 8 /* space if plus */
167 #define LEFT 16 /* left justified */
168 #define SPECIAL 32 /* 0x */
169 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
171 static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
172 {
173 char c,sign,tmp[66];
174 const char *digits;
175 const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
176 const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
177 int i;
179 digits = (type & LARGE) ? large_digits : small_digits;
180 if (type & LEFT)
181 type &= ~ZEROPAD;
182 if (base < 2 || base > 36)
183 return buf;
184 c = (type & ZEROPAD) ? '0' : ' ';
185 sign = 0;
186 if (type & SIGN) {
187 if (num < 0) {
188 sign = '-';
189 num = -num;
190 size--;
191 } else if (type & PLUS) {
192 sign = '+';
193 size--;
194 } else if (type & SPACE) {
195 sign = ' ';
196 size--;
197 }
198 }
199 if (type & SPECIAL) {
200 if (base == 16)
201 size -= 2;
202 else if (base == 8)
203 size--;
204 }
205 i = 0;
206 if (num == 0)
207 tmp[i++]='0';
208 else
209 {
210 /* XXX KAF: force unsigned mod and div. */
211 unsigned long long num2=(unsigned long long)num;
212 unsigned int base2=(unsigned int)base;
213 while (num2 != 0) { tmp[i++] = digits[num2%base2]; num2 /= base2; }
214 }
215 if (i > precision)
216 precision = i;
217 size -= precision;
218 if (!(type&(ZEROPAD+LEFT))) {
219 while(size-->0) {
220 if (buf <= end)
221 *buf = ' ';
222 ++buf;
223 }
224 }
225 if (sign) {
226 if (buf <= end)
227 *buf = sign;
228 ++buf;
229 }
230 if (type & SPECIAL) {
231 if (base==8) {
232 if (buf <= end)
233 *buf = '0';
234 ++buf;
235 } else if (base==16) {
236 if (buf <= end)
237 *buf = '0';
238 ++buf;
239 if (buf <= end)
240 *buf = digits[33];
241 ++buf;
242 }
243 }
244 if (!(type & LEFT)) {
245 while (size-- > 0) {
246 if (buf <= end)
247 *buf = c;
248 ++buf;
249 }
250 }
251 while (i < precision--) {
252 if (buf <= end)
253 *buf = '0';
254 ++buf;
255 }
256 while (i-- > 0) {
257 if (buf <= end)
258 *buf = tmp[i];
259 ++buf;
260 }
261 while (size-- > 0) {
262 if (buf <= end)
263 *buf = ' ';
264 ++buf;
265 }
266 return buf;
267 }
269 /**
270 * vsnprintf - Format a string and place it in a buffer
271 * @buf: The buffer to place the result into
272 * @size: The size of the buffer, including the trailing null space
273 * @fmt: The format string to use
274 * @args: Arguments for the format string
275 *
276 * Call this function if you are already dealing with a va_list.
277 * You probably want snprintf instead.
278 */
279 int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
280 {
281 int len;
282 unsigned long long num;
283 int i, base;
284 char *str, *end, c;
285 const char *s;
287 int flags; /* flags to number() */
289 int field_width; /* width of output field */
290 int precision; /* min. # of digits for integers; max
291 number of chars for from string */
292 int qualifier; /* 'h', 'l', or 'L' for integer fields */
293 /* 'z' support added 23/7/1999 S.H. */
294 /* 'z' changed to 'Z' --davidm 1/25/99 */
296 str = buf;
297 end = buf + size - 1;
299 if (end < buf - 1) {
300 end = ((void *) -1);
301 size = end - buf + 1;
302 }
304 for (; *fmt ; ++fmt) {
305 if (*fmt != '%') {
306 if (str <= end)
307 *str = *fmt;
308 ++str;
309 continue;
310 }
312 /* process flags */
313 flags = 0;
314 repeat:
315 ++fmt; /* this also skips first '%' */
316 switch (*fmt) {
317 case '-': flags |= LEFT; goto repeat;
318 case '+': flags |= PLUS; goto repeat;
319 case ' ': flags |= SPACE; goto repeat;
320 case '#': flags |= SPECIAL; goto repeat;
321 case '0': flags |= ZEROPAD; goto repeat;
322 }
324 /* get field width */
325 field_width = -1;
326 if (isdigit(*fmt))
327 field_width = skip_atoi(&fmt);
328 else if (*fmt == '*') {
329 ++fmt;
330 /* it's the next argument */
331 field_width = va_arg(args, int);
332 if (field_width < 0) {
333 field_width = -field_width;
334 flags |= LEFT;
335 }
336 }
338 /* get the precision */
339 precision = -1;
340 if (*fmt == '.') {
341 ++fmt;
342 if (isdigit(*fmt))
343 precision = skip_atoi(&fmt);
344 else if (*fmt == '*') {
345 ++fmt;
346 /* it's the next argument */
347 precision = va_arg(args, int);
348 }
349 if (precision < 0)
350 precision = 0;
351 }
353 /* get the conversion qualifier */
354 qualifier = -1;
355 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
356 qualifier = *fmt;
357 ++fmt;
358 if (qualifier == 'l' && *fmt == 'l') {
359 qualifier = 'L';
360 ++fmt;
361 }
362 }
363 if (*fmt == 'q') {
364 qualifier = 'L';
365 ++fmt;
366 }
368 /* default base */
369 base = 10;
371 switch (*fmt) {
372 case 'c':
373 if (!(flags & LEFT)) {
374 while (--field_width > 0) {
375 if (str <= end)
376 *str = ' ';
377 ++str;
378 }
379 }
380 c = (unsigned char) va_arg(args, int);
381 if (str <= end)
382 *str = c;
383 ++str;
384 while (--field_width > 0) {
385 if (str <= end)
386 *str = ' ';
387 ++str;
388 }
389 continue;
391 case 's':
392 s = va_arg(args, char *);
393 if (!s)
394 s = "<NULL>";
396 len = strnlen(s, precision);
398 if (!(flags & LEFT)) {
399 while (len < field_width--) {
400 if (str <= end)
401 *str = ' ';
402 ++str;
403 }
404 }
405 for (i = 0; i < len; ++i) {
406 if (str <= end)
407 *str = *s;
408 ++str; ++s;
409 }
410 while (len < field_width--) {
411 if (str <= end)
412 *str = ' ';
413 ++str;
414 }
415 continue;
417 case 'p':
418 if (field_width == -1) {
419 field_width = 2*sizeof(void *);
420 flags |= ZEROPAD;
421 }
422 str = number(str, end,
423 (unsigned long) va_arg(args, void *),
424 16, field_width, precision, flags);
425 continue;
428 case 'n':
429 /* FIXME:
430 * What does C99 say about the overflow case here? */
431 if (qualifier == 'l') {
432 long * ip = va_arg(args, long *);
433 *ip = (str - buf);
434 } else if (qualifier == 'Z') {
435 size_t * ip = va_arg(args, size_t *);
436 *ip = (str - buf);
437 } else {
438 int * ip = va_arg(args, int *);
439 *ip = (str - buf);
440 }
441 continue;
443 case '%':
444 if (str <= end)
445 *str = '%';
446 ++str;
447 continue;
449 /* integer number formats - set up the flags and "break" */
450 case 'o':
451 base = 8;
452 break;
454 case 'X':
455 flags |= LARGE;
456 case 'x':
457 base = 16;
458 break;
460 case 'd':
461 case 'i':
462 flags |= SIGN;
463 case 'u':
464 break;
466 default:
467 if (str <= end)
468 *str = '%';
469 ++str;
470 if (*fmt) {
471 if (str <= end)
472 *str = *fmt;
473 ++str;
474 } else {
475 --fmt;
476 }
477 continue;
478 }
479 if (qualifier == 'L')
480 num = va_arg(args, long long);
481 else if (qualifier == 'l') {
482 num = va_arg(args, unsigned long);
483 if (flags & SIGN)
484 num = (signed long) num;
485 } else if (qualifier == 'Z') {
486 num = va_arg(args, size_t);
487 } else if (qualifier == 'h') {
488 num = (unsigned short) va_arg(args, int);
489 if (flags & SIGN)
490 num = (signed short) num;
491 } else {
492 num = va_arg(args, unsigned int);
493 if (flags & SIGN)
494 num = (signed int) num;
495 }
497 str = number(str, end, num, base,
498 field_width, precision, flags);
499 }
500 if (str <= end)
501 *str = '\0';
502 else if (size > 0)
503 /* don't write out a null byte if the buf size is zero */
504 *end = '\0';
505 /* the trailing null byte doesn't count towards the total
506 * ++str;
507 */
508 return str-buf;
509 }
511 /**
512 * snprintf - Format a string and place it in a buffer
513 * @buf: The buffer to place the result into
514 * @size: The size of the buffer, including the trailing null space
515 * @fmt: The format string to use
516 * @...: Arguments for the format string
517 */
518 int snprintf(char * buf, size_t size, const char *fmt, ...)
519 {
520 va_list args;
521 int i;
523 va_start(args, fmt);
524 i=vsnprintf(buf,size,fmt,args);
525 va_end(args);
526 return i;
527 }
529 /**
530 * vsprintf - Format a string and place it in a buffer
531 * @buf: The buffer to place the result into
532 * @fmt: The format string to use
533 * @args: Arguments for the format string
534 *
535 * Call this function if you are already dealing with a va_list.
536 * You probably want sprintf instead.
537 */
538 int vsprintf(char *buf, const char *fmt, va_list args)
539 {
540 return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
541 }
544 /**
545 * sprintf - Format a string and place it in a buffer
546 * @buf: The buffer to place the result into
547 * @fmt: The format string to use
548 * @...: Arguments for the format string
549 */
550 int sprintf(char * buf, const char *fmt, ...)
551 {
552 va_list args;
553 int i;
555 va_start(args, fmt);
556 i=vsprintf(buf,fmt,args);
557 va_end(args);
558 return i;
559 }
561 /**
562 * vsscanf - Unformat a buffer into a list of arguments
563 * @buf: input buffer
564 * @fmt: format of buffer
565 * @args: arguments
566 */
567 int vsscanf(const char * buf, const char * fmt, va_list args)
568 {
569 const char *str = buf;
570 char *next;
571 char digit;
572 int num = 0;
573 int qualifier;
574 int base;
575 int field_width;
576 int is_sign = 0;
578 while(*fmt && *str) {
579 /* skip any white space in format */
580 /* white space in format matchs any amount of
581 * white space, including none, in the input.
582 */
583 if (isspace(*fmt)) {
584 while (isspace(*fmt))
585 ++fmt;
586 while (isspace(*str))
587 ++str;
588 }
590 /* anything that is not a conversion must match exactly */
591 if (*fmt != '%' && *fmt) {
592 if (*fmt++ != *str++)
593 break;
594 continue;
595 }
597 if (!*fmt)
598 break;
599 ++fmt;
601 /* skip this conversion.
602 * advance both strings to next white space
603 */
604 if (*fmt == '*') {
605 while (!isspace(*fmt) && *fmt)
606 fmt++;
607 while (!isspace(*str) && *str)
608 str++;
609 continue;
610 }
612 /* get field width */
613 field_width = -1;
614 if (isdigit(*fmt))
615 field_width = skip_atoi(&fmt);
617 /* get conversion qualifier */
618 qualifier = -1;
619 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
620 *fmt == 'Z' || *fmt == 'z') {
621 qualifier = *fmt++;
622 if (unlikely(qualifier == *fmt)) {
623 if (qualifier == 'h') {
624 qualifier = 'H';
625 fmt++;
626 } else if (qualifier == 'l') {
627 qualifier = 'L';
628 fmt++;
629 }
630 }
631 }
632 base = 10;
633 is_sign = 0;
635 if (!*fmt || !*str)
636 break;
638 switch(*fmt++) {
639 case 'c':
640 {
641 char *s = (char *) va_arg(args,char*);
642 if (field_width == -1)
643 field_width = 1;
644 do {
645 *s++ = *str++;
646 } while (--field_width > 0 && *str);
647 num++;
648 }
649 continue;
650 case 's':
651 {
652 char *s = (char *) va_arg(args, char *);
653 if(field_width == -1)
654 field_width = INT_MAX;
655 /* first, skip leading white space in buffer */
656 while (isspace(*str))
657 str++;
659 /* now copy until next white space */
660 while (*str && !isspace(*str) && field_width--) {
661 *s++ = *str++;
662 }
663 *s = '\0';
664 num++;
665 }
666 continue;
667 case 'n':
668 /* return number of characters read so far */
669 {
670 int *i = (int *)va_arg(args,int*);
671 *i = str - buf;
672 }
673 continue;
674 case 'o':
675 base = 8;
676 break;
677 case 'x':
678 case 'X':
679 base = 16;
680 break;
681 case 'i':
682 base = 0;
683 case 'd':
684 is_sign = 1;
685 case 'u':
686 break;
687 case '%':
688 /* looking for '%' in str */
689 if (*str++ != '%')
690 return num;
691 continue;
692 default:
693 /* invalid format; stop here */
694 return num;
695 }
697 /* have some sort of integer conversion.
698 * first, skip white space in buffer.
699 */
700 while (isspace(*str))
701 str++;
703 digit = *str;
704 if (is_sign && digit == '-')
705 digit = *(str + 1);
707 if (!digit
708 || (base == 16 && !isxdigit(digit))
709 || (base == 10 && !isdigit(digit))
710 || (base == 8 && (!isdigit(digit) || digit > '7'))
711 || (base == 0 && !isdigit(digit)))
712 break;
714 switch(qualifier) {
715 case 'H': /* that's 'hh' in format */
716 if (is_sign) {
717 signed char *s = (signed char *) va_arg(args,signed char *);
718 *s = (signed char) simple_strtol(str,&next,base);
719 } else {
720 unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
721 *s = (unsigned char) simple_strtoul(str, &next, base);
722 }
723 break;
724 case 'h':
725 if (is_sign) {
726 short *s = (short *) va_arg(args,short *);
727 *s = (short) simple_strtol(str,&next,base);
728 } else {
729 unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
730 *s = (unsigned short) simple_strtoul(str, &next, base);
731 }
732 break;
733 case 'l':
734 if (is_sign) {
735 long *l = (long *) va_arg(args,long *);
736 *l = simple_strtol(str,&next,base);
737 } else {
738 unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
739 *l = simple_strtoul(str,&next,base);
740 }
741 break;
742 case 'L':
743 if (is_sign) {
744 long long *l = (long long*) va_arg(args,long long *);
745 *l = simple_strtoll(str,&next,base);
746 } else {
747 unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
748 *l = simple_strtoull(str,&next,base);
749 }
750 break;
751 case 'Z':
752 case 'z':
753 {
754 size_t *s = (size_t*) va_arg(args,size_t*);
755 *s = (size_t) simple_strtoul(str,&next,base);
756 }
757 break;
758 default:
759 if (is_sign) {
760 int *i = (int *) va_arg(args, int*);
761 *i = (int) simple_strtol(str,&next,base);
762 } else {
763 unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
764 *i = (unsigned int) simple_strtoul(str,&next,base);
765 }
766 break;
767 }
768 num++;
770 if (!next)
771 break;
772 str = next;
773 }
774 return num;
775 }
777 /**
778 * sscanf - Unformat a buffer into a list of arguments
779 * @buf: input buffer
780 * @fmt: formatting of buffer
781 * @...: resulting arguments
782 */
783 int sscanf(const char * buf, const char * fmt, ...)
784 {
785 va_list args;
786 int i;
788 va_start(args,fmt);
789 i = vsscanf(buf,fmt,args);
790 va_end(args);
791 return i;
792 }
794 #endif