1*2c53affbSjmc /* $OpenBSD: gcvt.c,v 1.15 2022/12/27 17:10:06 jmc Exp $ */
280944f19Smillert
380944f19Smillert /*
4260966efSmillert * Copyright (c) 2002, 2003, 2006, 2010
5bf198cc6Smillert * Todd C. Miller <millert@openbsd.org>
680944f19Smillert *
706f01696Smillert * Permission to use, copy, modify, and distribute this software for any
806f01696Smillert * purpose with or without fee is hereby granted, provided that the above
906f01696Smillert * copyright notice and this permission notice appear in all copies.
1080944f19Smillert *
11328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18328f1f07Smillert *
19328f1f07Smillert * Sponsored in part by the Defense Advanced Research Projects
20328f1f07Smillert * Agency (DARPA) and Air Force Research Laboratory, Air Force
21328f1f07Smillert * Materiel Command, USAF, under agreement number F39502-99-1-0512.
2280944f19Smillert */
2380944f19Smillert
2445b391e8Smillert #include <locale.h>
2580944f19Smillert #include <stdio.h>
2680944f19Smillert #include <stdlib.h>
2780944f19Smillert #include <string.h>
28def3c8f6Sguenther #include "gdtoa.h"
2980944f19Smillert
30260966efSmillert #define DEFPREC 6
31260966efSmillert
3280944f19Smillert char *
gcvt(double value,int ndigit,char * buf)3380944f19Smillert gcvt(double value, int ndigit, char *buf)
3480944f19Smillert {
3580944f19Smillert char *digits, *dst, *src;
3680944f19Smillert int i, decpt, sign;
3745b391e8Smillert struct lconv *lconv;
3880944f19Smillert
3945b391e8Smillert lconv = localeconv();
40260966efSmillert if (ndigit <= 0) {
41260966efSmillert /* Match printf(3) behavior. */
42260966efSmillert ndigit = ndigit ? DEFPREC : 1;
4380944f19Smillert }
4480944f19Smillert
4580944f19Smillert digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL);
46384cfdc1Smartynas if (digits == NULL)
47384cfdc1Smartynas return (NULL);
48aed36ee6Smillert if (decpt == 9999) {
493a59a6c9Smillert /*
503a59a6c9Smillert * Infinity or NaN, convert to inf or nan with sign.
51260966efSmillert * We can't infer buffer size based on ndigit.
52260966efSmillert * We have to assume it is at least 5 chars.
533a59a6c9Smillert */
54260966efSmillert snprintf(buf, 5, "%s%s", sign ? "-" : "",
553a59a6c9Smillert *digits == 'I' ? "inf" : "nan");
5657536318Sderaadt __freedtoa(digits);
57aed36ee6Smillert return (buf);
58aed36ee6Smillert }
5980944f19Smillert
6080944f19Smillert dst = buf;
6180944f19Smillert if (sign)
6280944f19Smillert *dst++ = '-';
6380944f19Smillert
64*2c53affbSjmc /* Match printf(3) behavior for exponential vs. regular formatting. */
65260966efSmillert if (decpt <= -4 || decpt > ndigit) {
66df92a088Smillert /* exponential format (e.g. 1.2345e+13) */
6780944f19Smillert if (--decpt < 0) {
6880944f19Smillert sign = 1;
6980944f19Smillert decpt = -decpt;
7080944f19Smillert } else
7180944f19Smillert sign = 0;
72df92a088Smillert src = digits;
73df92a088Smillert *dst++ = *src++;
74260966efSmillert if (*src != '\0') {
7545b391e8Smillert *dst++ = *lconv->decimal_point;
76260966efSmillert do {
7780944f19Smillert *dst++ = *src++;
78260966efSmillert } while (*src != '\0');
79260966efSmillert }
8080944f19Smillert *dst++ = 'e';
8180944f19Smillert if (sign)
8280944f19Smillert *dst++ = '-';
8380944f19Smillert else
8480944f19Smillert *dst++ = '+';
8580944f19Smillert if (decpt < 10) {
8680944f19Smillert *dst++ = '0';
8780944f19Smillert *dst++ = '0' + decpt;
8880944f19Smillert *dst = '\0';
8980944f19Smillert } else {
9080944f19Smillert /* XXX - optimize */
9180944f19Smillert for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
92df92a088Smillert continue;
93df92a088Smillert dst[i + 1] = '\0';
9480944f19Smillert while (decpt != 0) {
9580944f19Smillert dst[i--] = '0' + decpt % 10;
9680944f19Smillert decpt /= 10;
9780944f19Smillert }
9880944f19Smillert }
9980944f19Smillert } else {
10080944f19Smillert /* standard format */
10180944f19Smillert for (i = 0, src = digits; i < decpt; i++) {
10280944f19Smillert if (*src != '\0')
10380944f19Smillert *dst++ = *src++;
10480944f19Smillert else
10580944f19Smillert *dst++ = '0';
10680944f19Smillert }
10780944f19Smillert if (*src != '\0') {
108df92a088Smillert if (src == digits)
109df92a088Smillert *dst++ = '0'; /* zero before decimal point */
11045b391e8Smillert *dst++ = *lconv->decimal_point;
111260966efSmillert while (decpt < 0) {
112260966efSmillert *dst++ = '0';
113260966efSmillert decpt++;
114260966efSmillert }
11580944f19Smillert for (i = decpt; digits[i] != '\0'; i++) {
11680944f19Smillert *dst++ = digits[i];
11780944f19Smillert }
11880944f19Smillert }
11980944f19Smillert *dst = '\0';
12080944f19Smillert }
12157536318Sderaadt __freedtoa(digits);
12280944f19Smillert return (buf);
12380944f19Smillert }
124