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