Skip to content
Snippets Groups Projects
tiny-printf.c 3.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * Tiny printf version for SPL
     *
     * Copied from:
     * http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
     *
     * Copyright (C) 2004,2008  Kustaa Nyholm
     *
     * SPDX-License-Identifier:	LGPL-2.1+
     */
    
    #include <common.h>
    #include <stdarg.h>
    #include <serial.h>
    
    
    struct printf_info {
    	char *bf;	/* Digit buffer */
    	char zs;	/* non-zero if a digit has been written */
    	char *outstr;	/* Next output position for sprintf() */
    
    	/* Output a character */
    	void (*putc)(struct printf_info *info, char ch);
    };
    
    void putc_normal(struct printf_info *info, char ch)
    
    static void out(struct printf_info *info, char c)
    
    static void out_dgt(struct printf_info *info, char dgt)
    {
    	out(info, dgt + (dgt < 10 ? '0' : 'a' - 10));
    	info->zs = 1;
    }
    
    static void div_out(struct printf_info *info, unsigned int *num,
    		    unsigned int div)
    
    	if (info->zs || dgt > 0)
    		out_dgt(info, dgt);
    
    int _vprintf(struct printf_info *info, const char *fmt, va_list va)
    
    	unsigned int num;
    	char buf[12];
    	unsigned int div;
    
    			info->putc(info, ch);
    
    			bool lz = false;
    			int width = 0;
    
    
    			ch = *(fmt++);
    			if (ch == '0') {
    				ch = *(fmt++);
    				lz = 1;
    			}
    
    			if (ch >= '0' && ch <= '9') {
    
    				width = 0;
    
    					width = (width * 10) + ch - '0';
    
    			info->bf = buf;
    			p = info->bf;
    			info->zs = 0;
    
    			case '\0':
    
    				goto abort;
    			case 'u':
    			case 'd':
    				num = va_arg(va, unsigned int);
    				if (ch == 'd' && (int)num < 0) {
    					num = -(int)num;
    
    				if (!num) {
    
    					out_dgt(info, 0);
    
    				} else {
    					for (div = 1000000000; div; div /= 10)
    
    						div_out(info, &num, div);
    
    				break;
    			case 'x':
    				num = va_arg(va, unsigned int);
    
    				if (!num) {
    
    				} else {
    					for (div = 0x10000000; div; div /= 0x10)
    
    						div_out(info, &num, div);
    
    				out(info, (char)(va_arg(va, int)));
    
    				break;
    			case 's':
    				p = va_arg(va, char*);
    				break;
    			case '%':
    
    			*info->bf = 0;
    			info->bf = p;
    			while (*info->bf++ && width > 0)
    
    				width--;
    			while (width-- > 0)
    
    				info->putc(info, lz ? '0' : ' ');
    
    			if (p) {
    				while ((ch = *p++))
    
    					info->putc(info, ch);
    
    int vprintf(const char *fmt, va_list va)
    {
    
    	struct printf_info info;
    
    	info.putc = putc_normal;
    	return _vprintf(&info, fmt, va);
    
    int printf(const char *fmt, ...)
    {
    
    	struct printf_info info;
    
    
    	va_list va;
    	int ret;
    
    
    	info.putc = putc_normal;
    
    	va_start(va, fmt);
    
    	ret = _vprintf(&info, fmt, va);
    
    	va_end(va);
    
    	return ret;
    }
    
    
    static void putc_outstr(struct printf_info *info, char ch)
    
    	*info->outstr++ = ch;
    
    int sprintf(char *buf, const char *fmt, ...)
    
    	struct printf_info info;
    
    	va_list va;
    	int ret;
    
    	va_start(va, fmt);
    
    	info.outstr = buf;
    	info.putc = putc_outstr;
    	ret = _vprintf(&info, fmt, va);
    
    	*info.outstr = '\0';
    
    
    /* Note that size is ignored */
    int snprintf(char *buf, size_t size, const char *fmt, ...)
    {
    
    	struct printf_info info;
    
    	va_list va;
    	int ret;
    
    	va_start(va, fmt);
    
    	info.outstr = buf;
    	info.putc = putc_outstr;
    	ret = _vprintf(&info, fmt, va);
    
    	va_end(va);
    
    	*info.outstr = '\0';
    
    
    void __assert_fail(const char *assertion, const char *file, unsigned line,
    		   const char *function)
    {
    	/* This will not return */
    	printf("%s:%u: %s: Assertion `%s' failed.", file, line, function,
    	       assertion);
    	hang();
    }