From 257551c6a0c7362d6eaf18bdee22e67e77023ebf Mon Sep 17 00:00:00 2001 From: Tom Rhodes Date: Sat, 24 Dec 2005 22:37:59 +0000 Subject: [PATCH] Add a64l(), l64a(), and l64a_r() XSI extentions. These functions convert between a 32-bit integer and a radix-64 ASCII string. The l64a_r() function is a NetBSD addition. PR: 51209 (based on submission, but very different) Reviewed by: bde, ru --- include/stdlib.h | 5 +- lib/libc/stdlib/Makefile.inc | 11 ++- lib/libc/stdlib/a64l.3 | 186 +++++++++++++++++++++++++++++++++++ lib/libc/stdlib/a64l.c | 46 +++++++++ lib/libc/stdlib/l64a.c | 52 ++++++++++ 5 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 lib/libc/stdlib/a64l.3 create mode 100644 lib/libc/stdlib/a64l.c create mode 100644 lib/libc/stdlib/l64a.c diff --git a/include/stdlib.h b/include/stdlib.h index 1cc6c371d7ed..1fa43282284e 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -172,7 +172,7 @@ void unsetenv(const char *); */ #if __XSI_VISIBLE /* XXX XSI requires pollution from here. We'd rather not. */ -/* long a64l(const char *); */ +long a64l(const char *); double drand48(void); /* char *ecvt(double, int, int * __restrict, int * __restrict); */ double erand48(unsigned short[3]); @@ -182,7 +182,7 @@ int getsubopt(char **, char *const *, char **); int grantpt(int); char *initstate(unsigned long /* XSI requires u_int */, char *, long); long jrand48(unsigned short[3]); -/* char *l64a(long); */ +char *l64a(long); void lcong48(unsigned short[7]); long lrand48(void); #ifndef _MKSTEMP_DECLARED @@ -258,6 +258,7 @@ __const char * getprogname(void); int heapsort(void *, size_t, size_t, int (*)(const void *, const void *)); +int l64a_r(long, char *, int); int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); void qsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *)); diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index bebbc63792fa..7883e96e9380 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -4,12 +4,12 @@ # machine-independent stdlib sources .PATH: ${.CURDIR}/${MACHINE_ARCH}/stdlib ${.CURDIR}/stdlib -MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ +MISRCS+=_Exit.c a64l.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 strtoimax.c \ + insque.c l64a.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 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 @@ -18,12 +18,13 @@ MISRCS+=_Exit.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ .include "${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc" .endif -MAN+= abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \ +MAN+= a64l.3 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 \ realpath.3 strfmon.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3 +MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3 MLINKS+=atol.3 atoll.3 MLINKS+=exit.3 _Exit.3 MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3 diff --git a/lib/libc/stdlib/a64l.3 b/lib/libc/stdlib/a64l.3 new file mode 100644 index 000000000000..97545e992316 --- /dev/null +++ b/lib/libc/stdlib/a64l.3 @@ -0,0 +1,186 @@ +.\" Copyright (c) 2005 Tom Rhodes +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.\" $FreeBSD$ +.\" +.Dd November 20, 2005 +.Dt A64L 3 +.Os +.Sh NAME +.Nm a64l , +.Nm l64a , +.Nm l64a_r +.Nd "convert between a long integer and a base-64 ASCII string" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft long +.Fn a64l "const char *s" +.Ft char * +.Fn l64a "long int l" +.Ft int +.Fn l64a_r "long int l" "char *buffer" "int buflen" +.Sh DESCRIPTION +These functions are used to maintain numbers stored in radix-64 +.Tn ASCII +characters. +This is a notation by which 32-bit integers can be represented by +up to six characters; each character represents a digit in +radix-64 notation. +If the type long contains more than 32 bits, only the low-order +32 bits are used for these operations. +.Pp +The characters used to represent +.Dq digits +are +.Ql .\& +for 0, +.Ql /\& +for 1, +.Ql 0\& +.Fl +.Ql 9\& +for 2 +.Fl +11, +.Ql A\& +.Fl +.Ql Z\& +for 12 +.Fl +37, and +.Ql a\& +.Fl +.Ql z\& +for 38 +.Fl +63. +.Pp +The +.Fn a64l +function takes a pointer to a radix-64 representation, in which the first +digit is the least significant, and returns a corresponding +.Ft long +value. +If the string pointed to by +.Fa s +contains more than six characters, +.Fn a64l +uses the first six. +If the first six characters of the string contain a null terminator, +.Fn a64l +uses only characters preceding the null terminator. +The +.Fn a64l +function scans the character string from left to right with the least +significant digit on the left, decoding each character as a 6-bit +radix-64 number. +If the type long contains more than 32 bits, the resulting value is +sign-extended. +The behavior of +.Fn a64l +is unspecified if +.Fa s +is a null pointer or the string pointed to by +.Fa s +was not generated by a previous call to +.Fn l64a . +.Pp +The +.Fn l64a +function takes a long argument and returns a pointer to the corresponding +radix-64 representation. +The behavior of +.Fn l64a +is unspecified if value is negative. +.Pp +The value returned by +.Fn l64a +is a pointer into a static buffer. +Subsequent calls to +.Fn l64a +may overwrite the buffer. +.Pp +The +.Fn l64a_r +function performs a conversion identical to that of +.Fn l64a +and stores the resulting representation in the memory area pointed to by +.Fa buffer , +consuming at most +.Fa buflen +characters including the terminating NUL character. +.Sh RETURN VALUES +On successful completion, +.Fn a64l +returns the +.Ft long +value resulting from conversion of the input string. +If a string pointed to by s is an empty string, +.Fn a64l +returns 0. +.Pp +The +l64a +function returns a pointer to the radix-64 representation. +If value is 0, +.Fn l64a +returns a pointer to an empty string. +.Sh SEE ALSO +.Xr stroul 3 +.Sh HISTORY +The +.Fn a64l , +.Fn l64a , +and +.Fn l64a_r +functions are derived from +.Nx +with modifications. +They were added to +.Fx 6.1 . +.Sh AUTHORS +The +.Fn a64l , +.Fn l64a , +and +.Fn l64a_r +were added to +.Fx +by +.An Tom Rhodes Aq trhodes@FreeBSD.org . +Almost all of this manual page came from the +.Tn POSIX +standard. diff --git a/lib/libc/stdlib/a64l.c b/lib/libc/stdlib/a64l.c new file mode 100644 index 000000000000..6d175ef8a85a --- /dev/null +++ b/lib/libc/stdlib/a64l.c @@ -0,0 +1,46 @@ +/*- + * Written by J.T. Conklin . + * Public domain. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: a64l.c,v 1.8 2000/01/22 22:19:19 mycroft Exp $"); +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#define ADOT 46 /* ASCII '.' */ +#define ASLASH ADOT + 1 /* ASCII '/' */ +#define A0 48 /* ASCII '0' */ +#define AA 65 /* ASCII 'A' */ +#define Aa 97 /* ASCII 'a' */ + +long +a64l(const char *s) +{ + long shift; + int digit, i, value; + + value = 0; + shift = 0; + for (i = 0; *s != '\0' && i < 6; i++, s++) { + if (*s <= ASLASH) + digit = *s - ASLASH + 1; + else if (*s <= A0 + 9) + digit = *s - A0 + 2; + else if (*s <= AA + 25) + digit = *s - AA + 12; + else + digit = *s - Aa + 38; + + value |= digit << shift; + shift += 6; + } + return (value); +} diff --git a/lib/libc/stdlib/l64a.c b/lib/libc/stdlib/l64a.c new file mode 100644 index 000000000000..bc105535ed12 --- /dev/null +++ b/lib/libc/stdlib/l64a.c @@ -0,0 +1,52 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: l64a.c,v 1.13 2003/07/26 19:24:54 salo Exp $"); +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD$"); + +#include + +#define ADOT 46 /* ASCII '.' */ +#define ASLASH ADOT + 1 /* ASCII '/' */ +#define A0 48 /* ASCII '0' */ +#define AA 65 /* ASCII 'A' */ +#define Aa 97 /* ASCII 'a' */ + +char * +l64a(long value) +{ + static char buf[8]; + + (void)l64a_r(value, buf, sizeof(buf)); + return (buf); +} + +int +l64a_r(long value, char *buffer, int buflen) +{ + long v; + int digit; + + v = value & (long)0xffffffff; + for (; v != 0 && buflen > 1; buffer++, buflen--) { + digit = v & 0x3f; + if (digit < 2) + *buffer = digit + ADOT; + else if (digit < 12) + *buffer = digit + A0 - 2; + else if (digit < 38) + *buffer = digit + AA - 12; + else + *buffer = digit + Aa - 38; + v >>= 6; + } + return (v == 0 ? 0 : -1); +}