1 /* $OpenBSD: gcvt.c,v 1.10 2006/10/29 18:45:56 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2003, 2006 Todd C. Miller <Todd.Miller@courtesan.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * Sponsored in part by the Defense Advanced Research Projects 19 * Agency (DARPA) and Air Force Research Laboratory, Air Force 20 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 21 */ 22 23 #include <locale.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 extern char *__dtoa(double, int, int, int *, int *, char **); 29 extern void __freedtoa(char *); 30 31 char * 32 gcvt(double value, int ndigit, char *buf) 33 { 34 char *digits, *dst, *src; 35 int i, decpt, sign; 36 struct lconv *lconv; 37 38 lconv = localeconv(); 39 if (ndigit == 0) { 40 buf[0] = '\0'; 41 return (buf); 42 } 43 44 digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL); 45 if (decpt == 9999) { 46 /* 47 * Infinity or NaN, convert to inf or nan with sign. 48 * We assume the buffer is at least ndigit long. 49 */ 50 snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "", 51 *digits == 'I' ? "inf" : "nan"); 52 __freedtoa(digits); 53 return (buf); 54 } 55 56 dst = buf; 57 if (sign) 58 *dst++ = '-'; 59 60 if (decpt < 0 || decpt > ndigit) { 61 /* exponential format (e.g. 1.2345e+13) */ 62 if (--decpt < 0) { 63 sign = 1; 64 decpt = -decpt; 65 } else 66 sign = 0; 67 src = digits; 68 *dst++ = *src++; 69 *dst++ = *lconv->decimal_point; 70 while (*src != '\0') 71 *dst++ = *src++; 72 *dst++ = 'e'; 73 if (sign) 74 *dst++ = '-'; 75 else 76 *dst++ = '+'; 77 if (decpt < 10) { 78 *dst++ = '0'; 79 *dst++ = '0' + decpt; 80 *dst = '\0'; 81 } else { 82 /* XXX - optimize */ 83 for (sign = decpt, i = 0; (sign /= 10) != 0; i++) 84 continue; 85 dst[i + 1] = '\0'; 86 while (decpt != 0) { 87 dst[i--] = '0' + decpt % 10; 88 decpt /= 10; 89 } 90 } 91 } else { 92 /* standard format */ 93 for (i = 0, src = digits; i < decpt; i++) { 94 if (*src != '\0') 95 *dst++ = *src++; 96 else 97 *dst++ = '0'; 98 } 99 if (*src != '\0') { 100 if (src == digits) 101 *dst++ = '0'; /* zero before decimal point */ 102 *dst++ = *lconv->decimal_point; 103 for (i = decpt; digits[i] != '\0'; i++) { 104 *dst++ = digits[i]; 105 } 106 } 107 *dst = '\0'; 108 } 109 __freedtoa(digits); 110 return (buf); 111 } 112