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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <limits.h>
43 extern short putoctal;
44 /*
45 * This version of printf is compatible with the Version 7 C
46 * printf. The differences are only minor except that
47 * viprintf assumes it is to print through putchar. Version 7
48 * printf is more general (and is much larger) and includes
49 * provisions for floating point.
50 */
51
52
53 #define MAXOCT 11 /* Maximum octal digits in a long */
54 #define MAXINT 32767 /* largest normal length positive integer */
55 #define BIG 1000000000 /* largest power of 10 less than an unsigned long */
56 #define MAXDIGS 10 /* number of digits in BIG */
57
58 static int width, sign, fill;
59
60 unsigned char *_p_dconv();
61 void _p_emit(unsigned char *, unsigned char *);
62
63 /*VARARGS*/
64 void
viprintf(unsigned char * fmt,...)65 viprintf(unsigned char *fmt, ...)
66 {
67 va_list ap;
68 unsigned char fcode;
69 wchar_t wfcode;
70 int prec;
71 int length,mask1,nbits,n;
72 int length2;
73 long int mask2, num;
74 unsigned char *bptr;
75 unsigned char *ptr;
76 unsigned char buf[134];
77
78 va_start(ap, fmt);
79 for (;;) {
80 /* process format string first */
81 for (;;) {
82 length2 = mbtowc(&wfcode, (char *)fmt, MB_LEN_MAX);
83 if(length2 <= 0) {
84 if (*fmt == '\0') {
85 fmt++;
86 return;
87 }
88 putchar(*fmt++);
89 } else {
90 if (wfcode == '%') {
91 fmt++;
92 break;
93 }
94 /* ordinary (non-%) character */
95 putchar(wfcode);
96 fmt += length2;
97 }
98 }
99 /* length modifier: -1 for h, 1 for l, 0 for none */
100 length = 0;
101 /* check for a leading - sign */
102 sign = 0;
103 if (*fmt == '-') {
104 sign++;
105 fmt++;
106 }
107 /* a '0' may follow the - sign */
108 /* this is the requested fill character */
109 fill = 1;
110 if (*fmt == '0') {
111 fill--;
112 fmt++;
113 }
114
115 /* Now comes a digit string which may be a '*' */
116 if (*fmt == '*') {
117 width = va_arg(ap, int);
118 if (width < 0) {
119 width = -width;
120 sign = !sign;
121 }
122 fmt++;
123 }
124 else {
125 width = 0;
126 while (*fmt>='0' && *fmt<='9')
127 width = width * 10 + (*fmt++ - '0');
128 }
129
130 /* maybe a decimal point followed by more digits (or '*') */
131 if (*fmt=='.') {
132 if (*++fmt == '*') {
133 prec = va_arg(ap, int);
134 fmt++;
135 }
136 else {
137 prec = 0;
138 while (*fmt>='0' && *fmt<='9')
139 prec = prec * 10 + (*fmt++ - '0');
140 }
141 }
142 else
143 prec = -1;
144
145 /*
146 * At this point, "sign" is nonzero if there was
147 * a sign, "fill" is 0 if there was a leading
148 * zero and 1 otherwise, "width" and "prec"
149 * contain numbers corresponding to the digit
150 * strings before and after the decimal point,
151 * respectively, and "fmt" addresses the next
152 * character after the whole mess. If there was
153 * no decimal point, "prec" will be -1.
154 */
155 switch (*fmt) {
156 case 'L':
157 case 'l':
158 length = 2;
159 /* FALLTHROUGH */
160 case 'h':
161 case 'H':
162 length--;
163 fmt++;
164 break;
165 }
166
167 /*
168 * At exit from the following switch, we will
169 * emit the characters starting at "bptr" and
170 * ending at "ptr"-1, unless fcode is '\0'.
171 */
172 switch (fcode = *fmt++) {
173 /* process characters and strings first */
174 case 'c':
175 buf[0] = va_arg(ap, int);
176 ptr = bptr = &buf[0];
177 if (buf[0] != '\0')
178 ptr++;
179 break;
180 case 's':
181 bptr = va_arg(ap,unsigned char *);
182 if (bptr==0)
183 bptr = (unsigned char *)"(null pointer)";
184 if (prec < 0)
185 prec = MAXINT;
186 for (n=0; *bptr++ && n < prec; n++) ;
187 ptr = --bptr;
188 bptr -= n;
189 break;
190 case 'O':
191 length = 1;
192 fcode = 'o';
193 /* FALLTHROUGH */
194 case 'o':
195 case 'X':
196 case 'x':
197 if (length > 0)
198 num = va_arg(ap,long);
199 else
200 num = (unsigned)va_arg(ap,int);
201 if (fcode=='o') {
202 mask1 = 0x7;
203 mask2 = 0x1fffffffL;
204 nbits = 3;
205 }
206 else {
207 mask1 = 0xf;
208 mask2 = 0x0fffffffL;
209 nbits = 4;
210 }
211 n = (num!=0);
212 bptr = buf + MAXOCT + 3;
213 /* shift and mask for speed */
214 do
215 if (((int) num & mask1) < 10)
216 *--bptr = ((int) num & mask1) + 060;
217 else
218 *--bptr = ((int) num & mask1) + 0127;
219 while (num = (num >> nbits) & mask2);
220
221 if (fcode=='o') {
222 if (n)
223 *--bptr = '0';
224 }
225 else
226 if (!sign && fill <= 0) {
227 putchar('0');
228 putchar(fcode);
229 width -= 2;
230 }
231 else {
232 *--bptr = fcode;
233 *--bptr = '0';
234 }
235 ptr = buf + MAXOCT + 3;
236 break;
237 case 'D':
238 case 'U':
239 case 'I':
240 length = 1;
241 fcode = fcode + 'a' - 'A';
242 /* FALLTHROUGH */
243 case 'd':
244 case 'i':
245 case 'u':
246 if (length > 0)
247 num = va_arg(ap,long);
248 else {
249 n = va_arg(ap,int);
250 if (fcode=='u')
251 num = (unsigned) n;
252 else
253 num = (long) n;
254 }
255 if (n = (fcode != 'u' && num < 0))
256 num = -num;
257 /* now convert to digits */
258 bptr = _p_dconv(num, buf);
259 if (n)
260 *--bptr = '-';
261 if (fill == 0)
262 fill = -1;
263 ptr = buf + MAXDIGS + 1;
264 break;
265 default:
266 /* not a control character,
267 * print it.
268 */
269 ptr = bptr = &fcode;
270 ptr++;
271 break;
272 }
273 if (fcode != '\0')
274 _p_emit(bptr,ptr);
275 }
276 va_end(ap);
277 }
278
279 /* _p_dconv converts the unsigned long integer "value" to
280 * printable decimal and places it in "buffer", right-justified.
281 * The value returned is the address of the first non-zero character,
282 * or the address of the last character if all are zero.
283 * The result is NOT null terminated, and is MAXDIGS characters long,
284 * starting at buffer[1] (to allow for insertion of a sign).
285 *
286 * This program assumes it is running on 2's complement machine
287 * with reasonable overflow treatment.
288 */
289 unsigned char *
_p_dconv(value,buffer)290 _p_dconv(value, buffer)
291 long value;
292 unsigned char *buffer;
293 {
294 unsigned char *bp;
295 int svalue;
296 int n;
297 long lval;
298
299 bp = buffer;
300
301 /* zero is a special case */
302 if (value == 0) {
303 bp += MAXDIGS;
304 *bp = '0';
305 return(bp);
306 }
307
308 /* develop the leading digit of the value in "n" */
309 n = 0;
310 while (value < 0) {
311 value -= BIG; /* will eventually underflow */
312 n++;
313 }
314 while ((lval = value - BIG) >= 0) {
315 value = lval;
316 n++;
317 }
318
319 /* stash it in buffer[1] to allow for a sign */
320 bp[1] = n + '0';
321 /*
322 * Now develop the rest of the digits. Since speed counts here,
323 * we do it in two loops. The first gets "value" down until it
324 * is no larger than MAXINT. The second one uses integer divides
325 * rather than long divides to speed it up.
326 */
327 bp += MAXDIGS + 1;
328 while (value > MAXINT) {
329 *--bp = (int)(value % 10) + '0';
330 value /= 10;
331 }
332
333 /* cannot lose precision */
334 svalue = value;
335 while (svalue > 0) {
336 *--bp = (svalue % 10) + '0';
337 svalue /= 10;
338 }
339
340 /* fill in intermediate zeroes if needed */
341 if (buffer[1] != '0') {
342 while (bp > buffer + 2)
343 *--bp = '0';
344 --bp;
345 }
346 return(bp);
347 }
348
349 /*
350 * This program sends string "s" to putchar. The character after
351 * the end of "s" is given by "send". This allows the size of the
352 * field to be computed; it is stored in "alen". "width" contains the
353 * user specified length. If width<alen, the width will be taken to
354 * be alen. "sign" is zero if the string is to be right-justified
355 * in the field, nonzero if it is to be left-justified. "fill" is
356 * 0 if the string is to be padded with '0', positive if it is to be
357 * padded with ' ', and negative if an initial '-' should appear before
358 * any padding in right-justification (to avoid printing "-3" as
359 * "000-3" where "-0003" was intended).
360 */
361 void
_p_emit(unsigned char * s,unsigned char * send)362 _p_emit(unsigned char *s, unsigned char *send)
363 {
364 unsigned char cfill;
365 int alen;
366 int npad, length;
367 wchar_t wchar;
368
369 alen = send - s;
370 if (alen > width)
371 width = alen;
372 cfill = fill>0? ' ': '0';
373
374 /* we may want to print a leading '-' before anything */
375 if (*s == '-' && fill < 0) {
376 putchar(*s++);
377 alen--;
378 width--;
379 }
380 npad = width - alen;
381
382 /* emit any leading pad characters */
383 if (!sign)
384 while (--npad >= 0)
385 putchar(cfill);
386
387 /* emit the string itself */
388 while (--alen >= 0) {
389 length = mbtowc(&wchar, (char *)s, MB_LEN_MAX);
390 if(length <= 0) {
391 putoctal = 1;
392 putchar((unsigned char)*s++);
393 putoctal = 0;
394 } else {
395 putchar(wchar);
396 s += length;
397 alen = alen - length + 1;
398 }
399 }
400 /* emit trailing pad characters */
401 if (sign)
402 while (--npad >= 0)
403 putchar(cfill);
404 }
405