NetBSD-5.0.2/sys/arch/sandpoint/stand/netboot/printf.c

Compare this file to the similar file:
Show the results in this format:

/* $NetBSD: printf.c,v 1.5 2008/04/28 20:23:34 martin Exp $ */

/*-
 * Copyright (c) 2007 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * printf -- format and write output using 'func' to write characters
 */

#include <sys/types.h>
#include <machine/stdarg.h>

#define MAXSTR	80

static int _doprnt(int (*)(int), const char *, va_list);
static void pr_int();
static int sputchar(int);
extern int putchar(int);

static char *sbuf, *ebuf;

void
printf(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_doprnt(putchar, fmt, ap);
	va_end(ap);
}

void
vprintf(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	_doprnt(putchar, fmt, ap);
	va_end(ap);
}

int
sprintf(char *buf, const char *fmt, ...)
{
	va_list ap;

	sbuf = buf;
	ebuf = buf + -(size_t)buf - 1;
	va_start(ap, fmt);
	_doprnt(sputchar, fmt, ap);
	*sbuf = '\0';
	return (sbuf - buf);
}

int
snprintf(char *buf, size_t size, const char *fmt, ...)
{
	va_list ap;

	sbuf = buf;
	ebuf = buf + size - 1;
	va_start(ap, fmt);
	_doprnt(sputchar, fmt, ap);
	*sbuf = '\0';
	return (sbuf - buf);
}

static int
_doprnt(func, fmt, ap)
	int (*func)(int);	/* Function to put a character */
	const char *fmt;	/* Format string for pr_int/pr_float */
	va_list ap;		/* Arguments to pr_int/pr_float */
{
	int i;
	char *str;
	char string[20];
	int length;
	int leftjust;
	int longflag;
	int fmax, fmin;
	int leading;
	int outcnt;
	char fill;
	char sign;

	outcnt = 0;
	while ((i = *fmt++) != '\0') {
		if (i != '%') {
			(*func)(i);
			outcnt += 1;
			continue;
		}
		if (*fmt == '%') {
			(*func)(*fmt++);
			outcnt += 1;
			continue;
		}
		leftjust = (*fmt == '-');
		if (leftjust)
			fmt++;
		fill = (*fmt == '0') ? *fmt++ : ' ';
		if (*fmt == '*')
			fmin = va_arg(ap, int);
		else {
			fmin = 0;
			while ('0' <= *fmt && *fmt <= '9')
				fmin = fmin * 10 + *fmt++ - '0';
		}
		if (*fmt != '.')
			fmax = 0;
		else {
			fmt++;
			if (*fmt == '*')
				fmax = va_arg(ap, int);
			else {
				fmax = 0;
				while ('0' <= *fmt && *fmt <= '9')
					fmax = fmax * 10 + *fmt++ - '0';
			}
		}
		longflag = (*fmt == 'l');
		if (longflag)
			fmt++;
		if ((i = *fmt++) == '\0') {
			(*func)('%');
			outcnt += 1;
			break;
		}
		str = string;
		sign = ' ';
		switch (i) {
		case 'c':
			str[0] = va_arg(ap, int);
			str[1] = '\0';
			fmax = 0;
			fill = ' ';
			break;

		case 's':
			str = va_arg(ap, char *);
			fill = ' ';
			break;

		case 'd':
		      {
			long l = va_arg(ap, long);
			if (l < 0) { sign = '-' ; l = -l; }
			pr_int((unsigned long)l, 10, str);
		      }
			break;

		case 'u':
			pr_int(va_arg(ap, unsigned long), 10, str);
			break;

		case 'o':
			pr_int(va_arg(ap, unsigned long), 8, str);
			fmax = 0;
			break;

		case 'X':
		case 'x':
			pr_int(va_arg(ap, unsigned long), 16, str);
			fmax = 0;
			break;

		case 'p':
			pr_int(va_arg(ap, unsigned long), 16, str);
			fill = '0';
			fmin = 8;
			fmax = 0;
			(*func)('0'); (*func)('x');
			outcnt += 2;
			break;
		default:
			(*func)(i);
			break;
		}
		for (i = 0; str[i] != '\0'; i++)
			;
		length = i;
		if (fmin > MAXSTR || fmin < 0)
			fmin = 0;
		if (fmax > MAXSTR || fmax < 0)
			fmax = 0;
		leading = 0;
		if (fmax != 0 || fmin != 0) {
			if (fmax != 0 && length > fmax)
				length = fmax;
			if (fmin != 0)
				leading = fmin - length;
			if (sign == '-')
				--leading;
		}
		outcnt += leading + length;
		if (sign == '-')
			outcnt += 1;
		if (sign == '-' && fill == '0')
			(*func)(sign);
		if (leftjust == 0)
			for (i = 0; i < leading; i++) (*func)(fill);
		if (sign == '-' && fill == ' ')
			(*func)(sign);
		for (i = 0; i < length; i++)
			(*func)(str[i]);
		if (leftjust != 0)
			for (i = 0; i < leading; i++) (*func)(fill);
	}
	return outcnt;
}

static void pr_int(lval, base, s)
	unsigned long lval;
	int base;
	char *s;
{
	char ptmp[12];	/* unsigned long requires 11 digit in octal form */
	int i;
	char *t = ptmp;
	static const char hexdigit[] = "0123456789abcdef";

	i = 1;
	*t++ = '\0';
	do {
		*t++ = hexdigit[lval % base];
	} while ((lval /= base) != 0 && ++i < sizeof(ptmp));
	while ((*s++ = *--t) != '\0')
		;
}

static int
sputchar(c)
	int c;
{

	if (sbuf < ebuf)
		*sbuf++ = c;
	return c;
}