xref: /illumos-gate/usr/src/psm/promif/ieee1275/common/prom_printf.c (revision 22028508fd28d36ff74dc02c5774a8ba1f0db045)
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 (c) 1995-1996, by Sun Microsystems, Inc.
24  * All rights reserved.
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 
33 static void _doprint(const char *, va_list, char **);
34 static void _printn(uint64_t, int, int, int, char **);
35 
36 /*
37  * Emit character functions...
38  */
39 
40 static void
41 _pput_flush(char *start, char *end)
42 {
43 	while (prom_write(prom_stdout_ihandle(),
44 	    start, end - start, 0, BYTE) == -1)
45 		;
46 }
47 
48 static void
49 _sput(char c, char **p)
50 {
51 	**p = c;
52 	*p += 1;
53 }
54 
55 /*VARARGS1*/
56 void
57 prom_printf(const char *fmt, ...)
58 {
59 	va_list adx;
60 
61 	va_start(adx, fmt);
62 	_doprint(fmt, adx, (char **)0);
63 	va_end(adx);
64 }
65 
66 void
67 prom_vprintf(const char *fmt, va_list adx)
68 {
69 	_doprint(fmt, adx, (char **)0);
70 }
71 
72 /*VARARGS2*/
73 char *
74 prom_sprintf(char *s, const char *fmt, ...)
75 {
76 	char *bp = s;
77 	va_list adx;
78 
79 	va_start(adx, fmt);
80 	_doprint(fmt, adx, &bp);
81 	*bp++ = (char)0;
82 	va_end(adx);
83 	return (s);
84 }
85 
86 char *
87 prom_vsprintf(char *s, const char *fmt, va_list adx)
88 {
89 	char *bp = s;
90 
91 	_doprint(fmt, adx, &bp);
92 	*bp++ = (char)0;
93 	return (s);
94 }
95 
96 static void
97 _doprint(const char *fmt, va_list adx, char **bp)
98 {
99 	int b, c, i, pad, width, ells;
100 	char *s, *start;
101 	char localbuf[100], *lbp;
102 	int64_t l;
103 	uint64_t ul;
104 
105 	if (bp == 0) {
106 		bp = &lbp;
107 		lbp = &localbuf[0];
108 	}
109 	start = *bp;
110 loop:
111 	width = 0;
112 	while ((c = *fmt++) != '%') {
113 		if (c == '\0')
114 			goto out;
115 		if (c == '\n') {
116 			_sput('\r', bp);
117 			_sput('\n', bp);
118 			if (start == localbuf) {
119 				_pput_flush(start, *bp);
120 				lbp = &localbuf[0];
121 			}
122 		} else
123 			_sput((char)c, bp);
124 		if (start == localbuf && (*bp - start > 80)) {
125 			_pput_flush(start, *bp);
126 			lbp = &localbuf[0];
127 		}
128 	}
129 
130 	c = *fmt++;
131 	for (pad = ' '; c == '0'; c = *fmt++)
132 		pad = '0';
133 
134 	for (width = 0; c >= '0' && c <= '9'; c = *fmt++)
135 		width = width * 10 + c - '0';
136 
137 	for (ells = 0; c == 'l'; c = *fmt++)
138 		ells++;
139 
140 	switch (c) {
141 	case 'd':
142 	case 'D':
143 		b = 10;
144 		if (ells == 0)
145 			l = (int64_t)va_arg(adx, int);
146 		else if (ells == 1)
147 			l = (int64_t)va_arg(adx, long);
148 		else
149 			l = (int64_t)va_arg(adx, int64_t);
150 		if (l < 0) {
151 			_sput('-', bp);
152 			width--;
153 			ul = -l;
154 		} else
155 			ul = l;
156 		goto number;
157 
158 	case 'p':
159 		ells = 1;
160 		/*FALLTHROUGH*/
161 	case 'x':
162 	case 'X':
163 		b = 16;
164 		goto u_number;
165 
166 	case 'u':
167 		b = 10;
168 		goto u_number;
169 
170 	case 'o':
171 	case 'O':
172 		b = 8;
173 u_number:
174 		if (ells == 0)
175 			ul = (uint64_t)va_arg(adx, u_int);
176 		else if (ells == 1)
177 			ul = (uint64_t)va_arg(adx, u_long);
178 		else
179 			ul = (uint64_t)va_arg(adx, uint64_t);
180 number:
181 		_printn(ul, b, width, pad, bp);
182 		break;
183 
184 	case 'c':
185 		b = va_arg(adx, int);
186 		for (i = 24; i >= 0; i -= 8)
187 			if ((c = ((b >> i) & 0x7f)) != 0) {
188 				if (c == '\n')
189 					_sput('\r', bp);
190 				_sput((char)c, bp);
191 			}
192 		break;
193 
194 	case 's':
195 		s = va_arg(adx, char *);
196 		while ((c = *s++) != 0) {
197 			if (c == '\n')
198 				_sput('\r', bp);
199 			_sput((char)c, bp);
200 			if (start == localbuf && (*bp - start > 80)) {
201 				_pput_flush(start, *bp);
202 				lbp = &localbuf[0];
203 			}
204 		}
205 		break;
206 
207 	case '%':
208 		_sput('%', bp);
209 		break;
210 	}
211 	if (start == localbuf && (*bp - start > 80)) {
212 		_pput_flush(start, *bp);
213 		lbp = &localbuf[0];
214 	}
215 	goto loop;
216 out:
217 	if (start == localbuf && (*bp - start > 0))
218 		_pput_flush(start, *bp);
219 }
220 
221 /*
222  * Printn prints a number n in base b.
223  * We don't use recursion to avoid deep kernel stacks.
224  */
225 static void
226 _printn(uint64_t n, int b, int width, int pad, char **bp)
227 {
228 	char prbuf[40];
229 	char *cp;
230 
231 	cp = prbuf;
232 	do {
233 		*cp++ = "0123456789abcdef"[n%b];
234 		n /= b;
235 		width--;
236 	} while (n);
237 	while (width-- > 0)
238 		*cp++ = (char)pad;
239 	do {
240 		_sput(*--cp, bp);
241 	} while (cp > prbuf);
242 }
243