|  | @@ -1,213 +1,322 @@
 | 
		
	
		
			
			|  | 1 | +#include <stddef.h>
 | 
		
	
		
			
			| 1 | 2 |  #include <stdarg.h>
 | 
		
	
		
			
			| 2 |  | -#include <gpxe/if_ether.h> /* for ETH_ALEN */
 | 
		
	
		
			
			| 3 |  | -#include "limits.h" /* for CHAR_BIT */
 | 
		
	
		
			
			| 4 |  | -#include "console.h"
 | 
		
	
		
			
			| 5 |  | -#include "errno.h"
 | 
		
	
		
			
			| 6 |  | -#include "vsprintf.h"
 | 
		
	
		
			
			| 7 |  | -
 | 
		
	
		
			
			| 8 |  | -#define LONGLONG_SHIFT	((int)((sizeof(unsigned long long)*CHAR_BIT) - 4))
 | 
		
	
		
			
			| 9 |  | -#define LONG_SHIFT	((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
 | 
		
	
		
			
			| 10 |  | -#define INT_SHIFT	((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
 | 
		
	
		
			
			| 11 |  | -#define SHRT_SHIFT	((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
 | 
		
	
		
			
			| 12 |  | -#define CHAR_SHIFT	((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
 | 
		
	
		
			
			|  | 3 | +#include <console.h>
 | 
		
	
		
			
			|  | 4 | +#include <errno.h>
 | 
		
	
		
			
			|  | 5 | +#include <vsprintf.h>
 | 
		
	
		
			
			|  | 6 | +
 | 
		
	
		
			
			|  | 7 | +#define CHAR_LEN	1
 | 
		
	
		
			
			|  | 8 | +#define SHORT_LEN	2
 | 
		
	
		
			
			|  | 9 | +#define INT_LEN		3
 | 
		
	
		
			
			|  | 10 | +#define LONG_LEN	4
 | 
		
	
		
			
			|  | 11 | +#define LONGLONG_LEN	5
 | 
		
	
		
			
			|  | 12 | +#define SIZE_T_LEN	6
 | 
		
	
		
			
			|  | 13 | +
 | 
		
	
		
			
			|  | 14 | +static uint8_t type_sizes[] = {
 | 
		
	
		
			
			|  | 15 | +	[CHAR_LEN]	= sizeof ( char ),
 | 
		
	
		
			
			|  | 16 | +	[SHORT_LEN]	= sizeof ( short ),
 | 
		
	
		
			
			|  | 17 | +	[INT_LEN]	= sizeof ( int ),
 | 
		
	
		
			
			|  | 18 | +	[LONG_LEN]	= sizeof ( long ),
 | 
		
	
		
			
			|  | 19 | +	[LONGLONG_LEN]	= sizeof ( long long ),
 | 
		
	
		
			
			|  | 20 | +	[SIZE_T_LEN]	= sizeof ( size_t ),
 | 
		
	
		
			
			|  | 21 | +};
 | 
		
	
		
			
			| 13 | 22 |  
 | 
		
	
		
			
			| 14 | 23 |  /** @file */
 | 
		
	
		
			
			| 15 | 24 |  
 | 
		
	
		
			
			| 16 | 25 |  /**
 | 
		
	
		
			
			| 17 |  | - * Write a formatted string to a buffer.
 | 
		
	
		
			
			|  | 26 | + * A printf context
 | 
		
	
		
			
			| 18 | 27 |   *
 | 
		
	
		
			
			| 19 |  | - * @v buf		Buffer into which to write the string, or NULL
 | 
		
	
		
			
			|  | 28 | + * Contexts are used in order to be able to share code between
 | 
		
	
		
			
			|  | 29 | + * vprintf() and vsnprintf(), without requiring the allocation of a
 | 
		
	
		
			
			|  | 30 | + * buffer for vprintf().
 | 
		
	
		
			
			|  | 31 | + */
 | 
		
	
		
			
			|  | 32 | +struct printf_context {
 | 
		
	
		
			
			|  | 33 | +	/**
 | 
		
	
		
			
			|  | 34 | +	 * Character handler
 | 
		
	
		
			
			|  | 35 | +	 *
 | 
		
	
		
			
			|  | 36 | +	 * @v ctx	Context
 | 
		
	
		
			
			|  | 37 | +	 * @v c		Character
 | 
		
	
		
			
			|  | 38 | +	 *
 | 
		
	
		
			
			|  | 39 | +	 * This method is called for each character written to the
 | 
		
	
		
			
			|  | 40 | +	 * formatted string.  It must increment @len.
 | 
		
	
		
			
			|  | 41 | +	 */
 | 
		
	
		
			
			|  | 42 | +	void ( * handler ) ( struct printf_context *ctx, unsigned int c );
 | 
		
	
		
			
			|  | 43 | +	/** Length of formatted string */
 | 
		
	
		
			
			|  | 44 | +	size_t len;
 | 
		
	
		
			
			|  | 45 | +	/** Buffer for formatted string (used by printf_sputc()) */
 | 
		
	
		
			
			|  | 46 | +	char *buf;
 | 
		
	
		
			
			|  | 47 | +	/** Buffer length (used by printf_sputc()) */
 | 
		
	
		
			
			|  | 48 | +	size_t max_len;
 | 
		
	
		
			
			|  | 49 | +};
 | 
		
	
		
			
			|  | 50 | +
 | 
		
	
		
			
			|  | 51 | +#define LCASE 0x20
 | 
		
	
		
			
			|  | 52 | +#define ALT_FORM 0x02
 | 
		
	
		
			
			|  | 53 | +
 | 
		
	
		
			
			|  | 54 | +static char * format_hex ( char *buf, unsigned long long num, int width,
 | 
		
	
		
			
			|  | 55 | +			   int flags ) {
 | 
		
	
		
			
			|  | 56 | +	char *ptr = buf;
 | 
		
	
		
			
			|  | 57 | +	int case_mod;
 | 
		
	
		
			
			|  | 58 | +
 | 
		
	
		
			
			|  | 59 | +	/* Generate the number */
 | 
		
	
		
			
			|  | 60 | +	case_mod = flags & LCASE;
 | 
		
	
		
			
			|  | 61 | +	do {
 | 
		
	
		
			
			|  | 62 | +		*ptr++ = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
 | 
		
	
		
			
			|  | 63 | +		num >>= 4;
 | 
		
	
		
			
			|  | 64 | +	} while ( num );
 | 
		
	
		
			
			|  | 65 | +
 | 
		
	
		
			
			|  | 66 | +	/* Zero-pad to width */
 | 
		
	
		
			
			|  | 67 | +	while ( ( ptr - buf ) < width )
 | 
		
	
		
			
			|  | 68 | +		*ptr++ = '0';
 | 
		
	
		
			
			|  | 69 | +
 | 
		
	
		
			
			|  | 70 | +	/* Add "0x" or "0X" if alternate form specified */
 | 
		
	
		
			
			|  | 71 | +	if ( flags & ALT_FORM ) {
 | 
		
	
		
			
			|  | 72 | +		*ptr++ = 'X' | case_mod;
 | 
		
	
		
			
			|  | 73 | +		*ptr++ = '0';
 | 
		
	
		
			
			|  | 74 | +	}
 | 
		
	
		
			
			|  | 75 | +
 | 
		
	
		
			
			|  | 76 | +	return ptr;
 | 
		
	
		
			
			|  | 77 | +}
 | 
		
	
		
			
			|  | 78 | +
 | 
		
	
		
			
			|  | 79 | +static char * format_decimal ( char *buf, signed long num, int width ) {
 | 
		
	
		
			
			|  | 80 | +	char *ptr = buf;
 | 
		
	
		
			
			|  | 81 | +	int negative = 0;
 | 
		
	
		
			
			|  | 82 | +
 | 
		
	
		
			
			|  | 83 | +	/* Generate the number */
 | 
		
	
		
			
			|  | 84 | +	if ( num < 0 ) {
 | 
		
	
		
			
			|  | 85 | +		negative = 1;
 | 
		
	
		
			
			|  | 86 | +		num = -num;
 | 
		
	
		
			
			|  | 87 | +	}
 | 
		
	
		
			
			|  | 88 | +	do {
 | 
		
	
		
			
			|  | 89 | +		*ptr++ = '0' + ( num % 10 );
 | 
		
	
		
			
			|  | 90 | +		num /= 10;
 | 
		
	
		
			
			|  | 91 | +	} while ( num );
 | 
		
	
		
			
			|  | 92 | +
 | 
		
	
		
			
			|  | 93 | +	/* Add "-" if necessary */
 | 
		
	
		
			
			|  | 94 | +	if ( negative )
 | 
		
	
		
			
			|  | 95 | +		*ptr++ = '-';
 | 
		
	
		
			
			|  | 96 | +
 | 
		
	
		
			
			|  | 97 | +	/* Space-pad to width */
 | 
		
	
		
			
			|  | 98 | +	while ( ( ptr - buf ) < width )
 | 
		
	
		
			
			|  | 99 | +		*ptr++ = ' ';
 | 
		
	
		
			
			|  | 100 | +
 | 
		
	
		
			
			|  | 101 | +	return ptr;
 | 
		
	
		
			
			|  | 102 | +}
 | 
		
	
		
			
			|  | 103 | +
 | 
		
	
		
			
			|  | 104 | +
 | 
		
	
		
			
			|  | 105 | +/**
 | 
		
	
		
			
			|  | 106 | + * Write a formatted string to a printf context
 | 
		
	
		
			
			|  | 107 | + *
 | 
		
	
		
			
			|  | 108 | + * @v ctx		Context
 | 
		
	
		
			
			| 20 | 109 |   * @v fmt		Format string
 | 
		
	
		
			
			| 21 | 110 |   * @v args		Arguments corresponding to the format string
 | 
		
	
		
			
			| 22 |  | - * @ret len		Length of string written to buffer (if buf != NULL)
 | 
		
	
		
			
			| 23 |  | - * @ret	0		(if buf == NULL)
 | 
		
	
		
			
			| 24 |  | - * @err None		-
 | 
		
	
		
			
			| 25 |  | - *
 | 
		
	
		
			
			| 26 |  | - * If #buf==NULL, then the string will be written to the console
 | 
		
	
		
			
			| 27 |  | - * directly using putchar().
 | 
		
	
		
			
			| 28 |  | - *
 | 
		
	
		
			
			|  | 111 | + * @ret len		Length of formatted string
 | 
		
	
		
			
			| 29 | 112 |   */
 | 
		
	
		
			
			| 30 |  | -static int vsprintf(char *buf, const char *fmt, va_list args)
 | 
		
	
		
			
			| 31 |  | -{
 | 
		
	
		
			
			| 32 |  | -	const char *p;
 | 
		
	
		
			
			| 33 |  | -	char *s;
 | 
		
	
		
			
			| 34 |  | -	s = buf;
 | 
		
	
		
			
			| 35 |  | -	for ( ; *fmt != '\0'; ++fmt) {
 | 
		
	
		
			
			| 36 |  | -		if (*fmt != '%') {
 | 
		
	
		
			
			| 37 |  | -			buf ? *s++ = *fmt : putchar(*fmt);
 | 
		
	
		
			
			|  | 113 | +int vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
 | 
		
	
		
			
			|  | 114 | +	int flags;
 | 
		
	
		
			
			|  | 115 | +	int width;
 | 
		
	
		
			
			|  | 116 | +	uint8_t *length;
 | 
		
	
		
			
			|  | 117 | +	int character;
 | 
		
	
		
			
			|  | 118 | +	unsigned long long hex;
 | 
		
	
		
			
			|  | 119 | +	signed long decimal;
 | 
		
	
		
			
			|  | 120 | +	char num_buf[32];
 | 
		
	
		
			
			|  | 121 | +	char *ptr;
 | 
		
	
		
			
			|  | 122 | +
 | 
		
	
		
			
			|  | 123 | +	/* Initialise context */
 | 
		
	
		
			
			|  | 124 | +	ctx->len = 0;
 | 
		
	
		
			
			|  | 125 | +
 | 
		
	
		
			
			|  | 126 | +	for ( ; *fmt ; fmt++ ) {
 | 
		
	
		
			
			|  | 127 | +		/* Pass through ordinary characters */
 | 
		
	
		
			
			|  | 128 | +		if ( *fmt != '%' ) {
 | 
		
	
		
			
			|  | 129 | +			ctx->handler ( ctx, *fmt );
 | 
		
	
		
			
			| 38 | 130 |  			continue;
 | 
		
	
		
			
			| 39 | 131 |  		}
 | 
		
	
		
			
			| 40 |  | -		/* skip width specs */
 | 
		
	
		
			
			| 41 | 132 |  		fmt++;
 | 
		
	
		
			
			| 42 |  | -		while (*fmt >= '0' && *fmt <= '9')
 | 
		
	
		
			
			| 43 |  | -			fmt++;
 | 
		
	
		
			
			| 44 |  | -		if (*fmt == '.')
 | 
		
	
		
			
			| 45 |  | -			fmt++;
 | 
		
	
		
			
			| 46 |  | -		while (*fmt >= '0' && *fmt <= '9')
 | 
		
	
		
			
			| 47 |  | -			fmt++;
 | 
		
	
		
			
			| 48 |  | -		if (*fmt == 's') {
 | 
		
	
		
			
			| 49 |  | -			for(p = va_arg(args, char *); *p != '\0'; p++)
 | 
		
	
		
			
			| 50 |  | -				buf ? *s++ = *p : putchar(*p);
 | 
		
	
		
			
			| 51 |  | -		} else if (*fmt == 'm') {
 | 
		
	
		
			
			| 52 |  | -			for(p = strerror(errno); *p != '\0'; p++)
 | 
		
	
		
			
			| 53 |  | -				buf ? *s++ = *p : putchar(*p);
 | 
		
	
		
			
			| 54 |  | -		} else {	/* Length of item is bounded */
 | 
		
	
		
			
			| 55 |  | -			char tmp[40], *q = tmp;
 | 
		
	
		
			
			| 56 |  | -			int alt = 0;
 | 
		
	
		
			
			| 57 |  | -			int shift = INT_SHIFT;
 | 
		
	
		
			
			| 58 |  | -			if (*fmt == '#') {
 | 
		
	
		
			
			| 59 |  | -				alt = 1;
 | 
		
	
		
			
			| 60 |  | -				fmt++;
 | 
		
	
		
			
			| 61 |  | -			}
 | 
		
	
		
			
			| 62 |  | -			if (*fmt == 'l') {
 | 
		
	
		
			
			| 63 |  | -				shift = LONG_SHIFT;
 | 
		
	
		
			
			| 64 |  | -				fmt++;
 | 
		
	
		
			
			|  | 133 | +		/* Process flag characters */
 | 
		
	
		
			
			|  | 134 | +		flags = 0;
 | 
		
	
		
			
			|  | 135 | +		for ( ; ; fmt++ ) {
 | 
		
	
		
			
			|  | 136 | +			if ( *fmt == '#' ) {
 | 
		
	
		
			
			|  | 137 | +				flags |= ALT_FORM;
 | 
		
	
		
			
			|  | 138 | +			} else if ( *fmt == '0' ) {
 | 
		
	
		
			
			|  | 139 | +				/* We always 0-pad hex and space-pad decimal */
 | 
		
	
		
			
			|  | 140 | +			} else {
 | 
		
	
		
			
			|  | 141 | +				/* End of flag characters */
 | 
		
	
		
			
			|  | 142 | +				break;
 | 
		
	
		
			
			| 65 | 143 |  			}
 | 
		
	
		
			
			| 66 |  | -			if (*fmt == 'l') {
 | 
		
	
		
			
			| 67 |  | -				shift = LONGLONG_SHIFT;
 | 
		
	
		
			
			| 68 |  | -				fmt++;
 | 
		
	
		
			
			| 69 |  | -			}
 | 
		
	
		
			
			| 70 |  | -			if (*fmt == 'h') {
 | 
		
	
		
			
			| 71 |  | -				shift = SHRT_SHIFT;
 | 
		
	
		
			
			| 72 |  | -				fmt++;
 | 
		
	
		
			
			| 73 |  | -				if (*fmt == 'h') {
 | 
		
	
		
			
			| 74 |  | -					shift = CHAR_SHIFT;
 | 
		
	
		
			
			| 75 |  | -					fmt++;
 | 
		
	
		
			
			| 76 |  | -				}
 | 
		
	
		
			
			|  | 144 | +		}
 | 
		
	
		
			
			|  | 145 | +		/* Process field width */
 | 
		
	
		
			
			|  | 146 | +		width = 0;
 | 
		
	
		
			
			|  | 147 | +		for ( ; ; fmt++ ) {
 | 
		
	
		
			
			|  | 148 | +			if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) {
 | 
		
	
		
			
			|  | 149 | +				width = ( width * 10 ) + ( *fmt - '0' );
 | 
		
	
		
			
			|  | 150 | +			} else {
 | 
		
	
		
			
			|  | 151 | +				break;
 | 
		
	
		
			
			| 77 | 152 |  			}
 | 
		
	
		
			
			| 78 |  | -
 | 
		
	
		
			
			| 79 |  | -			/*
 | 
		
	
		
			
			| 80 |  | -			 * Before each format q points to tmp buffer
 | 
		
	
		
			
			| 81 |  | -			 * After each format q points past end of item
 | 
		
	
		
			
			| 82 |  | -			 */
 | 
		
	
		
			
			| 83 |  | -			if ((*fmt | 0x20) == 'x') {
 | 
		
	
		
			
			| 84 |  | -				/* With x86 gcc, sizeof(long) == sizeof(int) */
 | 
		
	
		
			
			| 85 |  | -				unsigned long h;
 | 
		
	
		
			
			| 86 |  | -				int ncase;
 | 
		
	
		
			
			| 87 |  | -				if (shift > LONG_SHIFT) {
 | 
		
	
		
			
			| 88 |  | -					h = va_arg(args, unsigned long long);
 | 
		
	
		
			
			| 89 |  | -				} else if (shift > INT_SHIFT) {
 | 
		
	
		
			
			| 90 |  | -					h = va_arg(args, unsigned long);
 | 
		
	
		
			
			| 91 |  | -				} else {
 | 
		
	
		
			
			| 92 |  | -					h = va_arg(args, unsigned int);
 | 
		
	
		
			
			| 93 |  | -				}
 | 
		
	
		
			
			| 94 |  | -				ncase = (*fmt & 0x20);
 | 
		
	
		
			
			| 95 |  | -				if (alt) {
 | 
		
	
		
			
			| 96 |  | -					*q++ = '0';
 | 
		
	
		
			
			| 97 |  | -					*q++ = 'X' | ncase;
 | 
		
	
		
			
			| 98 |  | -				}
 | 
		
	
		
			
			| 99 |  | -				for ( ; shift >= 0; shift -= 4)
 | 
		
	
		
			
			| 100 |  | -					*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
 | 
		
	
		
			
			|  | 153 | +		}
 | 
		
	
		
			
			|  | 154 | +		/* We don't do floating point */
 | 
		
	
		
			
			|  | 155 | +		/* Process length modifier */
 | 
		
	
		
			
			|  | 156 | +		length = &type_sizes[INT_LEN];
 | 
		
	
		
			
			|  | 157 | +		for ( ; ; fmt++ ) {
 | 
		
	
		
			
			|  | 158 | +			if ( *fmt == 'h' ) {
 | 
		
	
		
			
			|  | 159 | +				length--;
 | 
		
	
		
			
			|  | 160 | +			} else if ( *fmt == 'l' ) {
 | 
		
	
		
			
			|  | 161 | +				length++;
 | 
		
	
		
			
			|  | 162 | +			} else if ( *fmt == 'z' ) {
 | 
		
	
		
			
			|  | 163 | +				length = &type_sizes[SIZE_T_LEN];
 | 
		
	
		
			
			|  | 164 | +			} else {
 | 
		
	
		
			
			|  | 165 | +				break;
 | 
		
	
		
			
			| 101 | 166 |  			}
 | 
		
	
		
			
			| 102 |  | -			else if (*fmt == 'd') {
 | 
		
	
		
			
			| 103 |  | -				char *r, *t;
 | 
		
	
		
			
			| 104 |  | -				long i;
 | 
		
	
		
			
			| 105 |  | -				if (shift > LONG_SHIFT) {
 | 
		
	
		
			
			| 106 |  | -					i = va_arg(args, long long);
 | 
		
	
		
			
			| 107 |  | -				} else if (shift > INT_SHIFT) {
 | 
		
	
		
			
			| 108 |  | -					i = va_arg(args, long);
 | 
		
	
		
			
			| 109 |  | -				} else {
 | 
		
	
		
			
			| 110 |  | -					i = va_arg(args, int);
 | 
		
	
		
			
			| 111 |  | -				}
 | 
		
	
		
			
			| 112 |  | -				if (i < 0) {
 | 
		
	
		
			
			| 113 |  | -					*q++ = '-';
 | 
		
	
		
			
			| 114 |  | -					i = -i;
 | 
		
	
		
			
			| 115 |  | -				}
 | 
		
	
		
			
			| 116 |  | -				t = q;		/* save beginning of digits */
 | 
		
	
		
			
			| 117 |  | -				do {
 | 
		
	
		
			
			| 118 |  | -					*q++ = '0' + (i % 10);
 | 
		
	
		
			
			| 119 |  | -					i /= 10;
 | 
		
	
		
			
			| 120 |  | -				} while (i);
 | 
		
	
		
			
			| 121 |  | -				/* reverse digits, stop in middle */
 | 
		
	
		
			
			| 122 |  | -				r = q;		/* don't alter q */
 | 
		
	
		
			
			| 123 |  | -				while (--r > t) {
 | 
		
	
		
			
			| 124 |  | -					i = *r;
 | 
		
	
		
			
			| 125 |  | -					*r = *t;
 | 
		
	
		
			
			| 126 |  | -					*t++ = i;
 | 
		
	
		
			
			| 127 |  | -				}
 | 
		
	
		
			
			|  | 167 | +		}
 | 
		
	
		
			
			|  | 168 | +		/* Process conversion specifier */
 | 
		
	
		
			
			|  | 169 | +		if ( *fmt == 'c' ) {
 | 
		
	
		
			
			|  | 170 | +			character = va_arg ( args, unsigned int );
 | 
		
	
		
			
			|  | 171 | +			ctx->handler ( ctx, character );
 | 
		
	
		
			
			|  | 172 | +		} else if ( *fmt == 's' ) {
 | 
		
	
		
			
			|  | 173 | +			ptr = va_arg ( args, char * );
 | 
		
	
		
			
			|  | 174 | +			for ( ; *ptr ; ptr++ ) {
 | 
		
	
		
			
			|  | 175 | +				ctx->handler ( ctx, *ptr );
 | 
		
	
		
			
			| 128 | 176 |  			}
 | 
		
	
		
			
			| 129 |  | -			else if (*fmt == '@') {
 | 
		
	
		
			
			| 130 |  | -				unsigned char *r;
 | 
		
	
		
			
			| 131 |  | -				union {
 | 
		
	
		
			
			| 132 |  | -					uint32_t	l;
 | 
		
	
		
			
			| 133 |  | -					unsigned char	c[4];
 | 
		
	
		
			
			| 134 |  | -				} u;
 | 
		
	
		
			
			| 135 |  | -				u.l = va_arg(args, uint32_t);
 | 
		
	
		
			
			| 136 |  | -				for (r = &u.c[0]; r < &u.c[4]; ++r)
 | 
		
	
		
			
			| 137 |  | -					q += sprintf(q, "%d.", *r);
 | 
		
	
		
			
			| 138 |  | -				--q;
 | 
		
	
		
			
			|  | 177 | +		} else if ( *fmt == 'p' ) {
 | 
		
	
		
			
			|  | 178 | +			hex = ( intptr_t ) va_arg ( args, void * );
 | 
		
	
		
			
			|  | 179 | +			ptr = format_hex ( num_buf, hex, width,
 | 
		
	
		
			
			|  | 180 | +					   ( ALT_FORM | LCASE ) );
 | 
		
	
		
			
			|  | 181 | +			do {
 | 
		
	
		
			
			|  | 182 | +				ctx->handler ( ctx, *(--ptr) );
 | 
		
	
		
			
			|  | 183 | +			} while ( ptr != num_buf );
 | 
		
	
		
			
			|  | 184 | +		} else if ( ( *fmt & ~0x20 ) == 'X' ) {
 | 
		
	
		
			
			|  | 185 | +			flags |= ( *fmt & 0x20 ); /* LCASE */
 | 
		
	
		
			
			|  | 186 | +			if ( *length >= sizeof ( unsigned long long ) ) {
 | 
		
	
		
			
			|  | 187 | +				hex = va_arg ( args, unsigned long long );
 | 
		
	
		
			
			|  | 188 | +			} else if ( *length >= sizeof ( unsigned long ) ) {
 | 
		
	
		
			
			|  | 189 | +				hex = va_arg ( args, unsigned long );
 | 
		
	
		
			
			|  | 190 | +			} else {
 | 
		
	
		
			
			|  | 191 | +				hex = va_arg ( args, unsigned int );
 | 
		
	
		
			
			| 139 | 192 |  			}
 | 
		
	
		
			
			| 140 |  | -			else if (*fmt == '!') {
 | 
		
	
		
			
			| 141 |  | -				const char *r;
 | 
		
	
		
			
			| 142 |  | -				p = va_arg(args, char *);
 | 
		
	
		
			
			| 143 |  | -				for (r = p + ETH_ALEN; p < r; ++p)
 | 
		
	
		
			
			| 144 |  | -					q += sprintf(q, "%hhX:", *p);
 | 
		
	
		
			
			| 145 |  | -				--q;
 | 
		
	
		
			
			|  | 193 | +			ptr = format_hex ( num_buf, hex, width, flags );
 | 
		
	
		
			
			|  | 194 | +			do {
 | 
		
	
		
			
			|  | 195 | +				ctx->handler ( ctx, *(--ptr) );
 | 
		
	
		
			
			|  | 196 | +			} while ( ptr != num_buf );
 | 
		
	
		
			
			|  | 197 | +		} else if ( *fmt == 'd' ) {
 | 
		
	
		
			
			|  | 198 | +			if ( *length >= sizeof ( signed long ) ) {
 | 
		
	
		
			
			|  | 199 | +				decimal = va_arg ( args, signed long );
 | 
		
	
		
			
			|  | 200 | +			} else {
 | 
		
	
		
			
			|  | 201 | +				decimal = va_arg ( args, signed int );
 | 
		
	
		
			
			| 146 | 202 |  			}
 | 
		
	
		
			
			| 147 |  | -			else if (*fmt == 'c')
 | 
		
	
		
			
			| 148 |  | -				*q++ = va_arg(args, int);
 | 
		
	
		
			
			| 149 |  | -			else
 | 
		
	
		
			
			| 150 |  | -				*q++ = *fmt;
 | 
		
	
		
			
			| 151 |  | -			/* now output the saved string */
 | 
		
	
		
			
			| 152 |  | -			for (p = tmp; p < q; ++p)
 | 
		
	
		
			
			| 153 |  | -				buf ? *s++ = *p : putchar(*p);
 | 
		
	
		
			
			|  | 203 | +			ptr = format_decimal ( num_buf, decimal, width );
 | 
		
	
		
			
			|  | 204 | +			do {
 | 
		
	
		
			
			|  | 205 | +				ctx->handler ( ctx, *(--ptr) );
 | 
		
	
		
			
			|  | 206 | +			} while ( ptr != num_buf );
 | 
		
	
		
			
			|  | 207 | +		} else {
 | 
		
	
		
			
			|  | 208 | +			ctx->handler ( ctx, *fmt );
 | 
		
	
		
			
			| 154 | 209 |  		}
 | 
		
	
		
			
			| 155 | 210 |  	}
 | 
		
	
		
			
			| 156 |  | -	if (buf)
 | 
		
	
		
			
			| 157 |  | -		*s = '\0';
 | 
		
	
		
			
			| 158 |  | -	return (s - buf);
 | 
		
	
		
			
			|  | 211 | +
 | 
		
	
		
			
			|  | 212 | +	return ctx->len;
 | 
		
	
		
			
			| 159 | 213 |  }
 | 
		
	
		
			
			| 160 | 214 |  
 | 
		
	
		
			
			| 161 | 215 |  /**
 | 
		
	
		
			
			| 162 |  | - * Write a formatted string to a buffer.
 | 
		
	
		
			
			|  | 216 | + * Write character to buffer
 | 
		
	
		
			
			| 163 | 217 |   *
 | 
		
	
		
			
			| 164 |  | - * @v buf		Buffer into which to write the string, or NULL
 | 
		
	
		
			
			| 165 |  | - * @v fmt		Format string
 | 
		
	
		
			
			| 166 |  | - * @v ...		Arguments corresponding to the format string
 | 
		
	
		
			
			| 167 |  | - * @ret len		Length of string written to buffer (if buf != NULL)
 | 
		
	
		
			
			| 168 |  | - * @ret	0		(if buf == NULL)
 | 
		
	
		
			
			| 169 |  | - * @err None		-
 | 
		
	
		
			
			|  | 218 | + * @v ctx		Context
 | 
		
	
		
			
			|  | 219 | + * @v c			Character
 | 
		
	
		
			
			|  | 220 | + */
 | 
		
	
		
			
			|  | 221 | +static void printf_sputc ( struct printf_context *ctx, unsigned int c ) {
 | 
		
	
		
			
			|  | 222 | +	if ( ++ctx->len < ctx->max_len )
 | 
		
	
		
			
			|  | 223 | +		ctx->buf[ctx->len-1] = c;
 | 
		
	
		
			
			|  | 224 | +}
 | 
		
	
		
			
			|  | 225 | +
 | 
		
	
		
			
			|  | 226 | +/**
 | 
		
	
		
			
			|  | 227 | + * Write a formatted string to a buffer
 | 
		
	
		
			
			| 170 | 228 |   *
 | 
		
	
		
			
			| 171 |  | - * If #buf==NULL, then the string will be written to the console
 | 
		
	
		
			
			| 172 |  | - * directly using putchar().
 | 
		
	
		
			
			|  | 229 | + * @v buf		Buffer into which to write the string
 | 
		
	
		
			
			|  | 230 | + * @v size		Size of buffer
 | 
		
	
		
			
			|  | 231 | + * @v fmt		Format string
 | 
		
	
		
			
			|  | 232 | + * @v args		Arguments corresponding to the format string
 | 
		
	
		
			
			|  | 233 | + * @ret len		Length of formatted string
 | 
		
	
		
			
			| 173 | 234 |   *
 | 
		
	
		
			
			|  | 235 | + * If the buffer is too small to contain the string, the returned
 | 
		
	
		
			
			|  | 236 | + * length is the length that would have been written had enough space
 | 
		
	
		
			
			|  | 237 | + * been available.
 | 
		
	
		
			
			| 174 | 238 |   */
 | 
		
	
		
			
			| 175 |  | -int sprintf(char *buf, const char *fmt, ...)
 | 
		
	
		
			
			| 176 |  | -{
 | 
		
	
		
			
			| 177 |  | -	va_list args;
 | 
		
	
		
			
			| 178 |  | -	int i;
 | 
		
	
		
			
			| 179 |  | -	va_start(args, fmt);
 | 
		
	
		
			
			| 180 |  | -	i=vsprintf(buf, fmt, args);
 | 
		
	
		
			
			| 181 |  | -	va_end(args);
 | 
		
	
		
			
			| 182 |  | -	return i;
 | 
		
	
		
			
			|  | 239 | +int vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) {
 | 
		
	
		
			
			|  | 240 | +	struct printf_context ctx;
 | 
		
	
		
			
			|  | 241 | +	int len;
 | 
		
	
		
			
			|  | 242 | +
 | 
		
	
		
			
			|  | 243 | +	/* Ensure last byte is NUL if a size is specified.  This
 | 
		
	
		
			
			|  | 244 | +	 * catches the case of the buffer being too small, in which
 | 
		
	
		
			
			|  | 245 | +	 * case a trailing NUL would not otherwise be added.
 | 
		
	
		
			
			|  | 246 | +	 */
 | 
		
	
		
			
			|  | 247 | +	if ( size != PRINTF_NO_LENGTH )
 | 
		
	
		
			
			|  | 248 | +		buf[size-1] = '\0';
 | 
		
	
		
			
			|  | 249 | +
 | 
		
	
		
			
			|  | 250 | +	/* Hand off to vcprintf */
 | 
		
	
		
			
			|  | 251 | +	ctx.handler = printf_sputc;
 | 
		
	
		
			
			|  | 252 | +	ctx.buf = buf;
 | 
		
	
		
			
			|  | 253 | +	ctx.max_len = size;
 | 
		
	
		
			
			|  | 254 | +	len = vcprintf ( &ctx, fmt, args );
 | 
		
	
		
			
			|  | 255 | +
 | 
		
	
		
			
			|  | 256 | +	/* Add trailing NUL */
 | 
		
	
		
			
			|  | 257 | +	printf_sputc ( &ctx, '\0' );
 | 
		
	
		
			
			|  | 258 | +
 | 
		
	
		
			
			|  | 259 | +	return len;
 | 
		
	
		
			
			| 183 | 260 |  }
 | 
		
	
		
			
			| 184 | 261 |  
 | 
		
	
		
			
			| 185 |  | -#warning "Remove this buffer-overflow-in-waiting at some point"
 | 
		
	
		
			
			|  | 262 | +/**
 | 
		
	
		
			
			|  | 263 | + * Write a formatted string to a buffer
 | 
		
	
		
			
			|  | 264 | + *
 | 
		
	
		
			
			|  | 265 | + * @v buf		Buffer into which to write the string
 | 
		
	
		
			
			|  | 266 | + * @v size		Size of buffer
 | 
		
	
		
			
			|  | 267 | + * @v fmt		Format string
 | 
		
	
		
			
			|  | 268 | + * @v ...		Arguments corresponding to the format string
 | 
		
	
		
			
			|  | 269 | + * @ret len		Length of formatted string
 | 
		
	
		
			
			|  | 270 | + */
 | 
		
	
		
			
			| 186 | 271 |  int snprintf ( char *buf, size_t size, const char *fmt, ... ) {
 | 
		
	
		
			
			| 187 | 272 |  	va_list args;
 | 
		
	
		
			
			| 188 | 273 |  	int i;
 | 
		
	
		
			
			| 189 | 274 |  
 | 
		
	
		
			
			| 190 | 275 |  	va_start ( args, fmt );
 | 
		
	
		
			
			| 191 |  | -	i = vsprintf ( buf, fmt, args );
 | 
		
	
		
			
			|  | 276 | +	i = vsnprintf ( buf, size, fmt, args );
 | 
		
	
		
			
			| 192 | 277 |  	va_end ( args );
 | 
		
	
		
			
			| 193 | 278 |  	return i;
 | 
		
	
		
			
			| 194 | 279 |  }
 | 
		
	
		
			
			| 195 | 280 |  
 | 
		
	
		
			
			|  | 281 | +/**
 | 
		
	
		
			
			|  | 282 | + * Write character to console
 | 
		
	
		
			
			|  | 283 | + *
 | 
		
	
		
			
			|  | 284 | + * @v ctx		Context
 | 
		
	
		
			
			|  | 285 | + * @v c			Character
 | 
		
	
		
			
			|  | 286 | + */
 | 
		
	
		
			
			|  | 287 | +static void printf_putchar ( struct printf_context *ctx, unsigned int c ) {
 | 
		
	
		
			
			|  | 288 | +	++ctx->len;
 | 
		
	
		
			
			|  | 289 | +	putchar ( c );
 | 
		
	
		
			
			|  | 290 | +}
 | 
		
	
		
			
			|  | 291 | +
 | 
		
	
		
			
			|  | 292 | +/**
 | 
		
	
		
			
			|  | 293 | + * Write a formatted string to the console
 | 
		
	
		
			
			|  | 294 | + *
 | 
		
	
		
			
			|  | 295 | + * @v fmt		Format string
 | 
		
	
		
			
			|  | 296 | + * @v args		Arguments corresponding to the format string
 | 
		
	
		
			
			|  | 297 | + * @ret len		Length of formatted string
 | 
		
	
		
			
			|  | 298 | + */
 | 
		
	
		
			
			|  | 299 | +int vprintf ( const char *fmt, va_list args ) {
 | 
		
	
		
			
			|  | 300 | +	struct printf_context ctx;
 | 
		
	
		
			
			|  | 301 | +
 | 
		
	
		
			
			|  | 302 | +	/* Hand off to vcprintf */
 | 
		
	
		
			
			|  | 303 | +	ctx.handler = printf_putchar;	
 | 
		
	
		
			
			|  | 304 | +	return vcprintf ( &ctx, fmt, args );	
 | 
		
	
		
			
			|  | 305 | +}
 | 
		
	
		
			
			|  | 306 | +
 | 
		
	
		
			
			| 196 | 307 |  /**
 | 
		
	
		
			
			| 197 | 308 |   * Write a formatted string to the console.
 | 
		
	
		
			
			| 198 | 309 |   *
 | 
		
	
		
			
			| 199 | 310 |   * @v fmt		Format string
 | 
		
	
		
			
			| 200 | 311 |   * @v ...		Arguments corresponding to the format string
 | 
		
	
		
			
			| 201 |  | - * @ret	None		-
 | 
		
	
		
			
			| 202 |  | - * @err None		-
 | 
		
	
		
			
			| 203 |  | - *
 | 
		
	
		
			
			|  | 312 | + * @ret	len		Length of formatted string
 | 
		
	
		
			
			| 204 | 313 |   */
 | 
		
	
		
			
			| 205 |  | -int printf(const char *fmt, ...)
 | 
		
	
		
			
			| 206 |  | -{
 | 
		
	
		
			
			|  | 314 | +int printf ( const char *fmt, ... ) {
 | 
		
	
		
			
			| 207 | 315 |  	va_list args;
 | 
		
	
		
			
			| 208 | 316 |  	int i;
 | 
		
	
		
			
			| 209 |  | -	va_start(args, fmt);
 | 
		
	
		
			
			| 210 |  | -	i=vsprintf(0, fmt, args);
 | 
		
	
		
			
			| 211 |  | -	va_end(args);
 | 
		
	
		
			
			|  | 317 | +
 | 
		
	
		
			
			|  | 318 | +	va_start ( args, fmt );
 | 
		
	
		
			
			|  | 319 | +	i = vprintf ( fmt, args );
 | 
		
	
		
			
			|  | 320 | +	va_end ( args );
 | 
		
	
		
			
			| 212 | 321 |  	return i;
 | 
		
	
		
			
			| 213 | 322 |  }
 |