aboutsummaryrefslogtreecommitdiffstats
path: root/src/pdclib/functions/stdlib
diff options
context:
space:
mode:
authortcsullivan <tullivan99@gmail.com>2018-11-17 13:02:57 -0500
committertcsullivan <tullivan99@gmail.com>2018-11-17 13:02:57 -0500
commitc6ef89664b8c0d7aa85bddd5c7014aa6df82cbe7 (patch)
treed1f9d09412a46bdf4344fe30392455070a72993d /src/pdclib/functions/stdlib
parentdb38c4b9dac461de0ed75bf6d079dacba1b31bc9 (diff)
added pdclib, removed sash
Diffstat (limited to 'src/pdclib/functions/stdlib')
-rw-r--r--src/pdclib/functions/stdlib/_Exit.c36
-rw-r--r--src/pdclib/functions/stdlib/abort.c40
-rw-r--r--src/pdclib/functions/stdlib/abs.c32
-rw-r--r--src/pdclib/functions/stdlib/atexit.c64
-rw-r--r--src/pdclib/functions/stdlib/atoi.c28
-rw-r--r--src/pdclib/functions/stdlib/atol.c28
-rw-r--r--src/pdclib/functions/stdlib/atoll.c28
-rw-r--r--src/pdclib/functions/stdlib/bsearch.c61
-rw-r--r--src/pdclib/functions/stdlib/calloc.c48
-rw-r--r--src/pdclib/functions/stdlib/div.c40
-rw-r--r--src/pdclib/functions/stdlib/exit.c44
-rw-r--r--src/pdclib/functions/stdlib/free.c52
-rw-r--r--src/pdclib/functions/stdlib/labs.c32
-rw-r--r--src/pdclib/functions/stdlib/ldiv.c40
-rw-r--r--src/pdclib/functions/stdlib/llabs.c32
-rw-r--r--src/pdclib/functions/stdlib/lldiv.c40
-rw-r--r--src/pdclib/functions/stdlib/malloc.c427
-rw-r--r--src/pdclib/functions/stdlib/qsort.c166
-rw-r--r--src/pdclib/functions/stdlib/rand.c34
-rw-r--r--src/pdclib/functions/stdlib/realloc.c56
-rw-r--r--src/pdclib/functions/stdlib/srand.c28
-rw-r--r--src/pdclib/functions/stdlib/strtol.c129
-rw-r--r--src/pdclib/functions/stdlib/strtoll.c123
-rw-r--r--src/pdclib/functions/stdlib/strtoul.c106
-rw-r--r--src/pdclib/functions/stdlib/strtoull.c101
25 files changed, 1815 insertions, 0 deletions
diff --git a/src/pdclib/functions/stdlib/_Exit.c b/src/pdclib/functions/stdlib/_Exit.c
new file mode 100644
index 0000000..de387db
--- /dev/null
+++ b/src/pdclib/functions/stdlib/_Exit.c
@@ -0,0 +1,36 @@
+/* _Exit( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+void _Exit( int status )
+{
+ /* TODO: Flush and close open streams. Remove tmpfile() files. Make this
+ called on process termination automatically.
+ */
+ _PDCLIB_Exit( status );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ int UNEXPECTED_RETURN = 0;
+ _Exit( 0 );
+ TESTCASE( UNEXPECTED_RETURN );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/abort.c b/src/pdclib/functions/stdlib/abort.c
new file mode 100644
index 0000000..69422f9
--- /dev/null
+++ b/src/pdclib/functions/stdlib/abort.c
@@ -0,0 +1,40 @@
+/* abort( void )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+#include <signal.h>
+
+#ifndef REGTEST
+
+void abort( void )
+{
+ raise( SIGABRT );
+ exit( EXIT_FAILURE );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdio.h>
+
+static void aborthandler( int sig )
+{
+ exit( 0 );
+}
+
+int main( void )
+{
+ int UNEXPECTED_RETURN_FROM_ABORT = 0;
+ TESTCASE( signal( SIGABRT, &aborthandler ) != SIG_ERR );
+ abort();
+ TESTCASE( UNEXPECTED_RETURN_FROM_ABORT );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/abs.c b/src/pdclib/functions/stdlib/abs.c
new file mode 100644
index 0000000..7a634e3
--- /dev/null
+++ b/src/pdclib/functions/stdlib/abs.c
@@ -0,0 +1,32 @@
+/* abs( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+int abs( int j )
+{
+ return ( j >= 0 ) ? j : -j;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <limits.h>
+
+int main( void )
+{
+ TESTCASE( abs( 0 ) == 0 );
+ TESTCASE( abs( INT_MAX ) == INT_MAX );
+ TESTCASE( abs( INT_MIN + 1 ) == -( INT_MIN + 1 ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/atexit.c b/src/pdclib/functions/stdlib/atexit.c
new file mode 100644
index 0000000..489c3df
--- /dev/null
+++ b/src/pdclib/functions/stdlib/atexit.c
@@ -0,0 +1,64 @@
+/* atexit( void (*)( void ) )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+extern void (*_PDCLIB_exitstack[])( void );
+extern size_t _PDCLIB_exitptr;
+
+int atexit( void (*func)( void ) )
+{
+ if ( _PDCLIB_exitptr == 0 )
+ {
+ return -1;
+ }
+ else
+ {
+ _PDCLIB_exitstack[ --_PDCLIB_exitptr ] = func;
+ return 0;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <assert.h>
+
+static int flags[ 32 ];
+
+static void counthandler( void )
+{
+ static int count = 0;
+ flags[ count ] = count;
+ ++count;
+}
+
+static void checkhandler( void )
+{
+ int i;
+ for ( i = 0; i < 31; ++i )
+ {
+ assert( flags[ i ] == i );
+ }
+}
+
+int main( void )
+{
+ int i;
+ TESTCASE( atexit( &checkhandler ) == 0 );
+ for ( i = 0; i < 31; ++i )
+ {
+ TESTCASE( atexit( &counthandler ) == 0 );
+ }
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/atoi.c b/src/pdclib/functions/stdlib/atoi.c
new file mode 100644
index 0000000..eaa9100
--- /dev/null
+++ b/src/pdclib/functions/stdlib/atoi.c
@@ -0,0 +1,28 @@
+/* atoi( const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+int atoi( const char * s )
+{
+ return (int) _PDCLIB_atomax( s );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* no tests for a simple wrapper */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/atol.c b/src/pdclib/functions/stdlib/atol.c
new file mode 100644
index 0000000..df17e83
--- /dev/null
+++ b/src/pdclib/functions/stdlib/atol.c
@@ -0,0 +1,28 @@
+/* atol( const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+long int atol( const char * s )
+{
+ return (long int) _PDCLIB_atomax( s );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* no tests for a simple wrapper */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/atoll.c b/src/pdclib/functions/stdlib/atoll.c
new file mode 100644
index 0000000..8b65b35
--- /dev/null
+++ b/src/pdclib/functions/stdlib/atoll.c
@@ -0,0 +1,28 @@
+/* atoll( const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+long long int atoll( const char * s )
+{
+ return (long long int) _PDCLIB_atomax( s );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* no tests for a simple wrapper */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/bsearch.c b/src/pdclib/functions/stdlib/bsearch.c
new file mode 100644
index 0000000..211c55c
--- /dev/null
+++ b/src/pdclib/functions/stdlib/bsearch.c
@@ -0,0 +1,61 @@
+/* bsearch( const void *, const void *, size_t, size_t, int(*)( const void *, const void * ) )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
+{
+ const void * pivot;
+ int rc;
+ size_t corr;
+ while ( nmemb )
+ {
+ /* algorithm needs -1 correction if remaining elements are an even number. */
+ corr = nmemb % 2;
+ nmemb /= 2;
+ pivot = (const char *)base + (nmemb * size);
+ rc = compar( key, pivot );
+ if ( rc > 0 )
+ {
+ base = (const char *)pivot + size;
+ /* applying correction */
+ nmemb -= ( 1 - corr );
+ }
+ else if ( rc == 0 )
+ {
+ return (void *)pivot;
+ }
+ }
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+static int compare( const void * left, const void * right )
+{
+ return *( (unsigned char *)left ) - *( (unsigned char *)right );
+}
+
+int main( void )
+{
+ TESTCASE( bsearch( "e", abcde, 4, 1, compare ) == NULL );
+ TESTCASE( bsearch( "e", abcde, 5, 1, compare ) == &abcde[4] );
+ TESTCASE( bsearch( "a", abcde + 1, 4, 1, compare ) == NULL );
+ TESTCASE( bsearch( "0", abcde, 1, 1, compare ) == NULL );
+ TESTCASE( bsearch( "a", abcde, 1, 1, compare ) == &abcde[0] );
+ TESTCASE( bsearch( "a", abcde, 0, 1, compare ) == NULL );
+ TESTCASE( bsearch( "e", abcde, 3, 2, compare ) == &abcde[4] );
+ TESTCASE( bsearch( "b", abcde, 3, 2, compare ) == NULL );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/calloc.c b/src/pdclib/functions/stdlib/calloc.c
new file mode 100644
index 0000000..d736065
--- /dev/null
+++ b/src/pdclib/functions/stdlib/calloc.c
@@ -0,0 +1,48 @@
+/* void * calloc( size_t, size_t )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+void * calloc( size_t nmemb, size_t size )
+{
+ /* assign memory for nmemb elements of given size */
+ void * rc = malloc( nmemb * size );
+ if ( rc != NULL )
+ {
+ /* zero-initialize the memory */
+ memset( rc, 0, nmemb * size );
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char * s;
+ TESTCASE( ( s = calloc( 3, 2 ) ) != NULL );
+ TESTCASE( s[0] == '\0' );
+ TESTCASE( s[5] == '\0' );
+ free( s );
+ TESTCASE( ( s = calloc( 6, 1 ) ) != NULL );
+ TESTCASE( s[0] == '\0' );
+ TESTCASE( s[5] == '\0' );
+ free( s );
+ TESTCASE( ( s = calloc( 1, 6 ) ) != NULL );
+ TESTCASE( s[0] == '\0' );
+ TESTCASE( s[5] == '\0' );
+ free( s );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/div.c b/src/pdclib/functions/stdlib/div.c
new file mode 100644
index 0000000..5d502c8
--- /dev/null
+++ b/src/pdclib/functions/stdlib/div.c
@@ -0,0 +1,40 @@
+/* div( int, int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+div_t div( int numer, int denom )
+{
+ div_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 )
+{
+ div_t result;
+ result = div( 5, 2 );
+ TESTCASE( result.quot == 2 && result.rem == 1 );
+ result = div( -5, 2 );
+ TESTCASE( result.quot == -2 && result.rem == -1 );
+ result = div( 5, -2 );
+ TESTCASE( result.quot == -2 && result.rem == 1 );
+ TESTCASE( sizeof( result.quot ) == sizeof( int ) );
+ TESTCASE( sizeof( result.rem ) == sizeof( int ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/exit.c b/src/pdclib/functions/stdlib/exit.c
new file mode 100644
index 0000000..e636a32
--- /dev/null
+++ b/src/pdclib/functions/stdlib/exit.c
@@ -0,0 +1,44 @@
+/* exit( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+/* TODO - "except that a function is called after any previously registered
+ functions that had already been called at the time it was registered.
+*/
+
+/* TODO: 32 is guaranteed. This should be dynamic but ATM gives problems
+ with my malloc.
+*/
+#define NUMBER_OF_SLOTS 40
+
+void (*_PDCLIB_exitstack[ NUMBER_OF_SLOTS ])( void ) = { _PDCLIB_closeall };
+size_t _PDCLIB_exitptr = NUMBER_OF_SLOTS;
+
+void exit( int status )
+{
+ while ( _PDCLIB_exitptr < NUMBER_OF_SLOTS )
+ {
+ _PDCLIB_exitstack[ _PDCLIB_exitptr++ ]();
+ }
+ _Exit( status );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Unwinding of regstack tested in atexit(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/free.c b/src/pdclib/functions/stdlib/free.c
new file mode 100644
index 0000000..126a17b
--- /dev/null
+++ b/src/pdclib/functions/stdlib/free.c
@@ -0,0 +1,52 @@
+/* void free( void * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_int.h"
+
+/* TODO: Primitive placeholder. Much room for improvement. */
+
+/* structure holding first and last element of free node list */
+extern struct _PDCLIB_headnode_t _PDCLIB_memlist;
+
+void free( void * ptr )
+{
+ if ( ptr == NULL )
+ {
+ return;
+ }
+ ptr = (void *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) );
+ ( (struct _PDCLIB_memnode_t *)ptr )->next = NULL;
+ if ( _PDCLIB_memlist.last != NULL )
+ {
+ _PDCLIB_memlist.last->next = ptr;
+ }
+ else
+ {
+ _PDCLIB_memlist.first = ptr;
+ }
+ _PDCLIB_memlist.last = ptr;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdbool.h>
+
+int main( void )
+{
+ free( NULL );
+ TESTCASE( true );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/labs.c b/src/pdclib/functions/stdlib/labs.c
new file mode 100644
index 0000000..3653453
--- /dev/null
+++ b/src/pdclib/functions/stdlib/labs.c
@@ -0,0 +1,32 @@
+/* labs( 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 <stdlib.h>
+
+#ifndef REGTEST
+
+long int labs( long int j )
+{
+ return ( j >= 0 ) ? j : -j;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <limits.h>
+
+int main( void )
+{
+ TESTCASE( labs( 0 ) == 0 );
+ TESTCASE( labs( LONG_MAX ) == LONG_MAX );
+ TESTCASE( labs( LONG_MIN + 1 ) == -( LONG_MIN + 1 ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/ldiv.c b/src/pdclib/functions/stdlib/ldiv.c
new file mode 100644
index 0000000..0f51944
--- /dev/null
+++ b/src/pdclib/functions/stdlib/ldiv.c
@@ -0,0 +1,40 @@
+/* ldiv( long int, 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 <stdlib.h>
+
+#ifndef REGTEST
+
+ldiv_t ldiv( long int numer, long int denom )
+{
+ ldiv_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 )
+{
+ ldiv_t result;
+ result = ldiv( 5, 2 );
+ TESTCASE( result.quot == 2 && result.rem == 1 );
+ result = ldiv( -5, 2 );
+ TESTCASE( result.quot == -2 && result.rem == -1 );
+ result = ldiv( 5, -2 );
+ TESTCASE( result.quot == -2 && result.rem == 1 );
+ TESTCASE( sizeof( result.quot ) == sizeof( long ) );
+ TESTCASE( sizeof( result.rem ) == sizeof( long ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/llabs.c b/src/pdclib/functions/stdlib/llabs.c
new file mode 100644
index 0000000..bc05bf3
--- /dev/null
+++ b/src/pdclib/functions/stdlib/llabs.c
@@ -0,0 +1,32 @@
+/* llabs( 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 <stdlib.h>
+
+#ifndef REGTEST
+
+long long int llabs( long long int j )
+{
+ return ( j >= 0 ) ? j : -j;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <limits.h>
+
+int main( void )
+{
+ TESTCASE( llabs( 0ll ) == 0 );
+ TESTCASE( llabs( LLONG_MAX ) == LLONG_MAX );
+ TESTCASE( llabs( LLONG_MIN + 1 ) == -( LLONG_MIN + 1 ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/lldiv.c b/src/pdclib/functions/stdlib/lldiv.c
new file mode 100644
index 0000000..4219e31
--- /dev/null
+++ b/src/pdclib/functions/stdlib/lldiv.c
@@ -0,0 +1,40 @@
+/* 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 <stdlib.h>
+
+#ifndef REGTEST
+
+lldiv_t lldiv( long long int numer, long long int denom )
+{
+ lldiv_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 )
+{
+ lldiv_t result;
+ result = lldiv( 5ll, 2ll );
+ TESTCASE( result.quot == 2 && result.rem == 1 );
+ result = lldiv( -5ll, 2ll );
+ TESTCASE( result.quot == -2 && result.rem == -1 );
+ result = lldiv( 5ll, -2ll );
+ TESTCASE( result.quot == -2 && result.rem == 1 );
+ TESTCASE( sizeof( result.quot ) == sizeof( long long ) );
+ TESTCASE( sizeof( result.rem ) == sizeof( long long ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/malloc.c b/src/pdclib/functions/stdlib/malloc.c
new file mode 100644
index 0000000..ed57e9a
--- /dev/null
+++ b/src/pdclib/functions/stdlib/malloc.c
@@ -0,0 +1,427 @@
+/* void * malloc( size_t )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+/* TODO: Primitive placeholder. Much room for improvement. */
+
+/* Keeping pointers to the first and the last element of the free list. */
+struct _PDCLIB_headnode_t _PDCLIB_memlist = { NULL, NULL };
+
+void * malloc( size_t size )
+{
+ if ( size == 0 )
+ {
+ return NULL;
+ }
+ if ( size < _PDCLIB_MINALLOC )
+ {
+ size = _PDCLIB_MINALLOC;
+ }
+ {
+ struct _PDCLIB_memnode_t * current = _PDCLIB_memlist.first;
+ struct _PDCLIB_memnode_t * previous = NULL;
+ struct _PDCLIB_memnode_t * firstfit = NULL;
+ struct _PDCLIB_memnode_t * firstfit_previous = NULL;
+ /* Trying exact fit */
+ while ( current != NULL )
+ {
+ if ( current->size == size )
+ {
+ /* Found exact fit, allocate node */
+ if ( previous != NULL )
+ {
+ /* Node in the middle of the list */
+ previous->next = current->next;
+ }
+ else
+ {
+ /* Node is first in list */
+ _PDCLIB_memlist.first = current->next;
+ }
+ if ( _PDCLIB_memlist.last == current )
+ {
+ /* Node is last in list */
+ _PDCLIB_memlist.last = previous;
+ }
+ return (char *)current + sizeof( struct _PDCLIB_memnode_t );
+ }
+ else if ( current->size > size && ( firstfit == NULL || current->size < firstfit->size ) )
+ {
+ /* Remember previous node in case we do not get an exact fit.
+ Note that this is the node *pointing to* the first fit,
+ as we need that for allocating (i.e., changing next pointer).
+ */
+ firstfit_previous = previous;
+ firstfit = current;
+ }
+ /* Skip to next node */
+ previous = current;
+ current = current->next;
+ }
+ /* No exact fit; go for first fit */
+ if ( firstfit != NULL )
+ {
+ int node_split = 0;
+ if ( ( firstfit->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) )
+ {
+ /* Oversized - split into two nodes */
+ struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)( (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ) + size );
+ newnode->size = firstfit->size - size - sizeof( struct _PDCLIB_memnode_t );
+ newnode->next = firstfit->next;
+ firstfit->next = newnode;
+ firstfit->size = firstfit->size - newnode->size - sizeof( struct _PDCLIB_memnode_t );
+ node_split = 1;
+ }
+ if ( firstfit_previous != NULL )
+ {
+ /* Node in the middle of the list */
+ firstfit_previous->next = firstfit->next;
+ }
+ else
+ {
+ /* Node is first in list */
+ _PDCLIB_memlist.first = firstfit->next;
+ }
+ if ( _PDCLIB_memlist.last == firstfit )
+ {
+ /* Node is last in list */
+ if ( node_split )
+ {
+ _PDCLIB_memlist.last = firstfit->next;
+ }
+ else
+ {
+ _PDCLIB_memlist.last = firstfit_previous;
+ }
+ }
+ return (char *)firstfit + sizeof( struct _PDCLIB_memnode_t );
+ }
+ }
+ {
+ /* No fit possible; how many additional pages do we need? */
+ size_t pages = ( ( size + sizeof( struct _PDCLIB_memnode_t ) - 1 ) / _PDCLIB_PAGESIZE ) + 1;
+ /* Allocate more pages */
+ struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)_PDCLIB_allocpages( (int)pages );
+ if ( newnode != NULL )
+ {
+ newnode->next = NULL;
+ newnode->size = pages * _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t );
+ if ( ( newnode->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) )
+ {
+ /* Oversized - split into two nodes */
+ struct _PDCLIB_memnode_t * splitnode = (struct _PDCLIB_memnode_t *)( (char *)newnode + sizeof( struct _PDCLIB_memnode_t ) + size );
+ splitnode->size = newnode->size - size - sizeof( struct _PDCLIB_memnode_t );
+ newnode->size = size;
+ /* Add splitted node as last element to free node list */
+ if ( _PDCLIB_memlist.last == NULL )
+ {
+ _PDCLIB_memlist.first = splitnode;
+ }
+ else
+ {
+ _PDCLIB_memlist.last->next = splitnode;
+ }
+ splitnode->next = NULL; /* TODO: This is bug #7, uncovered by testdriver yet. */
+ _PDCLIB_memlist.last = splitnode;
+ }
+ return (char *)newnode + sizeof( struct _PDCLIB_memnode_t );
+ }
+ }
+ /* No fit, heap extension not possible - out of memory */
+ return NULL;
+}
+
+#endif
+
+
+#ifdef TEST
+#include "_PDCLIB_test.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+#ifndef REGTEST
+
+/* Effective page size, i.e. how many bytes can be allocated and still be on
+ one page of memory.
+*/
+#define EFFECTIVE _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t )
+#define MEMTEST( ptr, size ) ( ( ptr = malloc( size ) ) != NULL ) && ( memset( ptr, 0, size ) == ptr )
+
+char * pages_start = 0;
+int test_nodes( const char * const, int, ... );
+void PRINT( const char * const, ... );
+
+/* This can be enabled to give a dump of node information */
+#if 0
+void PRINT( const char * const format, ... )
+{
+ va_list( ap );
+ va_start( ap, format );
+ vprintf( format, ap );
+}
+#else
+void PRINT( const char * const format, ... )
+{
+ /* EMPTY */
+}
+#endif
+
+/* Helper function checking number of allocated memory pages and the nodes
+ in the free memory list against expectations.
+*/
+int test_nodes( const char * const action, int expected_pages, ... )
+{
+ static int count = 1;
+ int result = 1;
+ /* Determining the amount of allocated pages */
+ int allocated_pages = ( (intptr_t)_PDCLIB_allocpages( 0 ) - (intptr_t)pages_start ) / _PDCLIB_PAGESIZE;
+ PRINT( action );
+ PRINT( "Test #%2d, %d allocated pages", count++, allocated_pages );
+ if ( allocated_pages != expected_pages )
+ {
+ PRINT( " - MISMATCH, expected\n %d pages\n", expected_pages );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ {
+ /* Now moving through the free nodes list */
+ va_list( ap );
+ struct _PDCLIB_memnode_t * tracer = _PDCLIB_memlist.first;
+ int firstnode = 0;
+ int lastnode = 0;
+ va_start( ap, expected_pages );
+ while ( tracer != NULL )
+ {
+ /* Expected data */
+ size_t expected_location = va_arg( ap, size_t );
+ /* Data from node */
+ size_t node_location = (char *)tracer - (char *)pages_start;
+ PRINT( " - node %.4p, size %#.4x", node_location, tracer->size );
+ if ( expected_location == 0 )
+ {
+ PRINT( " - UNEXPECTED NODE\n" );
+ result = 0;
+ continue;
+ }
+ /* Memorizing first and last expected node for later comparison. */
+ if ( firstnode == 0 )
+ {
+ firstnode = expected_location;
+ }
+ lastnode = expected_location;
+ {
+ /* Comparing expected node against current node */
+ size_t expected_size = va_arg( ap, size_t );
+ if ( ( node_location != expected_location ) || ( tracer->size != expected_size ) )
+ {
+ PRINT( " - MISMATCH, expected values\n %.4p %#.4p\n", expected_location, expected_size );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ }
+ tracer = tracer->next;
+ }
+ /* Comparing first and last node in memlist against expectations. */
+ PRINT( " - memlist first: %#.4x - last: %#.4x",
+ ( _PDCLIB_memlist.first == NULL ) ? NULL : (char *)_PDCLIB_memlist.first - (char *)pages_start,
+ ( _PDCLIB_memlist.last == NULL ) ? NULL : (char *)_PDCLIB_memlist.last - (char *)pages_start );
+ if ( ( firstnode != 0 ) &&
+ ( ( ( (char *)_PDCLIB_memlist.first - (char *)pages_start ) != firstnode )
+ || ( ( (char *)_PDCLIB_memlist.last - (char *)pages_start ) != lastnode ) ) )
+ {
+ PRINT( " - MISMATCH, expected values\n %#.4x - last: %#.4x\n", firstnode, lastnode );
+ result = 0;
+ }
+ else
+ {
+ PRINT( "\n" );
+ }
+ }
+ PRINT( "\n" );
+ return result;
+}
+
+#endif
+
+/* Note that this test driver heavily tests *internals* of the implementation
+ above (and of free() and realloc(), too). That means that changes in the
+ implementation must be accompanied with appropriate changes of the test
+ driver. It does *not* make a good regression tester for the implementation,
+ I am afraid, and thus there is no REGTEST equivalent.
+*/
+
+int main( void )
+{
+#ifndef REGTEST
+ void * ptr1, * ptr2, * ptr3, * ptr4, * ptr5, * ptr6, * ptr7, * ptr8, * ptr9, * ptrA, * ptrB, * ptrC;
+
+ pages_start = _PDCLIB_allocpages( 0 );
+ PRINT( "\nEffective is: %#.4x\nsizeof( memnode ) is: %#.2x\n\n", EFFECTIVE, sizeof( struct _PDCLIB_memnode_t ) );
+
+ /* Allocating 10 bytes; expecting one page allocation and a node split */
+ TESTCASE( MEMTEST( ptr1, 10 ) );
+ TESTCASE( test_nodes( "Allocating 10 bytes.", 1,
+ sizeof( struct _PDCLIB_memnode_t ) + 10, EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - 10,
+ 0 ) );
+
+ /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */
+ TESTCASE( MEMTEST( ptr2, EFFECTIVE - 10 - sizeof( struct _PDCLIB_memnode_t ) ) );
+ TESTCASE( test_nodes( "Allocating the rest of the page.", 1,
+ 0 ) );
+
+ /* Allocating a full page; expecting one page allocation, no node split */
+ TESTCASE( MEMTEST( ptr3, EFFECTIVE ) );
+ TESTCASE( test_nodes( "Allocating a full page.", 2,
+ 0 ) );
+
+ /* Allocating *almost* a full page; expecting one page allocation, no node split */
+ TESTCASE( MEMTEST( ptr4, EFFECTIVE - 4 ) );
+ TESTCASE( test_nodes( "Allocating *almost* a full page.", 3,
+ 0 ) );
+
+ /* Freeing and re-allocating the "almost" full page; expecting no page allocation, no node split */
+ free( ptr4 );
+ TESTCASE( MEMTEST( ptr5, EFFECTIVE - 4 ) );
+ TESTCASE( ptr4 == ptr5 );
+ TESTCASE( test_nodes( "Freeing and re-allocating the \"almost\" full page.", 3 ) );
+
+ /* Freeing the full page from test #3; expecting a full-sized free node. */
+ free( ptr3 );
+ TESTCASE( test_nodes( "Freeing the full page from test #3.", 3,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating two full pages; expecting two page allocations, no node split */
+ TESTCASE( MEMTEST( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) );
+ TESTCASE( test_nodes( "Allocating two full pages.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of 10 bytes; expecting no page allocation, no node split */
+ /* TODO: Shouldn't realloc() split the now much-too-large node? */
+ TESTCASE( realloc( ptr3, 10 ) == ptr3 );
+ TESTCASE( test_nodes( "Re-allocating to size of 10 bytes.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of two full pages; expecting no page allocation, no node split */
+ TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) == ptr3 );
+ TESTCASE( test_nodes( "Re-allocating to size of two full pages.", 5,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Re-allocating to size of three full pages; expecting three page allocation, freeing of two-page node */
+ TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE * 2 ) != ptr3 );
+ TESTCASE( test_nodes( "Re-allocating to size of three full pages.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ _PDCLIB_PAGESIZE * 3, EFFECTIVE + _PDCLIB_PAGESIZE,
+ 0 ) );
+
+ /* Allocating two full pages; expecting allocation of the available two-page node */
+ TESTCASE( MEMTEST( ptr4, EFFECTIVE + _PDCLIB_PAGESIZE ) );
+ TESTCASE( test_nodes( "Allocating two full pages.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating zero bytes; expecting no change */
+ TESTCASE( ! MEMTEST( ptr6, 0 ) );
+ TESTCASE( test_nodes( "Allocating zero bytes.", 8,
+ _PDCLIB_PAGESIZE * 1, EFFECTIVE,
+ 0 ) );
+
+ /* Allocating 4 bytes; expecting upsizing of requestupsizing of size, node split */
+ TESTCASE( MEMTEST( ptr7, 4 ) );
+ TESTCASE( test_nodes( "Allocating 4 bytes.", 8,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */
+ TESTCASE( MEMTEST( ptr8, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) );
+ TESTCASE( test_nodes( "Allocating the rest of the page.", 8, 0 ) );
+
+ /* Freeing the node from the previous test; expecting node to re-appear in free list */
+ free( ptr8 );
+ TESTCASE( test_nodes( "Freeing the node from the previous test.", 8,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Allocating one byte more than available in free node; expecting page allocation */
+ TESTCASE( MEMTEST( ptr8, EFFECTIVE + 1 - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) );
+ TESTCASE( test_nodes( "Allocating one byte more than available in free node.", 9,
+ _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ),
+ EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ),
+ 0 ) );
+
+ /* Re-allocating with NULL pointer; expecting no page allocation, no node split */
+ ptr9 = realloc( NULL, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) );
+ TESTCASE( ptr9 != NULL );
+ TESTCASE( memset( ptr9, 0, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) == ptr9 );
+ TESTCASE( test_nodes( "Re-allocating with NULL pointer.", 9, 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+#define TESTSIZE 3000
+ TESTCASE( MEMTEST( ptrA, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 10,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+ TESTCASE( MEMTEST( ptrB, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 11,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Allocating a bit more than half a page; expecting page allocation, node split */
+ TESTCASE( MEMTEST( ptrC, TESTSIZE ) );
+ TESTCASE( test_nodes( "Allocating a bit more than half a page.", 12,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ 0 ) );
+
+ /* Freeing the middle node */
+ free( ptrB );
+ TESTCASE( test_nodes( "Freeing the middle node.", 12,
+ _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE,
+ EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE,
+ _PDCLIB_PAGESIZE * 10,
+ TESTSIZE,
+ 0 ) );
+
+#else
+ puts( " NOTEST malloc() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/qsort.c b/src/pdclib/functions/stdlib/qsort.c
new file mode 100644
index 0000000..d28f74c
--- /dev/null
+++ b/src/pdclib/functions/stdlib/qsort.c
@@ -0,0 +1,166 @@
+/* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+/* This implementation is taken from Paul Edward's PDPCLIB.
+
+ Original code is credited to Raymond Gardner, Englewood CO.
+ Minor mods are credited to Paul Edwards.
+ Some reformatting and simplification done by Martin Baute.
+ All code is still Public Domain.
+*/
+
+/* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */
+static _PDCLIB_inline void memswp( char * i, char * j, size_t size )
+{
+ _PDCLIB_memswp( i, j, size );
+}
+
+/* For small sets, insertion sort is faster than quicksort.
+ T is the threshold below which insertion sort will be used.
+ Must be 3 or larger.
+*/
+#define T 7
+
+/* Macros for handling the QSort stack */
+#define PREPARE_STACK char * stack[STACKSIZE]; char * * stackptr = stack
+#define PUSH( base, limit ) stackptr[0] = base; stackptr[1] = limit; stackptr += 2
+#define POP( base, limit ) stackptr -= 2; base = stackptr[0]; limit = stackptr[1]
+/* TODO: Stack usage is log2( nmemb ) (minus what T shaves off the worst case).
+ Worst-case nmemb is platform dependent and should probably be
+ configured through _PDCLIB_config.h.
+*/
+#define STACKSIZE 64
+
+void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
+{
+ char * i;
+ char * j;
+ _PDCLIB_size_t thresh = T * size;
+ char * base_ = (char *)base;
+ char * limit = base_ + nmemb * size;
+ PREPARE_STACK;
+
+ for ( ;; )
+ {
+ if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */
+ {
+ /* We work from second to last - first will be pivot element. */
+ i = base_ + size;
+ j = limit - size;
+ /* We swap first with middle element, then sort that with second
+ and last element so that eventually first element is the median
+ of the three - avoiding pathological pivots.
+ TODO: Instead of middle element, chose one randomly.
+ */
+ memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
+ if ( compar( i, j ) > 0 ) memswp( i, j, size );
+ if ( compar( base_, j ) > 0 ) memswp( base_, j, size );
+ if ( compar( i, base_ ) > 0 ) memswp( i, base_, size );
+ /* Now we have the median for pivot element, entering main Quicksort. */
+ for ( ;; )
+ {
+ do
+ {
+ /* move i right until *i >= pivot */
+ i += size;
+ } while ( compar( i, base_ ) < 0 );
+ do
+ {
+ /* move j left until *j <= pivot */
+ j -= size;
+ } while ( compar( j, base_ ) > 0 );
+ if ( i > j )
+ {
+ /* break loop if pointers crossed */
+ break;
+ }
+ /* else swap elements, keep scanning */
+ memswp( i, j, size );
+ }
+ /* move pivot into correct place */
+ memswp( base_, j, size );
+ /* larger subfile base / limit to stack, sort smaller */
+ if ( j - base_ > limit - i )
+ {
+ /* left is larger */
+ PUSH( base_, j );
+ base_ = i;
+ }
+ else
+ {
+ /* right is larger */
+ PUSH( i, limit );
+ limit = j;
+ }
+ }
+ else /* insertion sort for less than T elements */
+ {
+ for ( j = base_, i = j + size; i < limit; j = i, i += size )
+ {
+ for ( ; compar( j, j + size ) > 0; j -= size )
+ {
+ memswp( j, j + size, size );
+ if ( j == base_ )
+ {
+ break;
+ }
+ }
+ }
+ if ( stackptr != stack ) /* if any entries on stack */
+ {
+ POP( base_, limit );
+ }
+ else /* else stack empty, done */
+ {
+ break;
+ }
+ }
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+#include <limits.h>
+
+static int compare( const void * left, const void * right )
+{
+ return *( (unsigned char *)left ) - *( (unsigned char *)right );
+}
+
+int main( void )
+{
+ char presort[] = { "shreicnyjqpvozxmbt" };
+ char sorted1[] = { "bcehijmnopqrstvxyz" };
+ char sorted2[] = { "bticjqnyozpvreshxm" };
+ char s[19];
+ strcpy( s, presort );
+ qsort( s, 18, 1, compare );
+ TESTCASE( strcmp( s, sorted1 ) == 0 );
+ strcpy( s, presort );
+ qsort( s, 9, 2, compare );
+ TESTCASE( strcmp( s, sorted2 ) == 0 );
+ strcpy( s, presort );
+ qsort( s, 1, 1, compare );
+ TESTCASE( strcmp( s, presort ) == 0 );
+#if defined( REGTEST ) && ( defined( __BSD_VISIBLE ) || defined( __APPLE__ ) )
+ puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." );
+#else
+ qsort( s, 100, 0, compare );
+ TESTCASE( strcmp( s, presort ) == 0 );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/rand.c b/src/pdclib/functions/stdlib/rand.c
new file mode 100644
index 0000000..779b3b2
--- /dev/null
+++ b/src/pdclib/functions/stdlib/rand.c
@@ -0,0 +1,34 @@
+/* rand( void )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+int rand( void )
+{
+ _PDCLIB_seed = _PDCLIB_seed * 1103515245 + 12345;
+ return (int)( _PDCLIB_seed / 65536 ) % 32768;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ int rnd1, rnd2;
+ TESTCASE( ( rnd1 = rand() ) < RAND_MAX );
+ TESTCASE( ( rnd2 = rand() ) < RAND_MAX );
+ srand( 1 );
+ TESTCASE( rand() == rnd1 );
+ TESTCASE( rand() == rnd2 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/realloc.c b/src/pdclib/functions/stdlib/realloc.c
new file mode 100644
index 0000000..cbc01d4
--- /dev/null
+++ b/src/pdclib/functions/stdlib/realloc.c
@@ -0,0 +1,56 @@
+/* void * realloc( void *, size_t )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#ifndef REGTEST
+
+/* TODO: Primitive placeholder. Improve. */
+
+void * realloc( void * ptr, size_t size )
+{
+ void * newptr = NULL;
+ if ( ptr == NULL )
+ {
+ return malloc( size );
+ }
+ if ( size > 0 )
+ {
+ struct _PDCLIB_memnode_t * baseptr = (struct _PDCLIB_memnode_t *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) );
+ if ( baseptr->size >= size )
+ {
+ /* Current memnode is large enough; nothing to do. */
+ return ptr;
+ }
+ else
+ {
+ /* Get larger memnode and copy over contents. */
+ if ( ( newptr = malloc( size ) ) == NULL )
+ {
+ return NULL;
+ }
+ memcpy( newptr, ptr, baseptr->size );
+ }
+ }
+ free( ptr );
+ return newptr;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* tests covered in malloc test driver */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/srand.c b/src/pdclib/functions/stdlib/srand.c
new file mode 100644
index 0000000..39c37ec
--- /dev/null
+++ b/src/pdclib/functions/stdlib/srand.c
@@ -0,0 +1,28 @@
+/* srand( unsigned int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+void srand( unsigned int seed )
+{
+ _PDCLIB_seed = seed;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* tested in rand.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/strtol.c b/src/pdclib/functions/stdlib/strtol.c
new file mode 100644
index 0000000..d89a648
--- /dev/null
+++ b/src/pdclib/functions/stdlib/strtol.c
@@ -0,0 +1,129 @@
+/* strtol( 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 <limits.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include <stdint.h>
+
+long int strtol( const char * s, char ** endptr, int base )
+{
+ long int rc;
+ char sign = '+';
+ const char * p = _PDCLIB_strtox_prelim( s, &sign, &base );
+ if ( base < 2 || base > 36 ) return 0;
+ if ( sign == '+' )
+ {
+ rc = (long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (int)( LONG_MAX % base ), &sign );
+ }
+ else
+ {
+ rc = (long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (int)( -( LONG_MIN % base ) ), &sign );
+ }
+ if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
+ return ( sign == '+' ) ? rc : -rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+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( strtol( "123", NULL, 10 ) == 123 );
+ /* proper detecting of default base 10 */
+ TESTCASE( strtol( "456", NULL, 0 ) == 456 );
+ /* proper functioning to smaller base */
+ TESTCASE( strtol( "14", NULL, 8 ) == 12 );
+ /* proper autodetecting of octal */
+ TESTCASE( strtol( "016", NULL, 0 ) == 14 );
+ /* proper autodetecting of hexadecimal, lowercase 'x' */
+ TESTCASE( strtol( "0xFF", NULL, 0 ) == 255 );
+ /* proper autodetecting of hexadecimal, uppercase 'X' */
+ TESTCASE( strtol( "0Xa1", NULL, 0 ) == 161 );
+ /* proper handling of border case: 0x followed by non-hexdigit */
+ TESTCASE( strtol( tricky, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == tricky + 2 );
+ /* proper handling of border case: 0 followed by non-octdigit */
+ TESTCASE( strtol( 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( strtol( overflow, &endptr, 36 ) == LONG_MIN );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* same for positive */
+ errno = 0;
+ TESTCASE( strtol( overflow + 1, &endptr, 36 ) == LONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* testing skipping of leading whitespace */
+ TESTCASE( strtol( " \n\v\t\f789", NULL, 0 ) == 789 );
+ /* testing conversion failure */
+ TESTCASE( strtol( overflow, &endptr, 10 ) == 0 );
+ TESTCASE( endptr == overflow );
+ endptr = NULL;
+ TESTCASE( strtol( overflow, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == overflow );
+ /* TODO: 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 LONG_MAX >> 30 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtol( "2147483647", NULL, 0 ) == 0x7fffffff );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "2147483648", NULL, 0 ) == LONG_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtol( "-2147483647", NULL, 0 ) == (long)0x80000001 );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "-2147483648", NULL, 0 ) == LONG_MIN );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "-2147483649", NULL, 0 ) == LONG_MIN );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+#elif LONG_MAX >> 62 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtol( "9223372036854775807", NULL, 0 ) == 0x7fffffffffffffff );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "9223372036854775808", NULL, 0 ) == LONG_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtol( "-9223372036854775807", NULL, 0 ) == (long)0x8000000000000001 );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "-9223372036854775808", NULL, 0 ) == LONG_MIN );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtol( "-9223372036854775809", NULL, 0 ) == LONG_MIN );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+#else
+#error Unsupported width of 'long' (neither 32 nor 64 bit).
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/strtoll.c b/src/pdclib/functions/stdlib/strtoll.c
new file mode 100644
index 0000000..24c3e8e
--- /dev/null
+++ b/src/pdclib/functions/stdlib/strtoll.c
@@ -0,0 +1,123 @@
+/* strtoll( 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 <limits.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include <stdint.h>
+
+long long int strtoll( const char * s, char ** endptr, int base )
+{
+ long long int rc;
+ char sign = '+';
+ const char * p = _PDCLIB_strtox_prelim( s, &sign, &base );
+ if ( base < 2 || base > 36 ) return 0;
+ if ( sign == '+' )
+ {
+ rc = (long long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (int)( LLONG_MAX % base ), &sign );
+ }
+ else
+ {
+ rc = (long long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (int)( -( LLONG_MIN % base ) ), &sign );
+ }
+ if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
+ return ( sign == '+' ) ? rc : -rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+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( strtoll( "123", NULL, 10 ) == 123 );
+ /* proper detecting of default base 10 */
+ TESTCASE( strtoll( "456", NULL, 0 ) == 456 );
+ /* proper functioning to smaller base */
+ TESTCASE( strtoll( "14", NULL, 8 ) == 12 );
+ /* proper autodetecting of octal */
+ TESTCASE( strtoll( "016", NULL, 0 ) == 14 );
+ /* proper autodetecting of hexadecimal, lowercase 'x' */
+ TESTCASE( strtoll( "0xFF", NULL, 0 ) == 255 );
+ /* proper autodetecting of hexadecimal, uppercase 'X' */
+ TESTCASE( strtoll( "0Xa1", NULL, 0 ) == 161 );
+ /* proper handling of border case: 0x followed by non-hexdigit */
+ TESTCASE( strtoll( tricky, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == tricky + 2 );
+ /* proper handling of border case: 0 followed by non-octdigit */
+ TESTCASE( strtoll( 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( strtoll( overflow, &endptr, 36 ) == LLONG_MIN );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* same for positive */
+ errno = 0;
+ TESTCASE( strtoll( overflow + 1, &endptr, 36 ) == LLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* testing skipping of leading whitespace */
+ TESTCASE( strtoll( " \n\v\t\f789", NULL, 0 ) == 789 );
+ /* testing conversion failure */
+ TESTCASE( strtoll( overflow, &endptr, 10 ) == 0 );
+ TESTCASE( endptr == overflow );
+ endptr = NULL;
+ TESTCASE( strtoll( overflow, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == overflow );
+ /* TODO: 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 LLONG_MAX >> 62 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoll( "9223372036854775807", NULL, 0 ) == 0x7fffffffffffffff );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "9223372036854775808", NULL, 0 ) == LLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoll( "-9223372036854775807", NULL, 0 ) == (long long)0x8000000000000001 );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "-9223372036854775808", NULL, 0 ) == LLONG_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "-9223372036854775809", NULL, 0 ) == LLONG_MIN );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+#elif LLONG_MAX >> 126 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoll( "170141183460469231731687303715884105728", NULL, 0 ) == 0x7fffffffffffffffffffffffffffffff );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "170141183460469231731687303715884105729", NULL, 0 ) == LLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoll( "-170141183460469231731687303715884105728", NULL, 0 ) == -0x80000000000000000000000000000001 );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "-170141183460469231731687303715884105729", NULL, 0 ) == LLONG_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoll( "-170141183460469231731687303715884105730", NULL, 0 ) == LLONG_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/src/pdclib/functions/stdlib/strtoul.c b/src/pdclib/functions/stdlib/strtoul.c
new file mode 100644
index 0000000..1a93477
--- /dev/null
+++ b/src/pdclib/functions/stdlib/strtoul.c
@@ -0,0 +1,106 @@
+/* strtoul( 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 <limits.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include <stdint.h>
+
+unsigned long int strtoul( const char * s, char ** endptr, int base )
+{
+ unsigned long int rc;
+ char sign = '+';
+ const char * p = _PDCLIB_strtox_prelim( s, &sign, &base );
+ if ( base < 2 || base > 36 ) return 0;
+ rc = (unsigned long int)_PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (int)( ULONG_MAX % base ), &sign );
+ if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
+ return ( sign == '+' ) ? rc : -rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+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( strtoul( "123", NULL, 10 ) == 123 );
+ /* proper detecting of default base 10 */
+ TESTCASE( strtoul( "456", NULL, 0 ) == 456 );
+ /* proper functioning to smaller base */
+ TESTCASE( strtoul( "14", NULL, 8 ) == 12 );
+ /* proper autodetecting of octal */
+ TESTCASE( strtoul( "016", NULL, 0 ) == 14 );
+ /* proper autodetecting of hexadecimal, lowercase 'x' */
+ TESTCASE( strtoul( "0xFF", NULL, 0 ) == 255 );
+ /* proper autodetecting of hexadecimal, uppercase 'X' */
+ TESTCASE( strtoul( "0Xa1", NULL, 0 ) == 161 );
+ /* proper handling of border case: 0x followed by non-hexdigit */
+ TESTCASE( strtoul( tricky, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == tricky + 2 );
+ /* proper handling of border case: 0 followed by non-octdigit */
+ TESTCASE( strtoul( 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( strtoul( overflow, &endptr, 36 ) == ULONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* same for positive */
+ errno = 0;
+ TESTCASE( strtoul( overflow + 1, &endptr, 36 ) == ULONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* testing skipping of leading whitespace */
+ TESTCASE( strtoul( " \n\v\t\f789", NULL, 0 ) == 789 );
+ /* testing conversion failure */
+ TESTCASE( strtoul( overflow, &endptr, 10 ) == 0 );
+ TESTCASE( endptr == overflow );
+ endptr = NULL;
+ TESTCASE( strtoul( overflow, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == overflow );
+ /* TODO: 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;
+/* long -> 32 bit */
+#if ULONG_MAX >> 31 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoul( "4294967295", NULL, 0 ) == ULONG_MAX );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtoul( "4294967296", NULL, 0 ) == ULONG_MAX );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+/* long -> 64 bit */
+#elif ULONG_MAX >> 63 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoul( "18446744073709551615", NULL, 0 ) == ULONG_MAX );
+ TESTCASE( errno == 0 );
+ errno = 0;
+ TESTCASE( strtoul( "18446744073709551616", NULL, 0 ) == ULONG_MAX );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+#else
+#error Unsupported width of 'long' (neither 32 nor 64 bit).
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdlib/strtoull.c b/src/pdclib/functions/stdlib/strtoull.c
new file mode 100644
index 0000000..e207110
--- /dev/null
+++ b/src/pdclib/functions/stdlib/strtoull.c
@@ -0,0 +1,101 @@
+/* strtoull( 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 <limits.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include <stdint.h>
+
+unsigned long long int strtoull( const char * s, char ** endptr, int base )
+{
+ unsigned long long int rc;
+ char sign = '+';
+ const char * p = _PDCLIB_strtox_prelim( s, &sign, &base );
+ if ( base < 2 || base > 36 ) return 0;
+ rc = _PDCLIB_strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (int)( ULLONG_MAX % base ), &sign );
+ if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
+ return ( sign == '+' ) ? rc : -rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+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( strtoull( "123", NULL, 10 ) == 123 );
+ /* proper detecting of default base 10 */
+ TESTCASE( strtoull( "456", NULL, 0 ) == 456 );
+ /* proper functioning to smaller base */
+ TESTCASE( strtoull( "14", NULL, 8 ) == 12 );
+ /* proper autodetecting of octal */
+ TESTCASE( strtoull( "016", NULL, 0 ) == 14 );
+ /* proper autodetecting of hexadecimal, lowercase 'x' */
+ TESTCASE( strtoull( "0xFF", NULL, 0 ) == 255 );
+ /* proper autodetecting of hexadecimal, uppercase 'X' */
+ TESTCASE( strtoull( "0Xa1", NULL, 0 ) == 161 );
+ /* proper handling of border case: 0x followed by non-hexdigit */
+ TESTCASE( strtoull( tricky, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == tricky + 2 );
+ /* proper handling of border case: 0 followed by non-octdigit */
+ TESTCASE( strtoull( 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( strtoull( overflow, &endptr, 36 ) == ULLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* same for positive */
+ errno = 0;
+ TESTCASE( strtoull( overflow + 1, &endptr, 36 ) == ULLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( ( endptr - overflow ) == 53 );
+ /* testing skipping of leading whitespace */
+ TESTCASE( strtoull( " \n\v\t\f789", NULL, 0 ) == 789 );
+ /* testing conversion failure */
+ TESTCASE( strtoull( overflow, &endptr, 10 ) == 0 );
+ TESTCASE( endptr == overflow );
+ endptr = NULL;
+ TESTCASE( strtoull( overflow, &endptr, 0 ) == 0 );
+ TESTCASE( endptr == overflow );
+ errno = 0;
+/* long long -> 64 bit */
+#if ULLONG_MAX >> 63 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoull( "18446744073709551615", NULL, 0 ) == ULLONG_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoull( "18446744073709551616", NULL, 0 ) == ULLONG_MAX );
+ TESTCASE( errno == ERANGE );
+ /* TODO: test "odd" overflow, i.e. base is not power of two */
+/* long long -> 128 bit */
+#elif ULLONG_MAX >> 127 == 1
+ /* testing "even" overflow, i.e. base is power of two */
+ TESTCASE( strtoull( "340282366920938463463374607431768211455", NULL, 0 ) == ULLONG_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoull( "340282366920938463463374607431768211456", NULL, 0 ) == ULLONG_MAX );
+ 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