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