standards/51292: [PATCH] add ecvt()/fcvt()/gcvt() functions (SUSv3)

Sergey A.Osokin osa at FreeBSD.org.ru
Tue Apr 22 13:30:10 PDT 2003


>Number:         51292
>Category:       standards
>Synopsis:       [PATCH] add ecvt()/fcvt()/gcvt() functions (SUSv3)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 22 13:30:06 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Sergey A. Osokin
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
n/a
>Environment:
System: FreeBSD 5.0-CURRENT i386


>Description:
	add ecvt()/fcvt()/gcvt() functions (SUSv3) (obtained from OpenBSD)
	+ add locale-specific tricks
>How-To-Repeat:
>Fix:

Index: src/lib/libc/stdlib/Makefile.inc
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdlib/Makefile.inc,v
retrieving revision 1.45
diff -u -r1.45 Makefile.inc
--- src/lib/libc/stdlib/Makefile.inc	5 Apr 2003 07:33:46 -0000	1.45
+++ src/lib/libc/stdlib/Makefile.inc	22 Apr 2003 16:44:44 -0000
@@ -5,13 +5,13 @@
 .PATH: ${.CURDIR}/${MACHINE_ARCH}/stdlib ${.CURDIR}/stdlib
 
 MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
-	bsearch.c calloc.c div.c exit.c getenv.c getopt.c getopt_long.c \
-	getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
-	insque.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c merge.c \
-	putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c reallocf.c \
-	realpath.c remque.c setenv.c strfmon.c strhash.c strtoimax.c \
-	strtol.c strtoll.c strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c \
-	system.c tdelete.c tfind.c tsearch.c twalk.c
+	bsearch.c calloc.c div.c exit.c ecvt.c gcvt.c getenv.c getopt.c \
+	getopt_long.c getsubopt.c grantpt.c hcreate.c heapsort.c imaxabs.c \
+	imaxdiv.c insque.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \
+	merge.c putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c \
+	reallocf.c realpath.c remque.c setenv.c strfmon.c strhash.c \
+	strtoimax.c strtol.c strtoll.c strtoq.c strtoul.c strtoull.c \
+	strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
 
 # machine-dependent stdlib sources
 .if exists(${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc)
@@ -19,12 +19,13 @@
 .endif
 
 MAN+=	abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
-	div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 grantpt.3 \
-	hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
-	lsearch.3 malloc.3 memory.3 qsort.3 radixsort.3 rand.3 random.3 \
+	div.3 ecvt.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \
+	grantpt.3 hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 \
+	lldiv.3 lsearch.3 malloc.3 memory.3 qsort.3 radixsort.3 rand.3 random.3 \
 	realpath.3 strfmon.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3
 
 MLINKS+=atol.3 atoll.3
+MLINKS+=ecvt.3 fcvt.3 ecvt.3 gcvt.3
 MLINKS+=exit.3 _Exit.3
 MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
 MLINKS+=grantpt.3 posix_openpt.3 grantpt.3 ptsname.3 grantpt.3 unlockpt.3
--- /dev/null	Tue Apr 22 14:58:19 2003
+++ src/lib/libc/stdlib/ecvt.3	Tue Apr 22 16:49:38 2003
@@ -0,0 +1,174 @@
+.\" $OpenBSD
+.\"
+.\" Copyright (c) 2002 Todd C. Miller <Todd.Miller at courtesan.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd April 22, 2003
+.Dt ECVT 3
+.Os
+.Sh NAME
+.Nm ecvt ,
+.Nm fcvt ,
+.Nm gcvt
+.Nd convert double to
+.Tn ASCII
+string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Ft char *
+.Fn ecvt "double value" "int ndigit" "int *decpt" "int *sign"
+.Ft char *
+.Fn fcvt "double value" "int ndigit" "int *decpt" "int *sign"
+.Ft char *
+.Fn gcvt "double value" "int ndigit" "char *buf"
+.Sh DESCRIPTION
+.Bf -symbolic
+These functions are provided for compatibility with legacy code.
+New code should use the
+.Xr snprintf 3
+function for improved safety and portability.
+.Ef
+.Pp
+The
+.Fn ecvt ,
+.Fn fcvt
+and
+.Fn gcvt
+functions convert the double precision floating-point number
+.Fa value
+to a NUL-terminated
+.Tn ASCII
+string.
+.Pp
+The
+.Fn ecvt
+function converts
+.Fa value
+to a NUL-terminated string of exactly
+.Fa ndigit
+digits and returns a pointer to that string.
+The result is padded with zeroes from left to right as needed.
+There are no leading zeroes unless
+.Fa value
+itself is 0.
+The least significant digit is rounded in an implementation-dependent manner.
+The position of the decimal point relative to the beginning of the string
+is stored in
+.Fa decpt .
+A negative value indicates that the decimal point is located
+to the left of the returned digits (this occurs when there is no
+whole number component to
+.Fa value ) .
+If
+.Fa value
+is zero, it is unspecified whether the integer pointed to by
+.Fa decpt
+will be 0 or 1.
+The decimal point itself is not included in the returned string.
+If the sign of the result is negative, the integer pointed to by
+.Fa sign
+is non-zero; otherwise, it is 0.
+.Pp
+If the converted value is out of range or is not representable,
+the contents of the returned string are unspecified.
+.Pp
+The
+.Fn fcvt
+function is identical to
+.Fn ecvt
+with the exception that
+.Fa ndigit
+specifies the number of digits after the decimal point (zero-padded as
+needed).
+.Pp
+The
+.Fn gcvt
+function converts
+.Fa value
+to a NUL-terminated string similar to the %g
+.Xr printf 3
+format specifier and stores the result in
+.Fa buf .
+It produces
+.Fa ndigit
+significant digits similar to the %f
+.Xr printf 3
+format specifier where possible.
+If
+.Fa ndigit 
+does allow sufficient precision, the result is stored in
+exponential notation similar to the %e
+.Xr printf 3
+format specifier.
+If
+.Fa value
+is less than zero,
+.Fa buf
+will be prefixed with a minus sign.
+A decimal point is included in the returned string if
+.Fa value
+is not a whole number.
+Unlike the
+.Fn ecvt
+and
+.Fn fcvt
+functions,
+.Fa buf
+is not zero-padded.
+.Sh RETURN VALUES
+The
+.Fn ecvt ,
+.Fn fcvt
+and
+.Fn gcvt
+functions return a NUL-terminated string representation of
+.Fa value .
+.Sh WARNINGS
+The
+.Fn ecvt
+and
+.Fn fcvt
+functions return a pointer to internal storage space that will be
+overwritten by subsequent calls to either function.
+.Pp
+The maximum possible precision of the return value is limited by the
+precision of a double and may not be the same on all architectures.
+.Pp
+The
+.Xr snprintf 3
+function is preferred over these functions for new code.
+.Sh SEE ALSO
+.Xr printf 3 ,
+.Xr strtod 3
+.Sh STANDARDS
+The
+.Fn ecvt ,
+.Fn fcvt
+and
+.Fn gcvt
+functions conform to
+.St -susv3 .
--- /dev/null	Tue Apr 22 14:58:19 2003
+++ src/lib/libc/stdlib/ecvt.c	Tue Apr 22 17:52:36 2003
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller at courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: ecvt.c,v 1.1 2002/12/02 15:38:54 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char *__dtoa(double, int, int, int *, int *, char **);
+static char *__cvt(double, int, int *, int *, int, int);
+
+static char *
+__cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
+{
+	static char 	*s;
+	char 		*p, *rve;
+	size_t 		siz;
+
+	if (ndigit == 0) {
+		*sign = value < 0.0;
+		*decpt = 0;
+		return ("");
+	}
+
+	if (s) {
+		free(s);
+		s = NULL;
+	}
+
+	if (ndigit < 0)
+		siz = -ndigit + 1;
+	else
+		siz = ndigit + 1;
+
+
+	/* __dtoa() doesn't allocate space for 0 so we do it by hand */
+	if (value == 0.0) {
+		*decpt = 1 - fmode;	/* 1 for 'e', 0 for 'f' */
+		*sign = 0;
+		if ((rve = s = (char *)malloc(siz)) == NULL)
+			return(NULL);
+		*rve++ = '0';
+		*rve = '\0';
+	} else {
+		p = __dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
+		if (*decpt == 9999) {
+			/* Nan or Infinity */
+			*decpt = 0;
+			return(p);
+		}
+		/* make a local copy and adjust rve to be in terms of s */
+		if (pad && fmode)
+			siz += *decpt;
+		if ((s = (char *)malloc(siz)) == NULL)
+			return(NULL);
+		(void) strlcpy(s, p, siz);
+		rve = s + (rve - p);
+	}
+
+	/* Add trailing zeros (unless we got NaN or Inf) */
+	if (pad && *decpt != 9999) {
+		siz -= rve - s;
+		while (--siz)
+			*rve++ = '0';
+		*rve = '\0';
+	}
+
+	return(s);
+}
+
+char *
+ecvt(double value, int ndigit, int *decpt, int *sign)
+{
+	return(__cvt(value, ndigit, decpt, sign, 0, 1));
+}
+
+char *
+fcvt(double value, int ndigit, int *decpt, int *sign)
+{
+	return(__cvt(value, ndigit, decpt, sign, 1, 1));
+}
--- /dev/null	Tue Apr 22 14:58:19 2003
+++ src/lib/libc/stdlib/gcvt.c	Tue Apr 22 20:42:51 2003
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller at courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: gcvt.c,v 1.2 2003/04/02 02:43:50 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+__FBSDID("$FreeBSD$");
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../locale/setlocale.h"	/* for ENCODING_LEN */
+
+extern char *__dtoa(double, int, int, int *, int *, char **);
+
+char *
+gcvt(double value, int ndigit, char *buf)
+{
+	char *digits, *dst, *src;
+	int i, decpt, sign;
+	char *lang;
+	struct lconv *lc:
+
+	if (ndigit == 0) {
+		buf[0] = '\0';
+		return (buf);
+	}
+
+	lang = getenv("LANG");
+
+	if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
+	    (lang[0] == '.' &&
+             (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
+            strchr(lang, '/') != NULL)
+		lang = "C";
+
+	if (setlocale(LC_ALL, lang) == NULL)
+		setlocale(LC_ALL, NULL);
+
+	lc = localeconv();
+
+	digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL);
+	if (decpt == 9999) {
+		/* Infinity or NaN, assume buffer is at least ndigit long. */
+		strlcpy(buf, digits, ndigit);
+		return (buf);
+	}
+
+	dst = buf;
+	if (sign)
+		*dst++ = (*lc->negative_sign == '\0') ? '-'
+		    : *lc->negative_sign;
+
+	if (decpt < 0 || decpt > ndigit) {
+		/* exponential format */
+		if (--decpt < 0) {
+			sign = 1;
+			decpt = -decpt;
+		} else
+			sign = 0;
+		for (src = digits; *src != '\0'; )
+			*dst++ = *src++;
+		*dst++ = 'e';
+		if (sign)
+			*dst++ = (*lc->negative_sign == '\0') ? '-'
+			    : *lc->negative_sign;
+		else
+			*dst++ = (*lc->positive_sign == '\0') ? '+'
+			    : *lc->positive_sign;
+		if (decpt < 10) {
+			*dst++ = '0';
+			*dst++ = '0' + decpt;
+			*dst = '\0';
+		} else {
+			/* XXX - optimize */
+			for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
+				sign /= 10;
+			while (decpt != 0) {
+				dst[i--] = '0' + decpt % 10;
+				decpt /= 10;
+			}
+		}
+	} else {
+		/* standard format */
+		for (i = 0, src = digits; i < decpt; i++) {
+			if (*src != '\0')
+				*dst++ = *src++;
+			else
+				*dst++ = '0';
+		}
+		if (*src != '\0') {
+			*dst++ = (*lc->decimal_point == '\0' ? '.'
+			    : *lc->decimal_point;
+			for (i = decpt; digits[i] != '\0'; i++) {
+				*dst++ = digits[i];
+			}
+		}
+		*dst = '\0';
+	}
+	return (buf);
+}
Index: src/include/stdlib.h
===================================================================
RCS file: /home/ncvs/src/include/stdlib.h,v
retrieving revision 1.48
diff -u -r1.48 stdlib.h
--- src/include/stdlib.h	12 Mar 2003 20:29:58 -0000	1.48
+++ src/include/stdlib.h	22 Apr 2003 16:44:45 -0000
@@ -176,10 +176,10 @@
 /* XXX XSI requires pollution from <sys/wait.h> here.  We'd rather not. */
 /* long	 a64l(const char *); */
 double	 drand48(void);
-/* char	*ecvt(double, int, int * __restrict, int * __restrict); */
+char	*ecvt(double, int, int * __restrict, int * __restrict);
 double	 erand48(unsigned short[3]);
-/* char	*fcvt(double, int, int * __restrict, int * __restrict); */
-/* char	*gcvt(double, int, int * __restrict, int * __restrict); */
+char	*fcvt(double, int, int * __restrict, int * __restrict);
+char	*gcvt(double, int, char *);
 #ifndef _GETSUBOPT_DECLARED
 int	 getsubopt(char **, char *const *, char **);
 #define	_GETSUBOPT_DECLARED
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-standards mailing list