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