From fde75f89eae541144585db53ce3f7c29d069b4d2 Mon Sep 17 00:00:00 2001 From: solar Date: Sat, 15 May 2010 00:26:39 +0000 Subject: [PATCH] Added inttypes.h --- functions/inttypes/imaxabs.c | 32 +++++++++ functions/inttypes/imaxdiv.c | 41 +++++++++++ functions/inttypes/strtoimax.c | 126 +++++++++++++++++++++++++++++++++ functions/inttypes/strtoumax.c | 81 +++++++++++++++++++++ includes/inttypes.h | 117 ++++++++++++++++++++++++++++++ includes/stdlib.h | 3 + 6 files changed, 400 insertions(+) create mode 100755 functions/inttypes/imaxabs.c create mode 100755 functions/inttypes/imaxdiv.c create mode 100755 functions/inttypes/strtoimax.c create mode 100755 functions/inttypes/strtoumax.c create mode 100755 includes/inttypes.h diff --git a/functions/inttypes/imaxabs.c b/functions/inttypes/imaxabs.c new file mode 100755 index 0000000..9beda2b --- /dev/null +++ b/functions/inttypes/imaxabs.c @@ -0,0 +1,32 @@ +/* $Id$ */ + +/* imaxabs( intmax_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +intmax_t imaxabs( intmax_t j ) +{ + return ( j >= 0 ) ? j : -j; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> +#include + +int main( void ) +{ + TESTCASE( imaxabs( (intmax_t)0 ) == 0 ); + TESTCASE( imaxabs( INTMAX_MAX ) == INTMAX_MAX ); + TESTCASE( imaxabs( INTMAX_MIN + 1 ) == -( INTMAX_MIN + 1 ) ); + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/imaxdiv.c b/functions/inttypes/imaxdiv.c new file mode 100755 index 0000000..be93b99 --- /dev/null +++ b/functions/inttypes/imaxdiv.c @@ -0,0 +1,41 @@ +/* $Id$ */ + +/* lldiv( long long int, long long int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ) +{ + imaxdiv_t rc; + rc.quot = numer / denom; + rc.rem = numer % denom; + /* TODO: pre-C99 compilers might require modulus corrections */ + return rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + imaxdiv_t result; + result = imaxdiv( (intmax_t)5, (intmax_t)2 ); + TESTCASE( result.quot == 2 && result.rem == 1 ); + result = imaxdiv( (intmax_t)-5, (intmax_t)2 ); + TESTCASE( result.quot == -2 && result.rem == -1 ); + result = imaxdiv( (intmax_t)5, (intmax_t)-2 ); + TESTCASE( result.quot == -2 && result.rem == 1 ); + TESTCASE( sizeof( result.quot ) == sizeof( intmax_t ) ); + TESTCASE( sizeof( result.rem ) == sizeof( intmax_t ) ); + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/strtoimax.c b/functions/inttypes/strtoimax.c new file mode 100755 index 0000000..af29d3d --- /dev/null +++ b/functions/inttypes/strtoimax.c @@ -0,0 +1,126 @@ +/* $Id$ */ + +/* strtoimax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +#include + +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + intmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + if ( sign == '+' ) + { + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MAX, (uintmax_t)( INTMAX_MAX / base ), (int)( INTMAX_MAX % base ), &sign ); + } + else + { + /* FIXME: This breaks on some machines that round negatives wrongly */ + /* FIXME: Sign error not caught by testdriver */ + rc = (intmax_t)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)INTMAX_MIN, (uintmax_t)( INTMAX_MIN / -base ), (int)( -( INTMAX_MIN % base ) ), &sign ); + } + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +#include + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoimax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoimax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoimax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoimax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoimax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoimax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoimax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoimax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoimax( overflow, &endptr, 36 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoimax( overflow + 1, &endptr, 36 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoimax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoimax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoimax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + /* These tests assume two-complement, but conversion should work for */ + /* one-complement and signed magnitude just as well. Anyone having a */ + /* platform to test this on? */ + errno = 0; +#if INTMAX_MAX == 0x7fffffffffffffffLL + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoimax( "0x7FFFFFFFFFFFFFFF", NULL, 0 ) == 0x7fffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x8000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7FFFFFFFFFFFFFFF", NULL, 0 ) == (long long)0x8000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x8000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#elif INTMAX_MAX == 0x7fffffffffffffffffffffffffffffffLL + /* testing "even" overflow, i.e. base is power of two */ + TESTCASE( strtoimax( "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == 0x7fffffffffffffffffffffffffffffff ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MAX ); + TESTCASE( errno == ERANGE ); + errno = 0; + TESTCASE( strtoimax( "-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == -0x80000000000000000000000000000001 ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == 0 ); + TESTCASE( strtoimax( "-0x80000000000000000000000000000001", NULL, 0 ) == INTMAX_MIN ); + TESTCASE( errno == ERANGE ); + /* TODO: test "odd" overflow, i.e. base is not power of two */ +#else +#error Unsupported width of 'long long' (neither 64 nor 128 bit). +#endif + return TEST_RESULTS; +} + +#endif diff --git a/functions/inttypes/strtoumax.c b/functions/inttypes/strtoumax.c new file mode 100755 index 0000000..063e7ab --- /dev/null +++ b/functions/inttypes/strtoumax.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +/* strtoumax( const char *, char * *, int ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +#include + +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char ** _PDCLIB_restrict endptr, int base ) +{ + uintmax_t rc; + char sign = '+'; + const char * p = _PDCLIB_strtox_prelim( nptr, &sign, &base ); + if ( base < 2 || base > 36 ) return 0; + rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)UINTMAX_MAX, (uintmax_t)( UINTMAX_MAX / base ), (int)( UINTMAX_MAX % base ), &sign ); + if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) nptr; + return ( sign == '+' ) ? rc : -rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> +#include + +int main( void ) +{ + char * endptr; + /* this, to base 36, overflows even a 256 bit integer */ + char overflow[] = "-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ_"; + /* tricky border case */ + char tricky[] = "+0xz"; + errno = 0; + /* basic functionality */ + TESTCASE( strtoumax( "123", NULL, 10 ) == 123 ); + /* proper detecting of default base 10 */ + TESTCASE( strtoumax( "456", NULL, 0 ) == 456 ); + /* proper functioning to smaller base */ + TESTCASE( strtoumax( "14", NULL, 8 ) == 12 ); + /* proper autodetecting of octal */ + TESTCASE( strtoumax( "016", NULL, 0 ) == 14 ); + /* proper autodetecting of hexadecimal, lowercase 'x' */ + TESTCASE( strtoumax( "0xFF", NULL, 0 ) == 255 ); + /* proper autodetecting of hexadecimal, uppercase 'X' */ + TESTCASE( strtoumax( "0Xa1", NULL, 0 ) == 161 ); + /* proper handling of border case: 0x followed by non-hexdigit */ + TESTCASE( strtoumax( tricky, &endptr, 0 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* proper handling of border case: 0 followed by non-octdigit */ + TESTCASE( strtoumax( tricky, &endptr, 8 ) == 0 ); + TESTCASE( endptr == tricky + 2 ); + /* errno should still be 0 */ + TESTCASE( errno == 0 ); + /* overflowing subject sequence must still return proper endptr */ + TESTCASE( strtoumax( overflow, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* same for positive */ + errno = 0; + TESTCASE( strtoumax( overflow + 1, &endptr, 36 ) == UINTMAX_MAX ); + TESTCASE( errno == ERANGE ); + TESTCASE( ( endptr - overflow ) == 53 ); + /* testing skipping of leading whitespace */ + TESTCASE( strtoumax( " \n\v\t\f789", NULL, 0 ) == 789 ); + /* testing conversion failure */ + TESTCASE( strtoumax( overflow, &endptr, 10 ) == 0 ); + TESTCASE( endptr == overflow ); + endptr = NULL; + TESTCASE( strtoumax( overflow, &endptr, 0 ) == 0 ); + TESTCASE( endptr == overflow ); + return TEST_RESULTS; +} + +#endif diff --git a/includes/inttypes.h b/includes/inttypes.h new file mode 100755 index 0000000..5b86807 --- /dev/null +++ b/includes/inttypes.h @@ -0,0 +1,117 @@ +/* $Id$ */ + +/* 7.8 Format conversion of integer types + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#ifndef _PDCLIB_INTTYPES_H +#define _PDCLIB_INTTYPES_H _PDCLIB_INTTYPES_H + +#include + +typedef struct _PDCLIB_imaxdiv_t imaxdiv_t; + +/* TODO: Print / Scan Macros */ +/* +PRId8 PRIdLEAST8 PRIdFAST8 PRIdMAX +PRId16 PRIdLEAST16 PRIdFAST16 PRIdPTR +PRId32 PRIdLEAST32 PRIdFAST32 +PRId64 PRIdLEAST64 PRIdFAST64 + +PRIi8 PRIiLEAST8 PRIiFAST8 PRIiMAX +PRIi16 PRIiLEAST16 PRIiFAST16 PRIdPTR +PRIi32 PRIiLEAST32 PRIiFAST32 +PRIi64 PRIiLEAST64 PRIiFAST64 + +PRIo8 PRIoLEAST8 PRIoFAST8 PRIoMAX +PRIo16 PRIoLEAST16 PRIoFAST16 PRIoPTR +PRIo32 PRIoLEAST32 PRIoFAST32 +PRIo64 PRIoLEAST64 PRIoFAST64 + +PRIu8 PRIuLEAST8 PRIuFAST8 PRIuMAX +PRIu16 PRIuLEAST16 PRIuFAST16 PRIuPTR +PRIu32 PRIuLEAST32 PRIuFAST32 +PRIu64 PRIuLEAST64 PRIuFAST64 + +PRIx8 PRIxLEAST8 PRIxFAST8 PRIxMAX +PRIx16 PRIxLEAST16 PRIxFAST16 PRIxPTR +PRIx32 PRIxLEAST32 PRIxFAST32 +PRIx64 PRIxLEAST64 PRIxFAST64 + +PRIX8 PRIXLEAST8 PRIXFAST8 PRIXMAX +PRIX16 PRIXLEAST16 PRIXFAST16 PRIXPTR +PRIX32 PRIXLEAST32 PRIXFAST32 +PRIX64 PRIXLEAST64 PRIXFAST64 + +SCNd8 SCNdLEAST8 SCNdFAST8 SCNdMAX +SCNd16 SCNdLEAST16 SCNdFAST16 SCNdPTR +SCNd32 SCNdLEAST32 SCNdFAST32 +SCNd64 SCNdLEAST64 SCNdFAST64 + +SCNi8 SCNiLEAST8 SCNiFAST8 SCNiMAX +SCNi16 SCNiLEAST16 SCNiFAST16 SCNdPTR +SCNi32 SCNiLEAST32 SCNiFAST32 +SCNi64 SCNiLEAST64 SCNiFAST64 + +SCNo8 SCNoLEAST8 SCNoFAST8 SCNoMAX +SCNo16 SCNoLEAST16 SCNoFAST16 SCNoPTR +SCNo32 SCNoLEAST32 SCNoFAST32 +SCNo64 SCNoLEAST64 SCNoFAST64 + +SCNu8 SCNuLEAST8 SCNuFAST8 SCNuMAX +SCNu16 SCNuLEAST16 SCNuFAST16 SCNuPTR +SCNu32 SCNuLEAST32 SCNuFAST32 +SCNu64 SCNuLEAST64 SCNuFAST64 + +SCNx8 SCNxLEAST8 SCNxFAST8 SCNxMAX +SCNx16 SCNxLEAST16 SCNxFAST16 SCNxPTR +SCNx32 SCNxLEAST32 SCNxFAST32 +SCNx64 SCNxLEAST64 SCNxFAST64 + +SCNX8 SCNXLEAST8 SCNXFAST8 SCNXMAX +SCNX16 SCNXLEAST16 SCNXFAST16 SCNXPTR +SCNX32 SCNXLEAST32 SCNXFAST32 +SCNX64 SCNXLEAST64 SCNXFAST64 +*/ + +/* 7.8.2 Functions for greatest-width integer types */ + +/* Calculate the absolute value of j */ +intmax_t imaxabs( intmax_t j ); + +/* Return quotient (quot) and remainder (rem) of an integer division in the + imaxdiv_t struct. +*/ +imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom ); + +/* Seperate the character array nptr into three parts: A (possibly empty) + sequence of whitespace characters, a character representation of an integer + to the given base, and trailing invalid characters (including the terminating + null character). If base is 0, assume it to be 10, unless the integer + representation starts with 0x / 0X (setting base to 16) or 0 (setting base to + 8). If given, base can be anything from 0 to 36, using the 26 letters of the + base alphabet (both lowercase and uppercase) as digits 10 through 35. + The integer representation is then converted into the return type of the + function. It can start with a '+' or '-' sign. If the sign is '-', the result + of the conversion is negated. + If the conversion is successful, the converted value is returned. If endptr + is not a NULL pointer, a pointer to the first trailing invalid character is + returned in *endptr. + If no conversion could be performed, zero is returned (and nptr in *endptr, + if endptr is not a NULL pointer). If the converted value does not fit into + the return type, the functions return INTMAX_MIN, INTMAX_MAX, or UINTMAX_MAX, + respectively, depending on the sign of the integer representation and the + return type, and errno is set to ERANGE. +*/ +/* This function is equivalent to strtol() / strtoul() in , but on + the potentially larger type. +*/ +intmax_t strtoimax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); +uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); + +/* TODO: wcstoimax(), wcstoumax() */ + +#endif + diff --git a/includes/stdlib.h b/includes/stdlib.h index 06eb9ce..f84851b 100644 --- a/includes/stdlib.h +++ b/includes/stdlib.h @@ -52,6 +52,9 @@ long double strtold( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restri LLONG_MIN, LLONG_MAX, or ULLONG_MAX respectively, depending on the sign of the integer representation and the return type, and errno is set to ERANGE. */ +/* There is strtoimax() and strtoumax() in operating on intmax_t / + uintmax_t, if the long long versions do not suit your needs. +*/ long int strtol( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); long long int strtoll( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); unsigned long int strtoul( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restrict endptr, int base ); -- 2.40.0