xref: /freebsd/lib/libc/stdio/xprintf_int.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
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 
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 <namespace.h>
47 #include <string.h>
48 #include <wchar.h>
49 #include <un-namespace.h>
50 
51 #include "printf.h"
52 
53 /* private stuff -----------------------------------------------------*/
54 
55 union arg {
56 	int			intarg;
57 	u_int			uintarg;
58 	long			longarg;
59 	u_long			ulongarg;
60 	intmax_t 		intmaxarg;
61 	uintmax_t 		uintmaxarg;
62 };
63 
64 /*
65  * Macros for converting digits to letters and vice versa
66  */
67 #define	to_char(n)	((n) + '0')
68 
69 /* various globals ---------------------------------------------------*/
70 
71 /*
72  * The size of the buffer we use for integer conversions.
73  * Technically, we would need the most space for base 10
74  * conversions with thousands' grouping characters between
75  * each pair of digits: 60 digits for 128 bit intmax_t.
76  * Use a bit more for better alignment of stuff.
77  */
78 #define	BUF	64
79 
80 /* misc --------------------------------------------------------------*/
81 
82 /*
83  * Convert an unsigned long to ASCII for printf purposes, returning
84  * a pointer to the first character of the string representation.
85  * Octal numbers can be forced to have a leading zero; hex numbers
86  * use the given digits.
87  */
88 static char *
89 __ultoa(u_long val, char *endp, int base, const char *xdigs,
90 	int needgrp, char thousep, const char *grp)
91 {
92 	char *cp = endp;
93 	long sval;
94 	int ndig;
95 
96 	/*
97 	 * Handle the three cases separately, in the hope of getting
98 	 * better/faster code.
99 	 */
100 	switch (base) {
101 	case 10:
102 		if (val < 10) {	/* many numbers are 1 digit */
103 			*--cp = to_char(val);
104 			return (cp);
105 		}
106 		ndig = 0;
107 		/*
108 		 * On many machines, unsigned arithmetic is harder than
109 		 * signed arithmetic, so we do at most one unsigned mod and
110 		 * divide; this is sufficient to reduce the range of
111 		 * the incoming value to where signed arithmetic works.
112 		 */
113 		if (val > LONG_MAX) {
114 			*--cp = to_char(val % 10);
115 			ndig++;
116 			sval = val / 10;
117 		} else
118 			sval = val;
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 		do {
186 			*--cp = to_char(sval % 10);
187 			ndig++;
188 			/*
189 			 * If (*grp == CHAR_MAX) then no more grouping
190 			 * should be performed.
191 			 */
192 			if (needgrp && *grp != CHAR_MAX && ndig == *grp
193 					&& sval > 9) {
194 				*--cp = thousep;
195 				ndig = 0;
196 				/*
197 				 * If (*(grp+1) == '\0') then we have to
198 				 * use *grp character (last grouping rule)
199 				 * for all next cases
200 				 */
201 				if (*(grp+1) != '\0')
202 					grp++;
203 			}
204 			sval /= 10;
205 		} while (sval != 0);
206 		break;
207 
208 	case 8:
209 		do {
210 			*--cp = to_char(val & 7);
211 			val >>= 3;
212 		} while (val);
213 		break;
214 
215 	case 16:
216 		do {
217 			*--cp = xdigs[val & 15];
218 			val >>= 4;
219 		} while (val);
220 		break;
221 
222 	default:
223 		abort();
224 	}
225 	return (cp);
226 }
227 
228 
229 /* 'd' ---------------------------------------------------------------*/
230 
231 int
232 __printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt)
233 {
234 	assert (n > 0);
235 	argt[0] = PA_INT;
236 	if (pi->is_ptrdiff)
237 		argt[0] |= PA_FLAG_PTRDIFF;
238 	else if (pi->is_size)
239 		argt[0] |= PA_FLAG_SIZE;
240 	else if (pi->is_long)
241 		argt[0] |= PA_FLAG_LONG;
242 	else if (pi->is_intmax)
243 		argt[0] |= PA_FLAG_INTMAX;
244 	else if (pi->is_quad)
245 		argt[0] |= PA_FLAG_QUAD;
246 	else if (pi->is_long_double)
247 		argt[0] |= PA_FLAG_LONG_LONG;
248 	else if (pi->is_short)
249 		argt[0] |= PA_FLAG_SHORT;
250 	else if (pi->is_char)
251 		argt[0] = PA_CHAR;
252 	return (1);
253 }
254 
255 int
256 __printf_render_int(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
257 {
258 	const union arg *argp;
259 	char buf[BUF];
260 	char *p, *pe;
261 	char ns;
262 	int l, ngrp, rdx, sign, zext;
263 	const char *nalt, *digit;
264 	char thousands_sep;	/* locale specific thousands separator */
265 	const char *grouping;	/* locale specific numeric grouping rules */
266 	uintmax_t uu;
267 	int ret;
268 
269 	ret = 0;
270 	nalt = NULL;
271 	digit = __lowercase_hex;
272 	ns = '\0';
273 	pe = buf + sizeof buf - 1;
274 
275 	if (pi->group) {
276 		thousands_sep = *(localeconv()->thousands_sep);
277 		grouping = localeconv()->grouping;
278 		ngrp = 1;
279 	} else {
280 		thousands_sep = 0;
281 		grouping = NULL;
282 		ngrp = 0;
283 	}
284 
285 	switch(pi->spec) {
286 	case 'd':
287 	case 'i':
288 		rdx = 10;
289 		sign = 1;
290 		break;
291 	case 'X':
292 		digit = __uppercase_hex;
293 		/*FALLTHOUGH*/
294 	case 'x':
295 		rdx = 16;
296 		sign = 0;
297 		break;
298 	case 'u':
299 	case 'U':
300 		rdx = 10;
301 		sign = 0;
302 		break;
303 	case 'o':
304 	case 'O':
305 		rdx = 8;
306 		sign = 0;
307 		break;
308 	default:
309 		fprintf(stderr, "pi->spec = '%c'\n", pi->spec);
310 		assert(1 == 0);
311 	}
312 	argp = arg[0];
313 
314 	if (sign)
315 		ns = pi->showsign;
316 
317 	if (pi->is_long_double || pi->is_quad || pi->is_intmax ||
318 	    pi->is_size || pi->is_ptrdiff) {
319 		if (sign && argp->intmaxarg < 0) {
320 			uu = -argp->intmaxarg;
321 			ns = '-';
322 		} else
323 			uu = argp->uintmaxarg;
324 	} else if (pi->is_long) {
325 		if (sign && argp->longarg < 0) {
326 			uu = (u_long)-argp->longarg;
327 			ns = '-';
328 		} else
329 			uu = argp->ulongarg;
330 	} else if (pi->is_short) {
331 		if (sign && (short)argp->intarg < 0) {
332 			uu = -(short)argp->intarg;
333 			ns = '-';
334 		} else
335 			uu = (unsigned short)argp->uintarg;
336 	} else if (pi->is_char) {
337 		if (sign && (signed char)argp->intarg < 0) {
338 			uu = -(signed char)argp->intarg;
339 			ns = '-';
340 		} else
341 			uu = (unsigned char)argp->uintarg;
342 	} else {
343 		if (sign && argp->intarg < 0) {
344 			uu = (unsigned)-argp->intarg;
345 			ns = '-';
346 		} else
347 			uu = argp->uintarg;
348 	}
349 	if (uu <= ULONG_MAX)
350 		p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
351 	else
352 		p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping);
353 
354 	l = 0;
355 	if (uu == 0) {
356 		/*-
357 		 * ``The result of converting a zero value with an
358 		 * explicit precision of zero is no characters.''
359 		 *      -- ANSI X3J11
360 		 *
361 		 * ``The C Standard is clear enough as is.  The call
362 		 * printf("%#.0o", 0) should print 0.''
363 		 *      -- Defect Report #151
364 		 */
365 			;
366 		if (pi->prec == 0 && !(pi->alt && rdx == 8))
367 			p = pe;
368 	} else if (pi->alt) {
369 		if (rdx == 8)
370 			*--p = '0';
371 		if (rdx == 16) {
372 			if (pi->spec == 'x')
373 				nalt = "0x";
374 			else
375 				nalt = "0X";
376 			l += 2;
377 		}
378 	}
379 	l += pe - p;
380 	if (ns)
381 		l++;
382 
383 	/*-
384 	 * ``... diouXx conversions ... if a precision is
385 	 * specified, the 0 flag will be ignored.''
386 	 *      -- ANSI X3J11
387 	 */
388 	if (pi->prec > (pe - p))
389 		zext = pi->prec - (pe - p);
390 	else if (pi->prec != -1)
391 		zext = 0;
392 	else if (pi->pad == '0' && pi->width > l && !pi->left)
393 		zext = pi->width - l;
394 	else
395 		zext = 0;
396 
397 	l += zext;
398 
399 	while (zext > 0 && p > buf) {
400 		*--p = '0';
401 		zext--;
402 	}
403 
404 	if (l < BUF) {
405 		if (ns) {
406 			*--p = ns;
407 		} else if (nalt != NULL) {
408 			*--p = nalt[1];
409 			*--p = nalt[0];
410 		}
411 		if (pi->width > (pe - p) && !pi->left) {
412 			l = pi->width - (pe - p);
413 			while (l > 0 && p > buf) {
414 				*--p = ' ';
415 				l--;
416 			}
417 			if (l)
418 				ret += __printf_pad(io, l, 0);
419 		}
420 	} else {
421 		if (!pi->left && pi->width > l)
422 			ret += __printf_pad(io, pi->width - l, 0);
423 		if (ns != '\0')
424 			ret += __printf_puts(io, &ns, 1);
425 		else if (nalt != NULL)
426 			ret += __printf_puts(io, nalt, 2);
427 		if (zext > 0)
428 			ret += __printf_pad(io, zext, 1);
429 	}
430 
431 	ret += __printf_puts(io, p, pe - p);
432 	if (pi->width > ret && pi->left)
433 		ret += __printf_pad(io, pi->width - ret, 0);
434 	__printf_flush(io);
435 	return (ret);
436 }
437 
438 /* 'p' ---------------------------------------------------------------*/
439 
440 int
441 __printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt)
442 {
443 
444 	assert (n > 0);
445 	argt[0] = PA_POINTER;
446 	return (1);
447 }
448 
449 int
450 __printf_render_ptr(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
451 {
452 	struct printf_info p2;
453 	uintmax_t u;
454 	const void *p;
455 
456 	/*-
457 	 * ``The argument shall be a pointer to void.  The
458 	 * value of the pointer is converted to a sequence
459 	 * of printable characters, in an implementation-
460 	 * defined manner.''
461 	 *      -- ANSI X3J11
462 	 */
463 	u = (uintmax_t)(uintptr_t) *((void **)arg[0]);
464 	p2 = *pi;
465 
466 	p2.spec = 'x';
467 	p2.alt = 1;
468 	p2.is_long_double = 1;
469 	p = &u;
470 	return (__printf_render_int(io, &p2, &p));
471 }
472