1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/promif.h>
30#include <sys/promimpl.h>
31#include <sys/varargs.h>
32
33static void _doprint(const char *, va_list, void (*)(char, char **), char **);
34static void _printn(uint64_t, int, int, int, void (*)(char, char **), char **);
35
36/*
37 * Emit character functions...
38 */
39
40/*ARGSUSED*/
41static void
42_pput(char c, char **p)
43{
44	(void) prom_putchar(c);
45}
46
47static void
48_sput(char c, char **p)
49{
50	**p = c;
51	*p += 1;
52}
53
54/*VARARGS1*/
55void
56prom_printf(const char *fmt, ...)
57{
58	va_list adx;
59
60	va_start(adx, fmt);
61	(void) _doprint(fmt, adx, _pput, (char **)0);
62	va_end(adx);
63}
64
65void
66prom_vprintf(const char *fmt, va_list adx)
67{
68	va_list tadx;
69
70	va_copy(tadx, adx);
71	(void) _doprint(fmt, tadx, _pput, (char **)0);
72	va_end(tadx);
73}
74
75/*VARARGS2*/
76char *
77prom_sprintf(char *s, const char *fmt, ...)
78{
79	char *bp = s;
80	va_list adx;
81
82	va_start(adx, fmt);
83	(void) _doprint(fmt, adx, _sput, &bp);
84	*bp++ = (char)0;
85	va_end(adx);
86	return (s);
87}
88
89char *
90prom_vsprintf(char *s, const char *fmt, va_list adx)
91{
92	char *bp = s;
93
94	(void) _doprint(fmt, adx, _sput, &bp);
95	*bp++ = (char)0;
96	return (s);
97}
98
99static void
100_doprint(const char *fmt, va_list adx, void (*emit)(char, char **), char **bp)
101{
102	int b, c, i, pad, width, ells;
103	register char *s;
104	int64_t	l;
105	uint64_t ul;
106
107loop:
108	width = 0;
109	while ((c = *fmt++) != '%') {
110		if (c == '\0')
111			return;
112		if (c == '\n')
113			(*emit)('\r', bp);
114		(*emit)(c, bp);
115	}
116
117	c = *fmt++;
118
119	for (pad = ' '; c == '0'; c = *fmt++)
120		pad = '0';
121
122	for (width = 0; c >= '0' && c <= '9'; c = *fmt++)
123		width = (width * 10) + (c - '0');
124
125	for (ells = 0; c == 'l'; c = *fmt++)
126		ells++;
127
128	switch (c) {
129
130	case 'd':
131	case 'D':
132		b = 10;
133		if (ells == 0)
134			l = (int64_t)va_arg(adx, int);
135		else if (ells == 1)
136			l = (int64_t)va_arg(adx, long);
137		else
138			l = (int64_t)va_arg(adx, int64_t);
139		if (l < 0) {
140			(*emit)('-', bp);
141			width--;
142			ul = -l;
143		} else
144			ul = l;
145		goto number;
146
147	case 'p':
148		ells = 1;
149		/* FALLTHROUGH */
150	case 'x':
151	case 'X':
152		b = 16;
153		goto u_number;
154
155	case 'u':
156		b = 10;
157		goto u_number;
158
159	case 'o':
160	case 'O':
161		b = 8;
162u_number:
163		if (ells == 0)
164			ul = (uint64_t)va_arg(adx, uint_t);
165		else if (ells == 1)
166			ul = (uint64_t)va_arg(adx, ulong_t);
167		else
168			ul = (uint64_t)va_arg(adx, uint64_t);
169number:
170		_printn(ul, b, width, pad, emit, bp);
171		break;
172
173	case 'c':
174		b = va_arg(adx, int);
175		for (i = 24; i >= 0; i -= 8)
176			if ((c = ((b >> i) & 0x7f)) != 0) {
177				if (c == '\n')
178					(*emit)('\r', bp);
179				(*emit)(c, bp);
180			}
181		break;
182	case 's':
183		s = va_arg(adx, char *);
184		while ((c = *s++) != 0) {
185			if (c == '\n')
186				(*emit)('\r', bp);
187			(*emit)(c, bp);
188		}
189		break;
190
191	case '%':
192		(*emit)('%', bp);
193		break;
194	}
195	goto loop;
196}
197
198/*
199 * Printn prints a number n in base b.
200 * We don't use recursion to avoid deep kernel stacks.
201 */
202static void
203_printn(uint64_t n, int b, int width, int pad, void (*emit)(char, char **),
204	char **bp)
205{
206	char prbuf[40];
207	register char *cp;
208
209	cp = prbuf;
210	do {
211		*cp++ = "0123456789abcdef"[n%b];
212		n /= b;
213		width--;
214	} while (n);
215	while (width-- > 0)
216		*cp++ = (char)pad;
217	do {
218		(*emit)(*--cp, bp);
219	} while (cp > prbuf);
220}
221