xref: /dragonfly/lib/libc/stdio/xprintf_int.c (revision 0085a56d)
1 /*-
2  * Copyright (c) 2005 Poul-Henning Kamp
3  * Copyright (c) 1990, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/lib/libc/stdio/xprintf_int.c,v 1.2 2005/12/22 14:23:54 cognet Exp $
34  */
35 
36 #include "namespace.h"
37 #include <err.h>
38 #include <sys/types.h>
39 #include <stddef.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <limits.h>
43 #include <locale.h>
44 #include <stdint.h>
45 #include <assert.h>
46 #include <string.h>
47 #include <wchar.h>
48 #include "un-namespace.h"
49 
50 #include "printf.h"
51 
52 /* private stuff -----------------------------------------------------*/
53 
54 union arg {
55 	int			intarg;
56 	u_int			uintarg;
57 	long			longarg;
58 	u_long			ulongarg;
59 	intmax_t 		intmaxarg;
60 	uintmax_t 		uintmaxarg;
61 };
62 
63 /*
64  * Macros for converting digits to letters and vice versa
65  */
66 #define	to_char(n)	((n) + '0')
67 
68 /* various globals ---------------------------------------------------*/
69 
70 /*
71  * The size of the buffer we use for integer conversions.
72  * Technically, we would need the most space for base 10
73  * conversions with thousands' grouping characters between
74  * each pair of digits: 60 digits for 128 bit intmax_t.
75  * Use a bit more for better alignment of stuff.
76  */
77 #define	BUF	64
78 
79 /* misc --------------------------------------------------------------*/
80 
81 /*
82  * Convert an unsigned long to ASCII for printf purposes, returning
83  * a pointer to the first character of the string representation.
84  * Octal numbers can be forced to have a leading zero; hex numbers
85  * use the given digits.
86  */
87 static char *
88 __ultoa(u_long val, char *endp, int base, const char *xdigs,
89 	int needgrp, char thousep, const char *grp)
90 {
91 	char *cp = endp;
92 	long sval;
93 	int ndig;
94 
95 	/*
96 	 * Handle the three cases separately, in the hope of getting
97 	 * better/faster code.
98 	 */
99 	switch (base) {
100 	case 10:
101 		if (val < 10) {	/* many numbers are 1 digit */
102 			*--cp = to_char(val);
103 			return (cp);
104 		}
105 		ndig = 0;
106 		/*
107 		 * On many machines, unsigned arithmetic is harder than
108 		 * signed arithmetic, so we do at most one unsigned mod and
109 		 * divide; this is sufficient to reduce the range of
110 		 * the incoming value to where signed arithmetic works.
111 		 */
112 		if (val > LONG_MAX) {
113 			*--cp = to_char(val % 10);
114 			ndig++;
115 			sval = val / 10;
116 		} else {
117 			sval = val;
118 		}
119 		do {
120 			*--cp = to_char(sval % 10);
121 			ndig++;
122 			/*
123 			 * If (*grp == CHAR_MAX) then no more grouping
124 			 * should be performed.
125 			 */
126 			if (needgrp && ndig == *grp && *grp != CHAR_MAX
127 					&& sval > 9) {
128 				*--cp = thousep;
129 				ndig = 0;
130 				/*
131 				 * If (*(grp+1) == '\0') then we have to
132 				 * use *grp character (last grouping rule)
133 				 * for all next cases
134 				 */
135 				if (*(grp+1) != '\0')
136 					grp++;
137 			}
138 			sval /= 10;
139 		} while (sval != 0);
140 		break;
141 
142 	case 8:
143 		do {
144 			*--cp = to_char(val & 7);
145 			val >>= 3;
146 		} while (val);
147 		break;
148 
149 	case 16:
150 		do {
151 			*--cp = xdigs[val & 15];
152 			val >>= 4;
153 		} while (val);
154 		break;
155 
156 	default:			/* oops */
157 		assert(base == 16);
158 	}
159 	return (cp);
160 }
161 
162 
163 /* Identical to __ultoa, but for intmax_t. */
164 static char *
165 __ujtoa(uintmax_t val, char *endp, int base, const char *xdigs,
166 	int needgrp, char thousep, const char *grp)
167 {
168 	char *cp = endp;
169 	intmax_t sval;
170 	int ndig;
171 
172 	switch (base) {
173 	case 10:
174 		if (val < 10) {
175 			*--cp = to_char(val % 10);
176 			return (cp);
177 		}
178 		ndig = 0;
179 		if (val > INTMAX_MAX) {
180 			*--cp = to_char(val % 10);
181 			ndig++;
182 			sval = val / 10;
183 		} else {
184 			sval = val;
185 		}
186 		do {
187 			*--cp = to_char(sval % 10);
188 			ndig++;
189 			/*
190 			 * If (*grp == CHAR_MAX) then no more grouping
191 			 * should be performed.
192 			 */
193 			if (needgrp && *grp != CHAR_MAX && ndig == *grp
194 					&& sval > 9) {
195 				*--cp = thousep;
196 				ndig = 0;
197 				/*
198 				 * If (*(grp+1) == '\0') then we have to
199 				 * use *grp character (last grouping rule)
200 				 * for all next cases
201 				 */
202 				if (*(grp+1) != '\0')
203 					grp++;
204 			}
205 			sval /= 10;
206 		} while (sval != 0);
207 		break;
208 
209 	case 8:
210 		do {
211 			*--cp = to_char(val & 7);
212 			val >>= 3;
213 		} while (val);
214 		break;
215 
216 	case 16:
217 		do {
218 			*--cp = xdigs[val & 15];
219 			val >>= 4;
220 		} while (val);
221 		break;
222 
223 	default:
224 		abort();
225 	}
226 	return (cp);
227 }
228 
229 
230 /* 'd' ---------------------------------------------------------------*/
231 
232 int
233 __printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt)
234 {
235 	assert (n > 0);
236 	argt[0] = PA_INT;
237 	if (pi->is_ptrdiff)
238 		argt[0] |= PA_FLAG_PTRDIFF;
239 	else if (pi->is_size)
240 		argt[0] |= PA_FLAG_SIZE;
241 	else if (pi->is_long)
242 		argt[0] |= PA_FLAG_LONG;
243 	else if (pi->is_intmax)
244 		argt[0] |= PA_FLAG_INTMAX;
245 	else if (pi->is_quad)
246 		argt[0] |= PA_FLAG_QUAD;
247 	else if (pi->is_long_double)
248 		argt[0] |= PA_FLAG_LONG_LONG;
249 	else if (pi->is_short)
250 		argt[0] |= PA_FLAG_SHORT;
251 	else if (pi->is_char)
252 		argt[0] = PA_CHAR;
253 	return (1);
254 }
255 
256 int
257 __printf_render_int(struct __printf_io *io, const struct printf_info *pi,
258 		    const void *const *arg)
259 {
260 	const union arg *argp;
261 	char buf[BUF];
262 	char *p, *pe;
263 	char ns, l;
264 	int rdx, sign, zext, ngrp;
265 	const char *nalt, *digit;
266 	char thousands_sep;	/* locale specific thousands separator */
267 	const char *grouping;	/* locale specific numeric grouping rules */
268 	uintmax_t uu;
269 	int ret;
270 
271 	ret = 0;
272 	nalt = NULL;
273 	digit = __lowercase_hex;
274 	ns = '\0';
275 	pe = buf + sizeof buf - 1;
276 
277 	if (pi->group) {
278 		thousands_sep = *(localeconv()->thousands_sep);
279 		grouping = localeconv()->grouping;
280 		ngrp = 1;
281 	} else {
282 		thousands_sep = 0;
283 		grouping = NULL;
284 		ngrp = 0;
285 	}
286 
287 	switch(pi->spec) {
288 	case 'd':
289 	case 'i':
290 		rdx = 10;
291 		sign = 1;
292 		break;
293 	case 'X':
294 		digit = __uppercase_hex;
295 		/*FALLTHOUGH*/
296 	case 'x':
297 		rdx = 16;
298 		sign = 0;
299 		break;
300 	case 'u':
301 	case 'U':
302 		rdx = 10;
303 		sign = 0;
304 		break;
305 	case 'o':
306 	case 'O':
307 		rdx = 8;
308 		sign = 0;
309 		break;
310 	default:
311 		fprintf(stderr, "pi->spec = '%c'\n", pi->spec);
312 		assert(1 == 0);
313 	}
314 	argp = arg[0];
315 
316 	if (sign)
317 		ns = pi->showsign;
318 
319 	if (pi->is_long_double || pi->is_quad || pi->is_intmax ||
320 	    pi->is_size || pi->is_ptrdiff) {
321 		if (sign && argp->intmaxarg < 0) {
322 			uu = -argp->intmaxarg;
323 			ns = '-';
324 		} else {
325 			uu = argp->uintmaxarg;
326 		}
327 	} else if (pi->is_long) {
328 		if (sign && argp->longarg < 0) {
329 			uu = (u_long)-argp->longarg;
330 			ns = '-';
331 		} else {
332 			uu = argp->ulongarg;
333 		}
334 	} else if (pi->is_short) {
335 		if (sign && (short)argp->intarg < 0) {
336 			uu = -(short)argp->intarg;
337 			ns = '-';
338 		} else {
339 			uu = (unsigned short)argp->uintarg;
340 		}
341 	} else if (pi->is_char) {
342 		if (sign && (signed char)argp->intarg < 0) {
343 			uu = -(signed char)argp->intarg;
344 			ns = '-';
345 		} else {
346 			uu = (unsigned char)argp->uintarg;
347 		}
348 	} else {
349 		if (sign && argp->intarg < 0) {
350 			uu = (unsigned)-argp->intarg;
351 			ns = '-';
352 		} else {
353 			uu = argp->uintarg;
354 		}
355 	}
356 	if (uu <= ULONG_MAX)
357 		p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
358 	else
359 		p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
360 
361 	l = 0;
362 	if (uu == 0) {
363 		/*-
364 		 * ``The result of converting a zero value with an
365 		 * explicit precision of zero is no characters.''
366 		 *      -- ANSI X3J11
367 		 *
368 		 * ``The C Standard is clear enough as is.  The call
369 		 * printf("%#.0o", 0) should print 0.''
370 		 *      -- Defect Report #151
371 		 */
372 		if (pi->prec == 0 && !(pi->alt && rdx == 8))
373 			p = pe;
374 	} else if (pi->alt) {
375 		if (rdx == 8)
376 			*--p = '0';
377 		if (rdx == 16) {
378 			if (pi->spec == 'x')
379 				nalt = "0x";
380 			else
381 				nalt = "0X";
382 			l += 2;
383 		}
384 	}
385 	l += pe - p;
386 	if (ns)
387 		l++;
388 
389 	/*-
390 	 * ``... diouXx conversions ... if a precision is
391 	 * specified, the 0 flag will be ignored.''
392 	 *      -- ANSI X3J11
393 	 */
394 	if (pi->prec > (pe - p))
395 		zext = pi->prec - (pe - p);
396 	else if (pi->prec != -1)
397 		zext = 0;
398 	else if (pi->pad == '0' && pi->width > l && !pi->left)
399 		zext = pi->width - l;
400 	else
401 		zext = 0;
402 
403 	l += zext;
404 
405 	while (zext > 0 && p > buf) {
406 		*--p = '0';
407 		zext--;
408 	}
409 
410 	if (l < BUF) {
411 		if (ns) {
412 			*--p = ns;
413 		} else if (nalt != NULL) {
414 			*--p = nalt[1];
415 			*--p = nalt[0];
416 		}
417 		if (pi->width > (pe - p) && !pi->left) {
418 			l = pi->width - (pe - p);
419 			while (l > 0 && p > buf) {
420 				*--p = ' ';
421 				l--;
422 			}
423 			if (l)
424 				ret += __printf_pad(io, l, 0);
425 		}
426 	} else {
427 		if (!pi->left && pi->width > l)
428 			ret += __printf_pad(io, pi->width - l, 0);
429 		if (ns != '\0')
430 			ret += __printf_puts(io, &ns, 1);
431 		else if (nalt != NULL)
432 			ret += __printf_puts(io, nalt, 2);
433 		if (zext > 0)
434 			ret += __printf_pad(io, zext, 1);
435 	}
436 
437 	ret += __printf_puts(io, p, pe - p);
438 	if (pi->width > ret && pi->left)
439 		ret += __printf_pad(io, pi->width - ret, 0);
440 	__printf_flush(io);
441 	return (ret);
442 }
443 
444 /* 'p' ---------------------------------------------------------------*/
445 
446 int
447 __printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt)
448 {
449 
450 	assert (n > 0);
451 	argt[0] = PA_POINTER;
452 	return (1);
453 }
454 
455 int
456 __printf_render_ptr(struct __printf_io *io, const struct printf_info *pi,
457 		    const void *const *arg)
458 {
459 	struct printf_info p2;
460 	uintmax_t u;
461 	const void *p;
462 
463 	/*-
464 	 * ``The argument shall be a pointer to void.  The
465 	 * value of the pointer is converted to a sequence
466 	 * of printable characters, in an implementation-
467 	 * defined manner.''
468 	 *      -- ANSI X3J11
469 	 */
470 	u = (uintmax_t)(uintptr_t) *((void **)arg[0]);
471 	p2 = *pi;
472 
473 	p2.spec = 'x';
474 	p2.alt = 1;
475 	p2.is_long_double = 1;
476 	p = &u;
477 	return (__printf_render_int(io, &p2, &p));
478 }
479