]> git.saurik.com Git - apple/libc.git/blame_incremental - stdio/FreeBSD/xprintf_int.c
Libc-997.1.1.tar.gz
[apple/libc.git] / stdio / FreeBSD / xprintf_int.c
... / ...
CommitLineData
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}