176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stddef.h> 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdarg.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <console.h> 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/vsprintf.h> 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** @file */ 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define CHAR_LEN 0 /**< "hh" length modifier */ 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SHORT_LEN 1 /**< "h" length modifier */ 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define INT_LEN 2 /**< no length modifier */ 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LONG_LEN 3 /**< "l" length modifier */ 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LONGLONG_LEN 4 /**< "ll" length modifier */ 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SIZE_T_LEN 5 /**< "z" length modifier */ 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint8_t type_sizes[] = { 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [CHAR_LEN] = sizeof ( char ), 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SHORT_LEN] = sizeof ( short ), 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [INT_LEN] = sizeof ( int ), 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [LONG_LEN] = sizeof ( long ), 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [LONGLONG_LEN] = sizeof ( long long ), 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [SIZE_T_LEN] = sizeof ( size_t ), 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Use lower-case for hexadecimal digits 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note that this value is set to 0x20 since that makes for very 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * efficient calculations. (Bitwise-ORing with @c LCASE converts to a 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * lower-case character, for example.) 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LCASE 0x20 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Use "alternate form" 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For hexadecimal numbers, this means to add a "0x" or "0X" prefix to 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the number. 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ALT_FORM 0x02 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Format a hexadecimal number 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v end End of buffer to contain number 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v num Number to format 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v width Minimum field width 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret ptr End of buffer 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Fills a buffer in reverse order with a formatted hexadecimal 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number. The number will be zero-padded to the specified width. 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Lower-case and "alternate form" (i.e. "0x" prefix) flags may be 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * set. 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * There must be enough space in the buffer to contain the largest 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number that this function can format. 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic char * format_hex ( char *end, unsigned long long num, int width, 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int flags ) { 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *ptr = end; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int case_mod; 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Generate the number */ 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case_mod = flags & LCASE; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod; 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman num >>= 4; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ( num ); 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Zero-pad to width */ 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ( end - ptr ) < width ) 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = '0'; 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add "0x" or "0X" if alternate form specified */ 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( flags & ALT_FORM ) { 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = 'X' | case_mod; 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = '0'; 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ptr; 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Format a decimal number 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v end End of buffer to contain number 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v num Number to format 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v width Minimum field width 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret ptr End of buffer 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Fills a buffer in reverse order with a formatted decimal number. 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The number will be space-padded to the specified width. 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * There must be enough space in the buffer to contain the largest 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * number that this function can format. 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic char * format_decimal ( char *end, signed long num, int width ) { 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *ptr = end; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int negative = 0; 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Generate the number */ 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( num < 0 ) { 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman negative = 1; 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman num = -num; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = '0' + ( num % 10 ); 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman num /= 10; 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ( num ); 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add "-" if necessary */ 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( negative ) 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = '-'; 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Space-pad to width */ 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while ( ( end - ptr ) < width ) 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = ' '; 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ptr; 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Print character via a printf context 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ctx Context 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v c Character 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Call's the printf_context::handler() method and increments 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * printf_context::len. 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void cputchar ( struct printf_context *ctx, unsigned int c ) { 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctx->handler ( ctx, c ); 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ++ctx->len; 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a formatted string to a printf context 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ctx Context 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v args Arguments corresponding to the format string 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansize_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) { 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int flags; 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int width; 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *length; 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *ptr; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char tmp_buf[32]; /* 32 is enough for all numerical formats. 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Insane width fields could overflow this buffer. */ 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialise context */ 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctx->len = 0; 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; *fmt ; fmt++ ) { 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Pass through ordinary characters */ 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *fmt != '%' ) { 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cputchar ( ctx, *fmt ); 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman fmt++; 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process flag characters */ 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman flags = 0; 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; ; fmt++ ) { 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *fmt == '#' ) { 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman flags |= ALT_FORM; 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *fmt == '0' ) { 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We always 0-pad hex and space-pad decimal */ 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* End of flag characters */ 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process field width */ 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman width = 0; 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; ; fmt++ ) { 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ( ( unsigned ) ( *fmt - '0' ) ) < 10 ) { 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman width = ( width * 10 ) + ( *fmt - '0' ); 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We don't do floating point */ 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process length modifier */ 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman length = &type_sizes[INT_LEN]; 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; ; fmt++ ) { 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *fmt == 'h' ) { 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman length--; 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *fmt == 'l' ) { 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman length++; 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *fmt == 'z' ) { 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman length = &type_sizes[SIZE_T_LEN]; 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process conversion specifier */ 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = tmp_buf + sizeof ( tmp_buf ) - 1; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *ptr = '\0'; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *fmt == 'c' ) { 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cputchar ( ctx, va_arg ( args, unsigned int ) ); 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *fmt == 's' ) { 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = va_arg ( args, char * ); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ! ptr ) 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = "<NULL>"; 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *fmt == 'p' ) { 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman intptr_t ptrval; 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptrval = ( intptr_t ) va_arg ( args, void * ); 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = format_hex ( ptr, ptrval, width, 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( ALT_FORM | LCASE ) ); 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( ( *fmt & ~0x20 ) == 'X' ) { 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned long long hex; 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman flags |= ( *fmt & 0x20 ); /* LCASE */ 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *length >= sizeof ( unsigned long long ) ) { 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hex = va_arg ( args, unsigned long long ); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( *length >= sizeof ( unsigned long ) ) { 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hex = va_arg ( args, unsigned long ); 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hex = va_arg ( args, unsigned int ); 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = format_hex ( ptr, hex, width, flags ); 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if ( ( *fmt == 'd' ) || ( *fmt == 'i' ) ){ 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman signed long decimal; 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( *length >= sizeof ( signed long ) ) { 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman decimal = va_arg ( args, signed long ); 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman decimal = va_arg ( args, signed int ); 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ptr = format_decimal ( ptr, decimal, width ); 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *(--ptr) = *fmt; 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Write out conversion result */ 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; *ptr ; ptr++ ) { 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cputchar ( ctx, *ptr ); 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ctx->len; 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Context used by vsnprintf() and friends */ 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct sputc_context { 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct printf_context ctx; 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** Buffer for formatted string (used by printf_sputc()) */ 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *buf; 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /** Buffer length (used by printf_sputc()) */ 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t max_len; 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write character to buffer 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ctx Context 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v c Character 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void printf_sputc ( struct printf_context *ctx, unsigned int c ) { 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct sputc_context * sctx = 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman container_of ( ctx, struct sputc_context, ctx ); 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ctx->len < sctx->max_len ) 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sctx->buf[ctx->len] = c; 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a formatted string to a buffer 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v buf Buffer into which to write the string 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v size Size of buffer 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v args Arguments corresponding to the format string 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If the buffer is too small to contain the string, the returned 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * length is the length that would have been written had enough space 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * been available. 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint vsnprintf ( char *buf, size_t size, const char *fmt, va_list args ) { 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct sputc_context sctx; 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t len; 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t end; 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off to vcprintf */ 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sctx.ctx.handler = printf_sputc; 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sctx.buf = buf; 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sctx.max_len = size; 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = vcprintf ( &sctx.ctx, fmt, args ); 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Add trailing NUL */ 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( size ) { 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman end = size - 1; 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( len < end ) 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman end = len; 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buf[end] = '\0'; 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return len; 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a formatted string to a buffer 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v buf Buffer into which to write the string 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v size Size of buffer 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ... Arguments corresponding to the format string 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint snprintf ( char *buf, size_t size, const char *fmt, ... ) { 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_list args; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_start ( args, fmt ); 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i = vsnprintf ( buf, size, fmt, args ); 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_end ( args ); 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return i; 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Version of vsnprintf() that accepts a signed buffer size 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v buf Buffer into which to write the string 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v size Size of buffer 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v args Arguments corresponding to the format string 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint vssnprintf ( char *buf, ssize_t ssize, const char *fmt, va_list args ) { 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Treat negative buffer size as zero buffer size */ 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ( ssize < 0 ) 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ssize = 0; 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off to vsnprintf */ 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return vsnprintf ( buf, ssize, fmt, args ); 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Version of vsnprintf() that accepts a signed buffer size 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v buf Buffer into which to write the string 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v size Size of buffer 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ... Arguments corresponding to the format string 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) { 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_list args; 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int len; 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off to vssnprintf */ 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_start ( args, fmt ); 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = vssnprintf ( buf, ssize, fmt, args ); 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_end ( args ); 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return len; 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write character to console 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ctx Context 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v c Character 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void printf_putchar ( struct printf_context *ctx __unused, 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int c ) { 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman putchar ( c ); 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a formatted string to the console 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v args Arguments corresponding to the format string 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint vprintf ( const char *fmt, va_list args ) { 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct printf_context ctx; 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Hand off to vcprintf */ 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctx.handler = printf_putchar; 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return vcprintf ( &ctx, fmt, args ); 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write a formatted string to the console. 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v fmt Format string 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v ... Arguments corresponding to the format string 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret len Length of formatted string 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint printf ( const char *fmt, ... ) { 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_list args; 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_start ( args, fmt ); 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i = vprintf ( fmt, args ); 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman va_end ( args ); 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return i; 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 424