ia64/xen-unstable

view extras/mini-os/lib/printf.c @ 18811:390ef36eb596

Remove Xen-private definitions from kexec public header.

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