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