1/* $OpenBSD: gcvt.c,v 1.11 2009/10/16 12:15:03 martynas 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 28extern char *__dtoa(double, int, int, int *, int *, char **); 29extern void __freedtoa(char *); 30 31char * 32gcvt(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 (digits == NULL) 46 return (NULL); 47 if (decpt == 9999) { 48 /* 49 * Infinity or NaN, convert to inf or nan with sign. 50 * We assume the buffer is at least ndigit long. 51 */ 52 snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "", 53 *digits == 'I' ? "inf" : "nan"); 54 __freedtoa(digits); 55 return (buf); 56 } 57 58 dst = buf; 59 if (sign) 60 *dst++ = '-'; 61 62 if (decpt < 0 || decpt > ndigit) { 63 /* exponential format (e.g. 1.2345e+13) */ 64 if (--decpt < 0) { 65 sign = 1; 66 decpt = -decpt; 67 } else 68 sign = 0; 69 src = digits; 70 *dst++ = *src++; 71 dst = stpcpy(dst, lconv->decimal_point); 72 while (*src != '\0') 73 *dst++ = *src++; 74 *dst++ = 'e'; 75 if (sign) 76 *dst++ = '-'; 77 else 78 *dst++ = '+'; 79 if (decpt < 10) { 80 *dst++ = '0'; 81 *dst++ = '0' + decpt; 82 *dst = '\0'; 83 } else { 84 /* XXX - optimize */ 85 for (sign = decpt, i = 0; (sign /= 10) != 0; i++) 86 continue; 87 dst[i + 1] = '\0'; 88 while (decpt != 0) { 89 dst[i--] = '0' + decpt % 10; 90 decpt /= 10; 91 } 92 } 93 } else { 94 /* standard format */ 95 for (i = 0, src = digits; i < decpt; i++) { 96 if (*src != '\0') 97 *dst++ = *src++; 98 else 99 *dst++ = '0'; 100 } 101 if (*src != '\0') { 102 if (src == digits) 103 *dst++ = '0'; /* zero before decimal point */ 104 dst = stpcpy(dst, lconv->decimal_point); 105 for (i = decpt; digits[i] != '\0'; i++) { 106 *dst++ = digits[i]; 107 } 108 } 109 *dst = '\0'; 110 } 111 __freedtoa(digits); 112 return (buf); 113} 114