mirror of
				https://gitlab.com/qemu-project/qboot.git
				synced 2024-02-13 08:33:40 +08:00 
			
		
		
		
	 f8d4dd2573
			
		
	
	f8d4dd2573
	
	
	
		
			
			printf is avoiding switch statements so that it can be used in very early startup, before jump tables can be read from the F segment. We could use -fno-jump-tables, but we can also keep the if statements and clean them up so that the indentation is fine. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
		
			
				
	
	
		
			254 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "bios.h"
 | |
| #include "stdio.h"
 | |
| #include "string.h"
 | |
| #include "stdlib.h"
 | |
| #include "ioport.h"
 | |
| 
 | |
| typedef struct pstream {
 | |
|     char *buffer;
 | |
|     int remain;
 | |
|     int added;
 | |
| } pstream_t;
 | |
| 
 | |
| typedef struct strprops {
 | |
|     char pad;
 | |
|     int npad;
 | |
| } strprops_t;
 | |
| 
 | |
| static void addchar(pstream_t *p, char c)
 | |
| {
 | |
|     if (p->remain) {
 | |
| 	*p->buffer++ = c;
 | |
| 	--p->remain;
 | |
|     }
 | |
|     ++p->added;
 | |
| }
 | |
| 
 | |
| int puts(const char *c)
 | |
| {
 | |
|     int n = 0;
 | |
|     while (c[n])
 | |
|         outb(0x3f8, c[n++]);
 | |
|     return n;
 | |
| }
 | |
| 
 | |
| void print_str(pstream_t *p, const char *s, strprops_t props)
 | |
| {
 | |
|     const char *s_orig = s;
 | |
|     int npad = props.npad;
 | |
| 
 | |
|     if (npad > 0) {
 | |
| 	npad -= strlen(s_orig);
 | |
| 	while (npad > 0) {
 | |
| 	    addchar(p, props.pad);
 | |
| 	    --npad;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     while (*s)
 | |
| 	addchar(p, *s++);
 | |
| 
 | |
|     if (npad < 0) {
 | |
| 	props.pad = ' '; /* ignore '0' flag with '-' flag */
 | |
| 	npad += strlen(s_orig);
 | |
| 	while (npad < 0) {
 | |
| 	    addchar(p, props.pad);
 | |
| 	    ++npad;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| static char digits[16] = "0123456789abcdef";
 | |
| 
 | |
| void print_int(pstream_t *ps, long n, int base, strprops_t props)
 | |
| {
 | |
|     char buf[sizeof(long) * 3 + 2], *p = buf;
 | |
|     int s = 0, i;
 | |
| 
 | |
|     if (n < 0) {
 | |
| 	n = -n;
 | |
| 	s = 1;
 | |
|     }
 | |
| 
 | |
|     while (n) {
 | |
| 	*p++ = digits[n % base];
 | |
| 	n /= base;
 | |
|     }
 | |
| 
 | |
|     if (s)
 | |
| 	*p++ = '-';
 | |
| 
 | |
|     if (p == buf)
 | |
| 	*p++ = '0';
 | |
| 
 | |
|     for (i = 0; i < (p - buf) / 2; ++i) {
 | |
| 	char tmp;
 | |
| 
 | |
| 	tmp = buf[i];
 | |
| 	buf[i] = p[-1-i];
 | |
| 	p[-1-i] = tmp;
 | |
|     }
 | |
| 
 | |
|     *p = 0;
 | |
| 
 | |
|     print_str(ps, buf, props);
 | |
| }
 | |
| 
 | |
| void print_unsigned(pstream_t *ps, unsigned long n, int base,
 | |
| 		    strprops_t props)
 | |
| {
 | |
|     char buf[sizeof(long) * 3 + 1], *p = buf;
 | |
|     int i;
 | |
| 
 | |
|     while (n) {
 | |
| 	*p++ = digits[n % base];
 | |
| 	n /= base;
 | |
|     }
 | |
| 
 | |
|     if (p == buf)
 | |
| 	*p++ = '0';
 | |
| 
 | |
|     for (i = 0; i < (p - buf) / 2; ++i) {
 | |
| 	char tmp;
 | |
| 
 | |
| 	tmp = buf[i];
 | |
| 	buf[i] = p[-1-i];
 | |
| 	p[-1-i] = tmp;
 | |
|     }
 | |
| 
 | |
|     *p = 0;
 | |
| 
 | |
|     print_str(ps, buf, props);
 | |
| }
 | |
| 
 | |
| static int fmtnum(const char **fmt)
 | |
| {
 | |
|     const char *f = *fmt;
 | |
|     int len = 0, num;
 | |
| 
 | |
|     if (*f == '-')
 | |
| 	++f, ++len;
 | |
| 
 | |
|     while (*f >= '0' && *f <= '9')
 | |
| 	++f, ++len;
 | |
| 
 | |
|     num = atol(*fmt);
 | |
|     *fmt += len;
 | |
|     return num;
 | |
| }
 | |
| 
 | |
| int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 | |
| {
 | |
|     pstream_t s;
 | |
| 
 | |
|     s.buffer = buf;
 | |
|     s.remain = size - 1;
 | |
|     s.added = 0;
 | |
|     while (*fmt) {
 | |
| 	char f = *fmt++;
 | |
| 	int nlong = 0;
 | |
| 	strprops_t props;
 | |
| 	memset(&props, 0, sizeof(props));
 | |
| 	props.pad = ' ';
 | |
| 
 | |
| 	if (f != '%') {
 | |
| 	    addchar(&s, f);
 | |
| 	    continue;
 | |
| 	}
 | |
|     morefmt:
 | |
| 	f = *fmt++;
 | |
| 	if (f == '%') {
 | |
| 	    addchar(&s, '%');
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == 'c') {
 | |
|             addchar(&s, va_arg(va, int));
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == '\0') {
 | |
| 	    --fmt;
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == '0') {
 | |
| 	    props.pad = '0';
 | |
| 	    ++fmt;
 | |
| 	    /* fall through */
 | |
| 	}
 | |
| 	if ((f >= '1' && f <= '9') || f == '-') {
 | |
| 	    --fmt;
 | |
| 	    props.npad = fmtnum(&fmt);
 | |
| 	    goto morefmt;
 | |
| 	}
 | |
| 	if (f == 'l') {
 | |
| 	    ++nlong;
 | |
| 	    goto morefmt;
 | |
| 	}
 | |
| 	if (f == 'd') {
 | |
| 	    switch (nlong) {
 | |
| 	    case 0:
 | |
| 		print_int(&s, va_arg(va, int), 10, props);
 | |
| 		break;
 | |
| 	    case 1:
 | |
| 		print_int(&s, va_arg(va, long), 10, props);
 | |
| 		break;
 | |
| 	    default:
 | |
| 		panic();
 | |
| 		break;
 | |
| 	    }
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == 'x') {
 | |
| 	    switch (nlong) {
 | |
| 	    case 0:
 | |
| 		print_unsigned(&s, va_arg(va, unsigned), 16, props);
 | |
| 		break;
 | |
| 	    case 1:
 | |
| 		print_unsigned(&s, va_arg(va, unsigned long), 16, props);
 | |
| 		break;
 | |
| 	    default:
 | |
| 		panic();
 | |
| 		break;
 | |
| 	    }
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == 'p') {
 | |
| 	    print_str(&s, "0x", props);
 | |
| 	    print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
 | |
| 	    continue;
 | |
| 	}
 | |
| 	if (f == 's') {
 | |
| 	    print_str(&s, va_arg(va, const char *), props);
 | |
| 	    continue;
 | |
| 	}
 | |
|         addchar(&s, f);
 | |
|     }
 | |
|     *s.buffer = 0;
 | |
|     ++s.added;
 | |
|     return s.added;
 | |
| }
 | |
| 
 | |
| 
 | |
| int snprintf(char *buf, int size, const char *fmt, ...)
 | |
| {
 | |
|     va_list va;
 | |
|     int r;
 | |
| 
 | |
|     va_start(va, fmt);
 | |
|     r = vsnprintf(buf, size, fmt, va);
 | |
|     va_end(va);
 | |
|     return r;
 | |
| }
 | |
| 
 | |
| int printf(const char *fmt, ...)
 | |
| {
 | |
|     va_list va;
 | |
|     char buf[2000];
 | |
|     int r;
 | |
| 
 | |
|     va_start(va, fmt);
 | |
|     r = vsnprintf(buf, sizeof buf, fmt, va);
 | |
|     va_end(va);
 | |
|     puts(buf);
 | |
|     return r;
 | |
| }
 |