aboutsummaryrefslogtreecommitdiffstats
path: root/src/pdclib/functions
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
parentdb38c4b9dac461de0ed75bf6d079dacba1b31bc9 (diff)
added pdclib, removed sash
Diffstat (limited to 'src/pdclib/functions')
-rw-r--r--src/pdclib/functions/_PDCLIB/Readme.txt10
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c46
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c37
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c33
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c90
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c39
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c63
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c365
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c88
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c158
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c84
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c165
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c81
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c50
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c41
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_print.c625
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c639
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c19
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c88
-rw-r--r--src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c94
-rw-r--r--src/pdclib/functions/_PDCLIB/assert.c71
-rw-r--r--src/pdclib/functions/_PDCLIB/errno.c37
-rw-r--r--src/pdclib/functions/_PDCLIB/stdarg.c115
-rw-r--r--src/pdclib/functions/ctype/isalnum.c38
-rw-r--r--src/pdclib/functions/ctype/isalpha.c34
-rw-r--r--src/pdclib/functions/ctype/isblank.c35
-rw-r--r--src/pdclib/functions/ctype/iscntrl.c33
-rw-r--r--src/pdclib/functions/ctype/isdigit.c34
-rw-r--r--src/pdclib/functions/ctype/isgraph.c37
-rw-r--r--src/pdclib/functions/ctype/islower.c35
-rw-r--r--src/pdclib/functions/ctype/isprint.c38
-rw-r--r--src/pdclib/functions/ctype/ispunct.c38
-rw-r--r--src/pdclib/functions/ctype/isspace.c36
-rw-r--r--src/pdclib/functions/ctype/isupper.c35
-rw-r--r--src/pdclib/functions/ctype/isxdigit.c41
-rw-r--r--src/pdclib/functions/ctype/tolower.c35
-rw-r--r--src/pdclib/functions/ctype/toupper.c35
-rw-r--r--src/pdclib/functions/inttypes/imaxabs.c32
-rw-r--r--src/pdclib/functions/inttypes/imaxdiv.c39
-rw-r--r--src/pdclib/functions/inttypes/strtoimax.c147
-rw-r--r--src/pdclib/functions/inttypes/strtoumax.c111
-rw-r--r--src/pdclib/functions/locale/localeconv.c28
-rw-r--r--src/pdclib/functions/locale/setlocale.c257
-rw-r--r--src/pdclib/functions/stdio/clearerr.c52
-rw-r--r--src/pdclib/functions/stdio/fclose.c106
-rw-r--r--src/pdclib/functions/stdio/feof.c28
-rw-r--r--src/pdclib/functions/stdio/ferror.c28
-rw-r--r--src/pdclib/functions/stdio/fflush.c53
-rw-r--r--src/pdclib/functions/stdio/fgetc.c38
-rw-r--r--src/pdclib/functions/stdio/fgetpos.c43
-rw-r--r--src/pdclib/functions/stdio/fgets.c88
-rw-r--r--src/pdclib/functions/stdio/fopen.c102
-rw-r--r--src/pdclib/functions/stdio/fprintf.c43
-rw-r--r--src/pdclib/functions/stdio/fputc.c47
-rw-r--r--src/pdclib/functions/stdio/fputs.c69
-rw-r--r--src/pdclib/functions/stdio/fread.c81
-rw-r--r--src/pdclib/functions/stdio/freopen.c104
-rw-r--r--src/pdclib/functions/stdio/fscanf.c41
-rw-r--r--src/pdclib/functions/stdio/fseek.c85
-rw-r--r--src/pdclib/functions/stdio/fsetpos.c43
-rw-r--r--src/pdclib/functions/stdio/ftell.c100
-rw-r--r--src/pdclib/functions/stdio/fwrite.c93
-rw-r--r--src/pdclib/functions/stdio/getc.c28
-rw-r--r--src/pdclib/functions/stdio/getchar.c28
-rw-r--r--src/pdclib/functions/stdio/perror.c58
-rw-r--r--src/pdclib/functions/stdio/printf.c44
-rw-r--r--src/pdclib/functions/stdio/putc.c28
-rw-r--r--src/pdclib/functions/stdio/putchar.c28
-rw-r--r--src/pdclib/functions/stdio/puts.c67
-rw-r--r--src/pdclib/functions/stdio/rename.c84
-rw-r--r--src/pdclib/functions/stdio/rewind.c29
-rw-r--r--src/pdclib/functions/stdio/scanf.c39
-rw-r--r--src/pdclib/functions/stdio/setbuf.c55
-rw-r--r--src/pdclib/functions/stdio/setvbuf.c108
-rw-r--r--src/pdclib/functions/stdio/snprintf.c43
-rw-r--r--src/pdclib/functions/stdio/sprintf.c41
-rw-r--r--src/pdclib/functions/stdio/sscanf.c39
-rw-r--r--src/pdclib/functions/stdio/testfile.txtbin0 -> 532 bytes
-rw-r--r--src/pdclib/functions/stdio/tmpnam.c42
-rw-r--r--src/pdclib/functions/stdio/ungetc.c32
-rw-r--r--src/pdclib/functions/stdio/vfprintf.c74
-rw-r--r--src/pdclib/functions/stdio/vfscanf.c113
-rw-r--r--src/pdclib/functions/stdio/vprintf.c46
-rw-r--r--src/pdclib/functions/stdio/vscanf.c45
-rw-r--r--src/pdclib/functions/stdio/vsnprintf.c80
-rw-r--r--src/pdclib/functions/stdio/vsprintf.c44
-rw-r--r--src/pdclib/functions/stdio/vsscanf.c109
-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
-rw-r--r--src/pdclib/functions/string/memchr.c41
-rw-r--r--src/pdclib/functions/string/memcmp.c43
-rw-r--r--src/pdclib/functions/string/memcpy.c40
-rw-r--r--src/pdclib/functions/string/memmove.c52
-rw-r--r--src/pdclib/functions/string/memset.c40
-rw-r--r--src/pdclib/functions/string/strcat.c46
-rw-r--r--src/pdclib/functions/string/strchr.c40
-rw-r--r--src/pdclib/functions/string/strcmp.c41
-rw-r--r--src/pdclib/functions/string/strcoll.c46
-rw-r--r--src/pdclib/functions/string/strcpy.c37
-rw-r--r--src/pdclib/functions/string/strcspn.c50
-rw-r--r--src/pdclib/functions/string/strerror.c41
-rw-r--r--src/pdclib/functions/string/strlen.c34
-rw-r--r--src/pdclib/functions/string/strncat.c60
-rw-r--r--src/pdclib/functions/string/strncmp.c54
-rw-r--r--src/pdclib/functions/string/strncpy.c56
-rw-r--r--src/pdclib/functions/string/strpbrk.c49
-rw-r--r--src/pdclib/functions/string/strrchr.c41
-rw-r--r--src/pdclib/functions/string/strspn.c49
-rw-r--r--src/pdclib/functions/string/strstr.c51
-rw-r--r--src/pdclib/functions/string/strtok.c107
-rw-r--r--src/pdclib/functions/string/strxfrm.c50
-rw-r--r--src/pdclib/functions/time/asctime.c28
-rw-r--r--src/pdclib/functions/time/ctime.c28
-rw-r--r--src/pdclib/functions/time/difftime.c70
-rw-r--r--src/pdclib/functions/time/gmtime.c28
-rw-r--r--src/pdclib/functions/time/localtime.c28
-rw-r--r--src/pdclib/functions/time/mktime.c28
-rw-r--r--src/pdclib/functions/time/strftime.c1719
141 files changed, 11516 insertions, 0 deletions
diff --git a/src/pdclib/functions/_PDCLIB/Readme.txt b/src/pdclib/functions/_PDCLIB/Readme.txt
new file mode 100644
index 0000000..13ad05c
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/Readme.txt
@@ -0,0 +1,10 @@
+This directory holds various "internals" of PDCLib:
+
+- definitions of helper functions not specified by the standard (hidden in the
+ _PDCLIB_* namespace);
+
+- definitions of data objects, both internal (like _PDCLIB_digits) and specified by
+ the standard (_PDCLIB_errno);
+
+- test drivers for functionality that does not have its own implementation
+ file to put the test driver in (stdarg).
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c
new file mode 100644
index 0000000..eaf7ced
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_atomax.c
@@ -0,0 +1,46 @@
+/* _PDCLIB_atomax( 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 <string.h>
+#include <ctype.h>
+
+#ifndef REGTEST
+
+_PDCLIB_intmax_t _PDCLIB_atomax( const char * s )
+{
+ _PDCLIB_intmax_t rc = 0;
+ char sign = '+';
+ const char * x;
+ /* TODO: In other than "C" locale, additional patterns may be defined */
+ while ( isspace( *s ) ) ++s;
+ if ( *s == '+' ) ++s;
+ else if ( *s == '-' ) sign = *(s++);
+ /* TODO: Earlier version was missing tolower() but was not caught by tests */
+ while ( ( x = memchr( _PDCLIB_digits, tolower(*(s++)), 10 ) ) != NULL )
+ {
+ rc = rc * 10 + ( x - _PDCLIB_digits );
+ }
+ return ( sign == '+' ) ? rc : -rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ /* basic functionality */
+ TESTCASE( _PDCLIB_atomax( "123" ) == 123 );
+ /* testing skipping of leading whitespace and trailing garbage */
+ TESTCASE( _PDCLIB_atomax( " \n\v\t\f123xyz" ) == 123 );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c
new file mode 100644
index 0000000..3c928e7
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_closeall.c
@@ -0,0 +1,37 @@
+/* _PDCLIB_closeall( void )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+void _PDCLIB_closeall( void )
+{
+ struct _PDCLIB_file_t * stream = _PDCLIB_filelist;
+ struct _PDCLIB_file_t * next;
+ while ( stream != NULL )
+ {
+ next = stream->next;
+ fclose( stream );
+ stream = next;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* No testdriver */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c
new file mode 100644
index 0000000..69c4f2b
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_digits.c
@@ -0,0 +1,33 @@
+/* _PDCLIB_digits
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_int.h"
+
+const char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+/* For _PDCLIB/print.c only; obsolete with ctype.h */
+const char _PDCLIB_Xdigits[] = "0123456789ABCDEF";
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+#ifndef REGTEST
+ TESTCASE( strcmp( _PDCLIB_digits, "0123456789abcdefghijklmnopqrstuvwxyz" ) == 0 );
+ TESTCASE( strcmp( _PDCLIB_Xdigits, "0123456789ABCDEF" ) == 0 );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c
new file mode 100644
index 0000000..2555a00
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_filemode.c
@@ -0,0 +1,90 @@
+/* _PDCLIB_filemode( 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 <stddef.h>
+
+#ifndef REGTEST
+
+/* Helper function that parses the C-style mode string passed to fopen() into
+ the PDCLib flags FREAD, FWRITE, FAPPEND, FRW (read-write) and FBIN (binary
+ mode).
+*/
+unsigned int _PDCLIB_filemode( const char * const mode )
+{
+ unsigned rc = 0;
+ size_t i;
+ switch ( mode[0] )
+ {
+ case 'r':
+ rc |= _PDCLIB_FREAD;
+ break;
+ case 'w':
+ rc |= _PDCLIB_FWRITE;
+ break;
+ case 'a':
+ rc |= _PDCLIB_FAPPEND | _PDCLIB_FWRITE;
+ break;
+ default:
+ /* Other than read, write, or append - invalid */
+ return 0;
+ }
+ for ( i = 1; i < 4; ++i )
+ {
+ switch ( mode[i] )
+ {
+ case '+':
+ if ( rc & _PDCLIB_FRW ) return 0; /* Duplicates are invalid */
+ rc |= _PDCLIB_FRW;
+ break;
+ case 'b':
+ if ( rc & _PDCLIB_FBIN ) return 0; /* Duplicates are invalid */
+ rc |= _PDCLIB_FBIN;
+ break;
+ case '\0':
+ /* End of mode */
+ return rc;
+ default:
+ /* Other than read/write or binary - invalid. */
+ return 0;
+ }
+ }
+ /* Longer than three chars - invalid. */
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ TESTCASE( _PDCLIB_filemode( "r" ) == _PDCLIB_FREAD );
+ TESTCASE( _PDCLIB_filemode( "w" ) == _PDCLIB_FWRITE );
+ TESTCASE( _PDCLIB_filemode( "a" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE ) );
+ TESTCASE( _PDCLIB_filemode( "r+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW ) );
+ TESTCASE( _PDCLIB_filemode( "w+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW ) );
+ TESTCASE( _PDCLIB_filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW ) );
+ TESTCASE( _PDCLIB_filemode( "rb" ) == ( _PDCLIB_FREAD | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "wb" ) == ( _PDCLIB_FWRITE | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "r+b" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "w+b" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "rb+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "wb+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) );
+ TESTCASE( _PDCLIB_filemode( "x" ) == 0 );
+ TESTCASE( _PDCLIB_filemode( "r++" ) == 0 );
+ TESTCASE( _PDCLIB_filemode( "wbb" ) == 0 );
+ TESTCASE( _PDCLIB_filemode( "a+bx" ) == 0 );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c
new file mode 100644
index 0000000..2407337
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_is_leap.c
@@ -0,0 +1,39 @@
+/* _PDCLIB_is_leap( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_int.h"
+
+int _PDCLIB_is_leap( int year_offset )
+{
+ /* year given as offset from 1900, matching tm.tm_year in <time.h> */
+ long long year = year_offset + 1900ll;
+ return ( ( year % 4 ) == 0 && ( ( year % 25 ) != 0 || ( year % 400 ) == 0 ) );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ /* 1901 not leap */
+ TESTCASE( ! _PDCLIB_is_leap( 1 ) );
+ /* 1904 leap */
+ TESTCASE( _PDCLIB_is_leap( 4 ) );
+ /* 1900 not leap */
+ TESTCASE( ! _PDCLIB_is_leap( 0 ) );
+ /* 2000 leap */
+ TESTCASE( _PDCLIB_is_leap( 100 ) );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c
new file mode 100644
index 0000000..d66b996
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_collate.c
@@ -0,0 +1,63 @@
+/* _PDCLIB_load_lc_collate( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_collate_t * _PDCLIB_load_lc_collate( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_collate_t * rc = NULL;
+ const char * extension = "_collate.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_collate_t ) ) ) != NULL )
+ {
+ /* TODO: Collation data */
+
+ rc->alloced = 1;
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ TESTCASE( NO_TESTDRIVER );
+#endif
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c
new file mode 100644
index 0000000..81fb18f
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_ctype.c
@@ -0,0 +1,365 @@
+/* _PDCLIB_load_lc_ctype( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_ctype_t * _PDCLIB_load_lc_ctype( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_ctype_t * rc = NULL;
+ const char * extension = "_ctype.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_ctype_t ) ) ) != NULL )
+ {
+ struct _PDCLIB_lc_ctype_entry_t * entry;
+
+ if ( ( entry = malloc( sizeof( struct _PDCLIB_lc_ctype_entry_t ) * _PDCLIB_CHARSET_SIZE + 1 ) ) != NULL )
+ {
+ rc->entry = entry + 1;
+ rc->entry[ -1 ].flags = rc->entry[ -1 ].upper = rc->entry[ -1 ].lower = 0;
+
+ if ( fscanf( fh, "%x %x %x %x %x %x", &rc->digits_low, &_PDCLIB_lc_ctype.digits_high, &_PDCLIB_lc_ctype.Xdigits_low, &_PDCLIB_lc_ctype.Xdigits_high, &_PDCLIB_lc_ctype.xdigits_low, &_PDCLIB_lc_ctype.xdigits_high ) == 6 )
+ {
+ size_t i;
+
+ for ( i = 0; i < _PDCLIB_CHARSET_SIZE; ++i )
+ {
+ if ( fscanf( fh, "%x %hhx %hhx", &rc->entry[ i ].flags, &rc->entry[ i ].upper, &rc->entry[ i ].lower ) != 3 )
+ {
+ fclose( fh );
+ free( file );
+ free( rc->entry - 1 );
+ free( rc );
+ return NULL;
+ }
+ }
+ }
+
+ rc->alloced = 1;
+ }
+ else
+ {
+ free( rc );
+ }
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <ctype.h>
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_ctype.dat", "wb" );
+ TESTCASE( fh != NULL );
+ /* For test purposes, let's set up a charset that only has the hex digits */
+ /* 0x00..0x09 - digits */
+ /* 0x11..0x16 - Xdigits */
+ /* 0x21..0x26 - xdigits */
+ TESTCASE( fprintf( fh, "%x %x\n", 0x00, 0x09 ) );
+ TESTCASE( fprintf( fh, "%x %x %x %x\n", 0x11, 0x16, 0x21, 0x26 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x00, 0x00 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x01, 0x01 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x02, 0x02 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x03, 0x03 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x04, 0x04 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x05, 0x05 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x06, 0x06 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x07, 0x07 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x08, 0x08 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH, 0x09, 0x09 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0A, 0x0A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0B, 0x0B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0C, 0x0C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0D, 0x0D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0E, 0x0E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x0F, 0x0F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x10, 0x10 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x11, 0x11 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x12, 0x12 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x13, 0x13 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x14, 0x14 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x15, 0x15 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_UPPER, 0x16, 0x16 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x17, 0x17 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x18, 0x18 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x19, 0x19 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1A, 0x1A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1B, 0x1B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1C, 0x1C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1D, 0x1D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1E, 0x1E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x1F, 0x1F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x20, 0x20 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x21, 0x21 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x22, 0x22 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x23, 0x23 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x24, 0x24 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x25, 0x25 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", _PDCLIB_CTYPE_GRAPH | _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_LOWER, 0x26, 0x26 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x27, 0x27 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x28, 0x28 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x29, 0x29 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2A, 0x2A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2B, 0x2B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2C, 0x2C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2D, 0x2D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2E, 0x2E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x2F, 0x2F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x30, 0x30 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x31, 0x31 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x32, 0x32 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x33, 0x33 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x34, 0x34 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x35, 0x35 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x36, 0x36 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x37, 0x37 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x38, 0x38 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x39, 0x39 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3A, 0x3A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3B, 0x3B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3C, 0x3C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3D, 0x3D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3E, 0x3E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x3F, 0x3F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x40, 0x40 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x41, 0x41 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x42, 0x42 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x43, 0x43 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x44, 0x44 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x45, 0x45 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x46, 0x46 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x47, 0x47 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x48, 0x48 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x49, 0x49 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4A, 0x4A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4B, 0x4B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4C, 0x4C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4D, 0x4D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4E, 0x4E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x4F, 0x4F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x50, 0x50 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x51, 0x51 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x52, 0x52 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x53, 0x53 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x54, 0x54 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x55, 0x55 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x56, 0x56 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x57, 0x57 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x58, 0x58 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x59, 0x59 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5A, 0x5A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5B, 0x5B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5C, 0x5C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5D, 0x5D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5E, 0x5E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x5F, 0x5F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x60, 0x60 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x61, 0x61 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x62, 0x62 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x63, 0x63 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x64, 0x64 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x65, 0x65 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x66, 0x66 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x67, 0x67 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x68, 0x68 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x69, 0x69 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6A, 0x6A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6B, 0x6B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6C, 0x6C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6D, 0x6D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6E, 0x6E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x6F, 0x6F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x70, 0x70 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x71, 0x71 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x72, 0x72 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x73, 0x73 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x74, 0x74 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x75, 0x75 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x76, 0x76 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x77, 0x77 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x78, 0x78 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x79, 0x79 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7A, 0x7A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7B, 0x7B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7C, 0x7C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7D, 0x7D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7E, 0x7E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x7F, 0x7F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x80, 0x80 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x81, 0x81 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x82, 0x82 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x83, 0x83 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x84, 0x84 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x85, 0x85 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x86, 0x86 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x87, 0x87 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x88, 0x88 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x89, 0x89 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8A, 0x8A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8B, 0x8B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8C, 0x8C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8D, 0x8D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8E, 0x8E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x8F, 0x8F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x90, 0x90 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x91, 0x91 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x92, 0x92 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x93, 0x93 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x94, 0x94 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x95, 0x95 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x96, 0x96 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x97, 0x97 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x98, 0x98 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x99, 0x99 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9A, 0x9A ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9B, 0x9B ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9C, 0x9C ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9D, 0x9D ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9E, 0x9E ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0x9F, 0x9F ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA0, 0xA0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA1, 0xA1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA2, 0xA2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA3, 0xA3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA4, 0xA4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA5, 0xA5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA6, 0xA6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA7, 0xA7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA8, 0xA8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xA9, 0xA9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAA, 0xAA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAB, 0xAB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAC, 0xAC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAD, 0xAD ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAE, 0xAE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xAF, 0xAF ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB0, 0xB0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB1, 0xB1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB2, 0xB2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB3, 0xB3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB4, 0xB4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB5, 0xB5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB6, 0xB6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB7, 0xB7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB8, 0xB8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xB9, 0xB9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBA, 0xBA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBB, 0xBB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBC, 0xBC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBD, 0xBD ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBE, 0xBE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xBF, 0xBF ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC0, 0xC0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC1, 0xC1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC2, 0xC2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC3, 0xC3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC4, 0xC4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC5, 0xC5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC6, 0xC6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC7, 0xC7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC8, 0xC8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xC9, 0xC9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCA, 0xCA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCB, 0xCB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCC, 0xCC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCD, 0xCD ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCE, 0xCE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xCF, 0xCF ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD0, 0xD0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD1, 0xD1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD2, 0xD2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD3, 0xD3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD4, 0xD4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD5, 0xD5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD6, 0xD6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD7, 0xD7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD8, 0xD8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xD9, 0xD9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDA, 0xDA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDB, 0xDB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDC, 0xDC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDD, 0xDD ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDE, 0xDE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xDF, 0xDF ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE0, 0xE0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE1, 0xE1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE2, 0xE2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE3, 0xE3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE4, 0xE4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE5, 0xE5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE6, 0xE6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE7, 0xE7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE8, 0xE8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xE9, 0xE9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEA, 0xEA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEB, 0xEB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEC, 0xEC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xED, 0xED ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEE, 0xEE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xEF, 0xEF ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF0, 0xF0 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF1, 0xF1 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF2, 0xF2 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF3, 0xF3 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF4, 0xF4 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF5, 0xF5 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF6, 0xF6 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF7, 0xF7 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF8, 0xF8 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xF9, 0xF9 ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFA, 0xFA ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFB, 0xFB ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFC, 0xFC ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFD, 0xFD ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFE, 0xFE ) );
+ TESTCASE( fprintf( fh, "%x %x %x\n", 0x00, 0xFF, 0xFF) );
+ fclose( fh );
+ TESTCASE( _PDCLIB_load_lc_ctype( "./", "test" ) != NULL );
+ remove( "test_ctype.dat" );
+ /*
+ TESTCASE( isdigit( 0x00 ) && ! isxdigit( 0x00 ) && ! isalpha( 0x00 ) );
+ TESTCASE( ! isdigit( 0x11 ) && isxdigit( 0x11 ) && isalpha( 0x11 ) && isupper( 0x11 ) && ! islower( 0x11 ) );
+ TESTCASE( ! isdigit( 0x21 ) && isxdigit( 0x21 ) && isalpha( 0x21 ) && ! isupper( 0x11 ) && islower( 0x11 ) );
+ */
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c
new file mode 100644
index 0000000..6ff2a50
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_messages.c
@@ -0,0 +1,88 @@
+/* _PDCLIB_load_lc_messages( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_messages_t * _PDCLIB_load_lc_messages( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_messages_t * rc = NULL;
+ const char * extension = "_messages.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_messages_t ) ) ) != NULL )
+ {
+ char * data = _PDCLIB_load_lines( fh, _PDCLIB_ERRNO_MAX );
+
+ if ( data != NULL )
+ {
+ size_t i;
+
+ for ( i = 0; i < _PDCLIB_ERRNO_MAX; ++i )
+ {
+ rc->errno_texts[ i ] = data;
+ data += strlen( data ) + 1;
+ }
+
+ rc->alloced = 1;
+ }
+ else
+ {
+ free( rc );
+ rc = NULL;
+ }
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_numeric.dat", "wb" );
+ struct _PDCLIB_lc_lconv_numeric_t * lc;
+ TESTCASE( fh != NULL );
+ TESTCASE( fputs( ",\n.\n\n", fh ) != EOF );
+ fclose( fh );
+ TESTCASE( ( lc = _PDCLIB_load_lc_numeric( "./", "test" ) ) );
+ remove( "test_numeric.dat" );
+ TESTCASE( strcmp( lc->decimal_point, "," ) == 0 );
+ TESTCASE( strcmp( lc->thousands_sep, "." ) == 0 );
+ TESTCASE( strcmp( lc->grouping, "" ) == 0 );
+#endif
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c
new file mode 100644
index 0000000..e2dcbb4
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_monetary.c
@@ -0,0 +1,158 @@
+/* _PDCLIB_load_lc_monetary( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_lconv_monetary_t * _PDCLIB_load_lc_monetary( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_lconv_monetary_t * rc = NULL;
+ const char * extension = "_monetary.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_lconv_monetary_t ) ) ) != NULL )
+ {
+ char buffer[ 14 ];
+ char * data = _PDCLIB_load_lines( fh, 7 );
+
+ if ( data != NULL )
+ {
+ if ( fread( buffer, 1, 14, fh ) == 14 )
+ {
+ rc->mon_decimal_point = data;
+ data += strlen( data ) + 1;
+ rc->mon_thousands_sep = data;
+ data += strlen( data ) + 1;
+ rc->mon_grouping = data;
+ data += strlen( data ) + 1;
+ rc->positive_sign = data;
+ data += strlen( data ) + 1;
+ rc->negative_sign = data;
+ data += strlen( data ) + 1;
+ rc->currency_symbol = data;
+ data += strlen( data ) + 1;
+ rc->int_curr_symbol = data;
+
+ rc->frac_digits = buffer[ 0 ];
+ rc->p_cs_precedes = buffer[ 1 ];
+ rc->n_cs_precedes = buffer[ 2 ];
+ rc->p_sep_by_space = buffer[ 3 ];
+ rc->n_sep_by_space = buffer[ 4 ];
+ rc->p_sign_posn = buffer[ 5 ];
+ rc->n_sign_posn = buffer[ 6 ];
+ rc->int_frac_digits = buffer[ 7 ];
+ rc->int_p_cs_precedes = buffer[ 8 ];
+ rc->int_n_cs_precedes = buffer[ 9 ];
+ rc->int_p_sep_by_space = buffer[ 10 ];
+ rc->int_n_sep_by_space = buffer[ 11 ];
+ rc->int_p_sign_posn = buffer[ 12 ];
+ rc->int_n_sign_posn= buffer[ 13 ];
+ }
+ else
+ {
+ free( data );
+ free( rc );
+ rc = NULL;
+ }
+ }
+ else
+ {
+ free( rc );
+ rc = NULL;
+ }
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_monetary.dat", "wb" );
+ struct _PDCLIB_lc_lconv_monetary_t * lc;
+ TESTCASE( fh != NULL );
+ fprintf( fh, "%s\n", "," ); /* mon_decimal_point */
+ fprintf( fh, "%s\n", "." ); /* mon_thousands_sep */
+ fprintf( fh, "%s\n", "3" ); /* mon_grouping */
+ fprintf( fh, "%s\n", "" ); /* positive_sign */
+ fprintf( fh, "%s\n", "-" ); /* negative_sign */
+ fprintf( fh, "%s\n", "\xa4" ); /* currency_symbol */
+ fprintf( fh, "%s\n", "EUR" ); /* int_curr_symbol */
+ fputc( 2, fh ); /* frac_digits */
+ fputc( 0, fh ); /* p_cs_precedes */
+ fputc( 0, fh ); /* n_cs_precedes */
+ fputc( 1, fh ); /* p_sep_by_space */
+ fputc( 1, fh ); /* n_sep_by_space */
+ fputc( 1, fh ); /* p_sign_posn */
+ fputc( 1, fh ); /* n_sign_posn */
+ fputc( 2, fh ); /* int_frac_digits */
+ fputc( 0, fh ); /* int_p_cs_precedes */
+ fputc( 0, fh ); /* int_n_cs_precedes */
+ fputc( 1, fh ); /* int_p_sep_by_space */
+ fputc( 1, fh ); /* int_n_sep_by_space */
+ fputc( 1, fh ); /* int_p_sign_posn */
+ fputc( 1, fh ); /* int_n_sign_posn */
+ fprintf( fh, "\n" );
+ fclose( fh );
+ TESTCASE( ( lc = _PDCLIB_load_lc_monetary( "./", "test" ) ) );
+ remove( "test_monetary.dat" );
+ TESTCASE( strcmp( lc->mon_decimal_point, "," ) == 0 );
+ TESTCASE( strcmp( lc->mon_thousands_sep, "." ) == 0 );
+ TESTCASE( strcmp( lc->mon_grouping, "3" ) == 0 );
+ TESTCASE( strcmp( lc->positive_sign, "" ) == 0 );
+ TESTCASE( strcmp( lc->negative_sign, "-" ) == 0 );
+ TESTCASE( strcmp( lc->currency_symbol, "\xa4" ) == 0 );
+ TESTCASE( strcmp( lc->int_curr_symbol, "EUR" ) == 0 );
+
+ TESTCASE( lc->frac_digits == 2 );
+ TESTCASE( lc->p_cs_precedes == 0 );
+ TESTCASE( lc->n_cs_precedes == 0 );
+ TESTCASE( lc->p_sep_by_space == 1 );
+ TESTCASE( lc->n_sep_by_space == 1 );
+ TESTCASE( lc->p_sign_posn == 1 );
+ TESTCASE( lc->n_sign_posn == 1 );
+ TESTCASE( lc->int_frac_digits == 2 );
+ TESTCASE( lc->int_p_cs_precedes == 0 );
+ TESTCASE( lc->int_n_cs_precedes == 0 );
+ TESTCASE( lc->int_p_sep_by_space == 1 );
+ TESTCASE( lc->int_n_sep_by_space == 1 );
+ TESTCASE( lc->int_p_sign_posn == 1 );
+ TESTCASE( lc->int_n_sign_posn == 1 );
+#endif
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c
new file mode 100644
index 0000000..de42bbd
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_numeric.c
@@ -0,0 +1,84 @@
+/* _PDCLIB_load_lc_numeric( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_lconv_numeric_t * _PDCLIB_load_lc_numeric( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_lconv_numeric_t * rc = NULL;
+ const char * extension = "_numeric.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_lconv_numeric_t ) ) ) != NULL )
+ {
+ char * data = _PDCLIB_load_lines( fh, 3 );
+
+ if ( data != NULL )
+ {
+ rc->decimal_point = data;
+ data += strlen( data ) + 1;
+ rc->thousands_sep = data;
+ data += strlen( data ) + 1;
+ rc->grouping = data;
+ }
+ else
+ {
+ free( rc );
+ rc = NULL;
+ }
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_numeric.dat", "wb" );
+ struct _PDCLIB_lc_lconv_numeric_t * lc;
+ TESTCASE( fh != NULL );
+ TESTCASE( fputs( ",\n.\n\n", fh ) != EOF );
+ fclose( fh );
+ TESTCASE( ( lc = _PDCLIB_load_lc_numeric( "./", "test" ) ) );
+ remove( "test_numeric.dat" );
+ TESTCASE( strcmp( lc->decimal_point, "," ) == 0 );
+ TESTCASE( strcmp( lc->thousands_sep, "." ) == 0 );
+ TESTCASE( strcmp( lc->grouping, "" ) == 0 );
+#endif
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c
new file mode 100644
index 0000000..733e5c7
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lc_time.c
@@ -0,0 +1,165 @@
+/* _PDCLIB_load_lc_time( const char *, const char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pdclib/_PDCLIB_int.h"
+
+struct _PDCLIB_lc_time_t * _PDCLIB_load_lc_time( const char * path, const char * locale )
+{
+ struct _PDCLIB_lc_time_t * rc = NULL;
+ const char * extension = "_time.dat";
+ char * file = malloc( strlen( path ) + strlen( locale ) + strlen( extension ) + 1 );
+
+ if ( file )
+ {
+ FILE * fh;
+
+ strcpy( file, path );
+ strcat( file, locale );
+ strcat( file, extension );
+
+ if ( ( fh = fopen( file, "rb" ) ) != NULL )
+ {
+ if ( ( rc = malloc( sizeof( struct _PDCLIB_lc_time_t ) ) ) != NULL )
+ {
+ char * data = _PDCLIB_load_lines( fh, 44 );
+
+ if ( data != NULL )
+ {
+ size_t i;
+
+ for ( i = 0; i < 12; ++i )
+ {
+ rc->month_name_abbr[ i ] = data;
+ data += strlen( data ) + 1;
+ }
+
+ for ( i = 0; i < 12; ++i )
+ {
+ rc->month_name_full[ i ] = data;
+ data += strlen( data ) + 1;
+ }
+
+ for ( i = 0; i < 7; ++i )
+ {
+ rc->day_name_abbr[ i ] = data;
+ data += strlen( data ) + 1;
+ }
+
+ for ( i = 0; i < 7; ++i )
+ {
+ rc->day_name_full[ i ] = data;
+ data += strlen( data ) + 1;
+ }
+
+ rc->alloced = 1;
+ }
+ else
+ {
+ free( rc );
+ rc = NULL;
+ }
+ }
+
+ fclose( fh );
+ }
+
+ free( file );
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_time.dat", "wb" );
+ struct _PDCLIB_lc_time_t * lc;
+
+ TESTCASE( fh != NULL );
+
+ /* month name abbreviation */
+ TESTCASE( fprintf( fh, "%s\n", "Jan" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Feb" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "M\xe4r" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Apr" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Mai" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Jun" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Jul" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Aug" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Sep" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Okt" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Nov" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Dez" ) == 4 );
+ /* month name full */
+ TESTCASE( fprintf( fh, "%s\n", "Januar" ) == 7 );
+ TESTCASE( fprintf( fh, "%s\n", "Februar" ) == 8 );
+ TESTCASE( fprintf( fh, "%s\n", "M\xe4rz" ) == 5 );
+ TESTCASE( fprintf( fh, "%s\n", "April" ) == 6 );
+ TESTCASE( fprintf( fh, "%s\n", "Mai" ) == 4 );
+ TESTCASE( fprintf( fh, "%s\n", "Juni" ) == 5 );
+ TESTCASE( fprintf( fh, "%s\n", "Juli" ) == 5 );
+ TESTCASE( fprintf( fh, "%s\n", "August" ) == 7 );
+ TESTCASE( fprintf( fh, "%s\n", "September" ) == 10 );
+ TESTCASE( fprintf( fh, "%s\n", "Oktober" ) == 8 );
+ TESTCASE( fprintf( fh, "%s\n", "November" ) == 9 );
+ TESTCASE( fprintf( fh, "%s\n", "Dezember" ) == 9 );
+ /* day name abbreviation */
+ TESTCASE( fprintf( fh, "%s\n", "So" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Mo" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Di" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Mi" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Do" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Fr" ) == 3 );
+ TESTCASE( fprintf( fh, "%s\n", "Sa" ) == 3 );
+ /* day name full */
+ TESTCASE( fprintf( fh, "%s\n", "Sonntag" ) == 8 );
+ TESTCASE( fprintf( fh, "%s\n", "Montag" ) == 7 );
+ TESTCASE( fprintf( fh, "%s\n", "Dienstag" ) == 9 );
+ TESTCASE( fprintf( fh, "%s\n", "Mittwoch" ) == 9 );
+ TESTCASE( fprintf( fh, "%s\n", "Donnerstag" ) == 11 );
+ TESTCASE( fprintf( fh, "%s\n", "Freitag" ) == 8 );
+ TESTCASE( fprintf( fh, "%s\n", "Samstag" ) == 8 );
+
+ TESTCASE( fprintf( fh, "%s\n", "%a %d %b %Y %T %Z" ) == 18 ); /* date time format (%c) */
+ TESTCASE( fprintf( fh, "%s\n", "%I:%M:%S" ) == 9 ); /* 12-hour time format (%r) */
+ TESTCASE( fprintf( fh, "%s\n", "%d.%m.%Y" ) == 9 ); /* date format (%x) */
+ TESTCASE( fprintf( fh, "%s\n", "%H:%M:%S" ) == 9 ); /* time format (%X) */
+
+ TESTCASE( fprintf( fh, "%s\n", "" ) == 1 ); /* AM */
+ TESTCASE( fprintf( fh, "%s\n", "" ) == 1 ); /* PM */
+ fclose( fh );
+ TESTCASE( ( lc = _PDCLIB_load_lc_time( "./", "test" ) ) );
+ remove( "test_time.dat" );
+
+ TESTCASE( strcmp( lc->month_name_abbr[ 0 ], "Jan" ) == 0 );
+ TESTCASE( strcmp( lc->month_name_abbr[ 11 ], "Dez" ) == 0 );
+ TESTCASE( strcmp( lc->month_name_full[ 0 ], "Januar" ) == 0 );
+ TESTCASE( strcmp( lc->month_name_full[ 11 ], "Dezember" ) == 0 );
+ TESTCASE( strcmp( lc->day_name_abbr[ 0 ], "So" ) == 0 );
+ TESTCASE( strcmp( lc->day_name_abbr[ 6 ], "Sa" ) == 0 );
+ TESTCASE( strcmp( lc->day_name_full[ 0 ], "Sonntag" ) == 0 );
+ TESTCASE( strcmp( lc->day_name_full[ 6 ], "Samstag" ) == 0 );
+
+#endif
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c
new file mode 100644
index 0000000..aaaa743
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_load_lines.c
@@ -0,0 +1,81 @@
+/* _PDCLIB_load_lines( FILE *, 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 <stdio.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+char * _PDCLIB_load_lines( FILE * fh, size_t lines )
+{
+ size_t required = 0;
+ long pos = ftell( fh );
+ char * rc = NULL;
+ int c;
+
+ /* Count the number of characters */
+ while ( lines && ( c = fgetc( fh ) ) != EOF )
+ {
+ if ( c == '\n' )
+ {
+ --lines;
+ }
+
+ ++required;
+ }
+
+ if ( ! feof( fh ) )
+ {
+ if ( ( rc = malloc( required ) ) != NULL )
+ {
+ size_t i;
+
+ fseek( fh, pos, SEEK_SET );
+ fread( rc, 1, required, fh );
+
+ for ( i = 0; i < required; ++i )
+ {
+ if ( rc[ i ] == '\n' )
+ {
+ rc[ i ] = '\0';
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ FILE * fh = fopen( "test_lines.txt", "w+" );
+ char * rc;
+
+ TESTCASE( fh != NULL );
+ TESTCASE( fputs( "Foo\n\nBar\n", fh ) != EOF );
+
+ rewind( fh );
+ rc = _PDCLIB_load_lines( fh, 3 );
+ fclose( fh );
+ remove( "test_lines.txt" );
+
+ TESTCASE( rc != NULL );
+ TESTCASE( strcmp( rc, "Foo" ) == 0 );
+ TESTCASE( strcmp( rc + 4, "" ) == 0 );
+ TESTCASE( strcmp( rc + 5, "Bar" ) == 0 );
+
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c
new file mode 100644
index 0000000..1d60642
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepread.c
@@ -0,0 +1,50 @@
+/* _PDCLIB_prepread( struct _PDCLIB_file_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int _PDCLIB_prepread( struct _PDCLIB_file_t * stream )
+{
+ if ( ( stream->bufidx > stream->bufend ) ||
+ ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) ||
+ ! ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_FRW ) ) )
+ {
+ /* Function called on illegal (e.g. output) stream.
+ See comments on implementation-defined errno values in
+ <_PDCLIB_config.h>.
+ */
+ _PDCLIB_errno = _PDCLIB_ERROR;
+ stream->status |= _PDCLIB_ERRORFLAG;
+ return EOF;
+ }
+ stream->status |= _PDCLIB_FREAD | _PDCLIB_BYTESTREAM;
+ if ( ( stream->bufidx == stream->bufend ) && ( stream->ungetidx == 0 ) )
+ {
+ return _PDCLIB_fillbuffer( stream );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c
new file mode 100644
index 0000000..dcdc970
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_prepwrite.c
@@ -0,0 +1,41 @@
+/* _PDCLIB_prepwrite( struct _PDCLIB_file_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int _PDCLIB_prepwrite( struct _PDCLIB_file_t * stream )
+{
+ if ( ( stream->bufidx < stream->bufend ) || ( stream->ungetidx > 0 ) ||
+ ( stream->status & ( _PDCLIB_FREAD | _PDCLIB_ERRORFLAG | _PDCLIB_WIDESTREAM | _PDCLIB_EOFFLAG ) ) ||
+ ! ( stream->status & ( _PDCLIB_FWRITE | _PDCLIB_FAPPEND | _PDCLIB_FRW ) ) )
+ {
+ /* Function called on illegal (e.g. input) stream.
+ See the comments on implementation-defined errno values in
+ <_PDCLIB_config.h>.
+ */
+ _PDCLIB_errno = _PDCLIB_ERROR;
+ stream->status |= _PDCLIB_ERRORFLAG;
+ return EOF;
+ }
+ stream->status |= _PDCLIB_FWRITE | _PDCLIB_BYTESTREAM;
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c
new file mode 100644
index 0000000..3c13da2
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_print.c
@@ -0,0 +1,625 @@
+/* _PDCLIB_print( const char *, struct _PDCLIB_status_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+/* Using an integer's bits as flags for both the conversion flags and length
+ modifiers.
+*/
+/* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the
+ width flags) into a combined field.
+*/
+#define E_minus (1<<0)
+#define E_plus (1<<1)
+#define E_alt (1<<2)
+#define E_space (1<<3)
+#define E_zero (1<<4)
+#define E_done (1<<5)
+
+#define E_char (1<<6)
+#define E_short (1<<7)
+#define E_long (1<<8)
+#define E_llong (1<<9)
+#define E_intmax (1<<10)
+#define E_size (1<<11)
+#define E_ptrdiff (1<<12)
+#define E_pointer (1<<13)
+
+#define E_ldouble (1<<14)
+
+#define E_lower (1<<15)
+#define E_unsigned (1<<16)
+
+/* This macro delivers a given character to either a memory buffer or a stream,
+ depending on the contents of 'status' (struct _PDCLIB_status_t).
+ x - the character to be delivered
+ i - pointer to number of characters already delivered in this call
+ n - pointer to maximum number of characters to be delivered in this call
+ s - the buffer into which the character shall be delivered
+*/
+#define PUT( x ) \
+do { \
+ int character = x; \
+ if ( status->i < status->n ) { \
+ if ( status->stream != NULL ) \
+ putc( character, status->stream ); \
+ else \
+ status->s[status->i] = character; \
+ } \
+ ++(status->i); \
+} while ( 0 )
+
+
+static void intformat( intmax_t value, struct _PDCLIB_status_t * status )
+{
+ /* At worst, we need two prefix characters (hex prefix). */
+ char preface[3] = "\0";
+ size_t preidx = 0;
+ if ( status->prec < 0 )
+ {
+ status->prec = 1;
+ }
+ if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) && ( value != 0 ) )
+ {
+ /* Octal / hexadecimal prefix for "%#" conversions */
+ preface[ preidx++ ] = '0';
+ if ( status->base == 16 )
+ {
+ preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
+ }
+ }
+ if ( value < 0 )
+ {
+ /* Negative sign for negative values - at all times. */
+ preface[ preidx++ ] = '-';
+ }
+ else if ( ! ( status->flags & E_unsigned ) )
+ {
+ /* plus sign / extra space are only for unsigned conversions */
+ if ( status->flags & E_plus )
+ {
+ preface[ preidx++ ] = '+';
+ }
+ else if ( status->flags & E_space )
+ {
+ preface[ preidx++ ] = ' ';
+ }
+ }
+ {
+ /* At this point, status->current has the number of digits queued up.
+ Determine if we have a precision requirement to pad those.
+ */
+ size_t prec_pads = ( (_PDCLIB_size_t)status->prec > status->current ) ? ( (_PDCLIB_size_t)status->prec - status->current ) : 0;
+ if ( ! ( status->flags & ( E_minus | E_zero ) ) )
+ {
+ /* Space padding is only done if no zero padding or left alignment
+ is requested. Calculate the number of characters that WILL be
+ printed, including any prefixes determined above.
+ */
+ /* The number of characters to be printed, plus prefixes if any. */
+ /* This line contained probably the most stupid, time-wasting bug
+ I've ever perpetrated. Greetings to Samface, DevL, and all
+ sceners at Breakpoint 2006.
+ */
+ size_t characters = preidx + ( ( status->current > (_PDCLIB_size_t)status->prec ) ? status->current : (_PDCLIB_size_t)status->prec );
+ if ( status->width > characters )
+ {
+ size_t i;
+ for ( i = 0; i < status->width - characters; ++i )
+ {
+ PUT( ' ' );
+ ++(status->current);
+ }
+ }
+ }
+ /* Now we did the padding, do the prefixes (if any). */
+ preidx = 0;
+ while ( preface[ preidx ] != '\0' )
+ {
+ PUT( preface[ preidx++ ] );
+ ++(status->current);
+ }
+ /* Do the precision padding if necessary. */
+ while ( prec_pads-- > 0 )
+ {
+ PUT( '0' );
+ ++(status->current);
+ }
+ if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
+ {
+ /* If field is not left aligned, and zero padding is requested, do
+ so.
+ */
+ while ( status->current < status->width )
+ {
+ PUT( '0' );
+ ++(status->current);
+ }
+ }
+ }
+}
+
+
+/* This function recursively converts a given integer value to a character
+ stream. The conversion is done under the control of a given status struct
+ and written either to a character string or a stream, depending on that
+ same status struct. The status struct also keeps the function from exceeding
+ snprintf() limits, and enables any necessary padding / prefixing of the
+ output once the number of characters to be printed is known, which happens
+ at the lowermost recursion level.
+*/
+#define INT2BASE() \
+do \
+{ \
+ /* Special case: zero value, zero precision -- no output (but padding) */ \
+ if ( status->current == 0 && value == 0 && status->prec == 0 ) \
+ { \
+ intformat( value, status ); \
+ } \
+ else \
+ { \
+ /* Registering the character being printed at the end of the function here \
+ already so it will be taken into account when the deepestmost recursion \
+ does the prefix / padding stuff. \
+ */ \
+ ++(status->current); \
+ if ( ( value / status->base ) != 0 ) \
+ { \
+ /* More digits to be done - recurse deeper */ \
+ int2base( value / status->base, status ); \
+ } \
+ else \
+ { \
+ /* We reached the last digit, the deepest point of our recursion, and \
+ only now know how long the number to be printed actually is. Now we \
+ have to do the sign, prefix, width, and precision padding stuff \
+ before printing the numbers while we resurface from the recursion. \
+ */ \
+ intformat( value, status ); \
+ } \
+ /* Recursion tail - print the current digit. */ \
+ { \
+ int digit = value % status->base; \
+ if ( digit < 0 ) \
+ { \
+ digit *= -1; \
+ } \
+ if ( status->flags & E_lower ) \
+ { \
+ /* Lowercase letters. Same array used for strto...(). */ \
+ PUT( _PDCLIB_digits[ digit ] ); \
+ } \
+ else \
+ { \
+ /* Uppercase letters. Array only used here, only 0-F. */ \
+ PUT( _PDCLIB_Xdigits[ digit ] ); \
+ } \
+ } \
+ } \
+} while ( 0 )
+
+
+static void int2base( intmax_t value, struct _PDCLIB_status_t * status )
+{
+ INT2BASE();
+}
+
+
+static void stringformat( const char * s, struct _PDCLIB_status_t * status )
+{
+ if ( status->flags & E_char )
+ {
+ status->prec = 1;
+ }
+ else
+ {
+ if ( status->prec < 0 )
+ {
+ status->prec = strlen( s );
+ }
+ else
+ {
+ int i;
+ for ( i = 0; i < status->prec; ++i )
+ {
+ if ( s[i] == 0 )
+ {
+ status->prec = i;
+ break;
+ }
+ }
+ }
+ }
+ if ( ! ( status->flags & E_minus ) && ( status->width > (_PDCLIB_size_t)status->prec ) )
+ {
+ while ( status->current < ( status->width - status->prec ) )
+ {
+ PUT( ' ' );
+ ++(status->current);
+ }
+ }
+ while ( status->prec > 0 )
+ {
+ PUT( *(s++) );
+ --(status->prec);
+ ++(status->current);
+ }
+ if ( status->flags & E_minus )
+ {
+ while ( status->width > status->current )
+ {
+ PUT( ' ' );
+ ++(status->current);
+ }
+ }
+}
+
+
+const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
+{
+ const char * orig_spec = spec;
+ if ( *(++spec) == '%' )
+ {
+ /* %% -> print single '%' */
+ PUT( *spec );
+ return ++spec;
+ }
+ /* Initializing status structure */
+ status->flags = 0;
+ status->base = 0;
+ status->current = 0;
+ status->width = 0;
+ status->prec = EOF;
+
+ /* First come 0..n flags */
+ do
+ {
+ switch ( *spec )
+ {
+ case '-':
+ /* left-aligned output */
+ status->flags |= E_minus;
+ ++spec;
+ break;
+ case '+':
+ /* positive numbers prefixed with '+' */
+ status->flags |= E_plus;
+ ++spec;
+ break;
+ case '#':
+ /* alternative format (leading 0x for hex, 0 for octal) */
+ status->flags |= E_alt;
+ ++spec;
+ break;
+ case ' ':
+ /* positive numbers prefixed with ' ' */
+ status->flags |= E_space;
+ ++spec;
+ break;
+ case '0':
+ /* right-aligned padding done with '0' instead of ' ' */
+ status->flags |= E_zero;
+ ++spec;
+ break;
+ default:
+ /* not a flag, exit flag parsing */
+ status->flags |= E_done;
+ break;
+ }
+ } while ( ! ( status->flags & E_done ) );
+
+ /* Optional field width */
+ if ( *spec == '*' )
+ {
+ /* Retrieve width value from argument stack */
+ int width = va_arg( status->arg, int );
+ if ( width < 0 )
+ {
+ status->flags |= E_minus;
+ status->width = abs( width );
+ }
+ else
+ {
+ status->width = width;
+ }
+ ++spec;
+ }
+ else
+ {
+ /* If a width is given, strtol() will return its value. If not given,
+ strtol() will return zero. In both cases, endptr will point to the
+ rest of the conversion specifier - just what we need.
+ */
+ status->width = (int)strtol( spec, (char**)&spec, 10 );
+ }
+
+ /* Optional precision */
+ if ( *spec == '.' )
+ {
+ ++spec;
+ if ( *spec == '*' )
+ {
+ /* Retrieve precision value from argument stack. A negative value
+ is as if no precision is given - as precision is initalized to
+ EOF (negative), there is no need for testing for negative here.
+ */
+ status->prec = va_arg( status->arg, int );
+ ++spec;
+ }
+ else
+ {
+ char * endptr;
+ status->prec = (int)strtol( spec, &endptr, 10 );
+ if ( spec == endptr )
+ {
+ /* Decimal point but no number - equals zero */
+ status->prec = 0;
+ }
+ spec = endptr;
+ }
+ /* Having a precision cancels out any zero flag. */
+ status->flags &= ~E_zero;
+ }
+
+ /* Optional length modifier
+ We step one character ahead in any case, and step back only if we find
+ there has been no length modifier (or step ahead another character if it
+ has been "hh" or "ll").
+ */
+ switch ( *(spec++) )
+ {
+ case 'h':
+ if ( *spec == 'h' )
+ {
+ /* hh -> char */
+ status->flags |= E_char;
+ ++spec;
+ }
+ else
+ {
+ /* h -> short */
+ status->flags |= E_short;
+ }
+ break;
+ case 'l':
+ if ( *spec == 'l' )
+ {
+ /* ll -> long long */
+ status->flags |= E_llong;
+ ++spec;
+ }
+ else
+ {
+ /* k -> long */
+ status->flags |= E_long;
+ }
+ break;
+ case 'j':
+ /* j -> intmax_t, which might or might not be long long */
+ status->flags |= E_intmax;
+ break;
+ case 'z':
+ /* z -> size_t, which might or might not be unsigned int */
+ status->flags |= E_size;
+ break;
+ case 't':
+ /* t -> ptrdiff_t, which might or might not be long */
+ status->flags |= E_ptrdiff;
+ break;
+ case 'L':
+ /* L -> long double */
+ status->flags |= E_ldouble;
+ break;
+ default:
+ --spec;
+ break;
+ }
+
+ /* Conversion specifier */
+ switch ( *spec )
+ {
+ case 'd':
+ /* FALLTHROUGH */
+ case 'i':
+ status->base = 10;
+ break;
+ case 'o':
+ status->base = 8;
+ status->flags |= E_unsigned;
+ break;
+ case 'u':
+ status->base = 10;
+ status->flags |= E_unsigned;
+ break;
+ case 'x':
+ status->base = 16;
+ status->flags |= ( E_lower | E_unsigned );
+ break;
+ case 'X':
+ status->base = 16;
+ status->flags |= E_unsigned;
+ break;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ break;
+ case 'a':
+ case 'A':
+ break;
+ case 'c':
+ /* TODO: wide chars. */
+ {
+ char c[1];
+ c[0] = (char)va_arg( status->arg, int );
+ status->flags |= E_char;
+ stringformat( c, status );
+ return ++spec;
+ }
+ case 's':
+ /* TODO: wide chars. */
+ stringformat( va_arg( status->arg, char * ), status );
+ return ++spec;
+ case 'p':
+ status->base = 16;
+ status->flags |= ( E_lower | E_unsigned | E_alt | E_pointer );
+ break;
+ case 'n':
+ {
+ int * val = va_arg( status->arg, int * );
+ *val = status->i;
+ return ++spec;
+ }
+ default:
+ /* No conversion specifier. Bad conversion. */
+ return orig_spec;
+ }
+
+ /* Do the actual output based on our findings */
+ if ( status->base != 0 )
+ {
+ /* Integer conversions */
+ /* TODO: Check for invalid flag combinations. */
+ if ( status->flags & E_unsigned )
+ {
+ uintmax_t value;
+ switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size | E_pointer | E_intmax ) )
+ {
+ case E_char:
+ value = (uintmax_t)(unsigned char)va_arg( status->arg, int );
+ break;
+ case E_short:
+ value = (uintmax_t)(unsigned short)va_arg( status->arg, int );
+ break;
+ case 0:
+ value = (uintmax_t)va_arg( status->arg, unsigned int );
+ break;
+ case E_long:
+ value = (uintmax_t)va_arg( status->arg, unsigned long );
+ break;
+ case E_llong:
+ value = (uintmax_t)va_arg( status->arg, unsigned long long );
+ break;
+ case E_size:
+ value = (uintmax_t)va_arg( status->arg, size_t );
+ break;
+ case E_pointer:
+ value = (uintmax_t)(uintptr_t)va_arg( status->arg, void * );
+ break;
+ case E_intmax:
+ value = va_arg( status->arg, uintmax_t );
+ break;
+ default:
+ puts( "UNSUPPORTED PRINTF FLAG COMBINATION" );
+ return NULL;
+ }
+ INT2BASE();
+ }
+ else
+ {
+ intmax_t value;
+ switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) )
+ {
+ case E_char:
+ value = (intmax_t)(char)va_arg( status->arg, int );
+ break;
+ case E_short:
+ value = (intmax_t)(short)va_arg( status->arg, int );
+ break;
+ case 0:
+ value = (intmax_t)va_arg( status->arg, int );
+ break;
+ case E_long:
+ value = (intmax_t)va_arg( status->arg, long );
+ break;
+ case E_llong:
+ value = (intmax_t)va_arg( status->arg, long long );
+ break;
+ case E_ptrdiff:
+ value = (intmax_t)va_arg( status->arg, ptrdiff_t );
+ break;
+ case E_intmax:
+ value = va_arg( status->arg, intmax_t );
+ break;
+ default:
+ puts( "UNSUPPORTED PRINTF FLAG COMBINATION" );
+ return NULL;
+ }
+ INT2BASE();
+ }
+ if ( status->flags & E_minus )
+ {
+ while ( status->current < status->width )
+ {
+ PUT( ' ' );
+ ++(status->current);
+ }
+ }
+ if ( status->i >= status->n && status->n > 0 )
+ {
+ status->s[status->n - 1] = '\0';
+ }
+ }
+ return ++spec;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "_PDCLIB/print.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+#ifndef REGTEST
+
+static int testprintf( char * buffer, const char * format, ... )
+{
+ /* Members: base, flags, n, i, current, s, width, prec, stream, arg */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 100;
+ status.i = 0;
+ status.current = 0;
+ status.s = buffer;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = NULL;
+ va_start( status.arg, format );
+ memset( buffer, '\0', 100 );
+ if ( *(_PDCLIB_print( format, &status )) != '\0' )
+ {
+ printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
+ ++TEST_RESULTS;
+ }
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#define TEST_CONVERSION_ONLY
+
+int main( void )
+{
+#ifndef REGTEST
+ char target[100];
+#include "printf_testcases.h"
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c
new file mode 100644
index 0000000..1f8fd71
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_scan.c
@@ -0,0 +1,639 @@
+/* _PDCLIB_scan( const char *, struct _PDCLIB_status_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+
+#ifndef REGTEST
+
+/* Using an integer's bits as flags for both the conversion flags and length
+ modifiers.
+*/
+#define E_suppressed 1<<0
+#define E_char 1<<6
+#define E_short 1<<7
+#define E_long 1<<8
+#define E_llong 1<<9
+#define E_intmax 1<<10
+#define E_size 1<<11
+#define E_ptrdiff 1<<12
+#define E_pointer 1<<13
+#define E_ldouble 1<<14
+#define E_unsigned 1<<16
+
+
+/* Helper function to get a character from the string or stream, whatever is
+ used for input. When reading from a string, returns EOF on end-of-string
+ so that handling of the return value can be uniform for both streams and
+ strings.
+*/
+static int GET( struct _PDCLIB_status_t * status )
+{
+ int rc = EOF;
+ if ( status->stream != NULL )
+ {
+ rc = getc( status->stream );
+ }
+ else
+ {
+ rc = ( *status->s == '\0' ) ? EOF : (unsigned char)*((status->s)++);
+ }
+ if ( rc != EOF )
+ {
+ ++(status->i);
+ ++(status->current);
+ }
+ return rc;
+}
+
+
+/* Helper function to put a read character back into the string or stream,
+ whatever is used for input.
+*/
+static void UNGET( int c, struct _PDCLIB_status_t * status )
+{
+ if ( status->stream != NULL )
+ {
+ ungetc( c, status->stream ); /* TODO: Error? */
+ }
+ else
+ {
+ --(status->s);
+ }
+ --(status->i);
+ --(status->current);
+}
+
+
+/* Helper function to check if a character is part of a given scanset */
+static int IN_SCANSET( const char * scanlist, const char * end_scanlist, int rc )
+{
+ /* SOLAR */
+ int previous = -1;
+ while ( scanlist != end_scanlist )
+ {
+ if ( ( *scanlist == '-' ) && ( previous != -1 ) )
+ {
+ /* possible scangroup ("a-z") */
+ if ( ++scanlist == end_scanlist )
+ {
+ /* '-' at end of scanlist does not describe a scangroup */
+ return rc == '-';
+ }
+ while ( ++previous <= (unsigned char)*scanlist )
+ {
+ if ( previous == rc )
+ {
+ return 1;
+ }
+ }
+ previous = -1;
+ }
+ else
+ {
+ /* not a scangroup, check verbatim */
+ if ( rc == (unsigned char)*scanlist )
+ {
+ return 1;
+ }
+ previous = (unsigned char)(*scanlist++);
+ }
+ }
+ return 0;
+}
+
+
+const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
+{
+ /* generic input character */
+ int rc;
+ const char * prev_spec;
+ const char * orig_spec = spec;
+ int value_parsed;
+ if ( *(++spec) == '%' )
+ {
+ /* %% -> match single '%' */
+ rc = GET( status );
+ switch ( rc )
+ {
+ case EOF:
+ /* input error */
+ if ( status->n == 0 )
+ {
+ status->n = -1;
+ }
+ return NULL;
+ case '%':
+ return ++spec;
+ default:
+ UNGET( rc, status );
+ break;
+ }
+ }
+ /* Initializing status structure */
+ status->flags = 0;
+ status->base = -1;
+ status->current = 0;
+ status->width = 0;
+ status->prec = 0;
+
+ /* '*' suppresses assigning parsed value to variable */
+ if ( *spec == '*' )
+ {
+ status->flags |= E_suppressed;
+ ++spec;
+ }
+
+ /* If a width is given, strtol() will return its value. If not given,
+ strtol() will return zero. In both cases, endptr will point to the
+ rest of the conversion specifier - just what we need.
+ */
+ prev_spec = spec;
+ status->width = (int)strtol( spec, (char**)&spec, 10 );
+ if ( spec == prev_spec )
+ {
+ status->width = SIZE_MAX;
+ }
+
+ /* Optional length modifier
+ We step one character ahead in any case, and step back only if we find
+ there has been no length modifier (or step ahead another character if it
+ has been "hh" or "ll").
+ */
+ switch ( *(spec++) )
+ {
+ case 'h':
+ if ( *spec == 'h' )
+ {
+ /* hh -> char */
+ status->flags |= E_char;
+ ++spec;
+ }
+ else
+ {
+ /* h -> short */
+ status->flags |= E_short;
+ }
+ break;
+ case 'l':
+ if ( *spec == 'l' )
+ {
+ /* ll -> long long */
+ status->flags |= E_llong;
+ ++spec;
+ }
+ else
+ {
+ /* l -> long */
+ status->flags |= E_long;
+ }
+ break;
+ case 'j':
+ /* j -> intmax_t, which might or might not be long long */
+ status->flags |= E_intmax;
+ break;
+ case 'z':
+ /* z -> size_t, which might or might not be unsigned int */
+ status->flags |= E_size;
+ break;
+ case 't':
+ /* t -> ptrdiff_t, which might or might not be long */
+ status->flags |= E_ptrdiff;
+ break;
+ case 'L':
+ /* L -> long double */
+ status->flags |= E_ldouble;
+ break;
+ default:
+ --spec;
+ break;
+ }
+
+ /* Conversion specifier */
+
+ /* whether valid input had been parsed */
+ value_parsed = 0;
+
+ switch ( *spec )
+ {
+ case 'd':
+ status->base = 10;
+ break;
+ case 'i':
+ status->base = 0;
+ break;
+ case 'o':
+ status->base = 8;
+ status->flags |= E_unsigned;
+ break;
+ case 'u':
+ status->base = 10;
+ status->flags |= E_unsigned;
+ break;
+ case 'x':
+ status->base = 16;
+ status->flags |= E_unsigned;
+ break;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ break;
+ case 'c':
+ {
+ char * c = va_arg( status->arg, char * );
+ /* for %c, default width is one */
+ if ( status->width == SIZE_MAX )
+ {
+ status->width = 1;
+ }
+ /* reading until width reached or input exhausted */
+ while ( ( status->current < status->width ) &&
+ ( ( rc = GET( status ) ) != EOF ) )
+ {
+ *(c++) = rc;
+ value_parsed = 1;
+ }
+ /* width or input exhausted */
+ if ( value_parsed )
+ {
+ ++status->n;
+ return ++spec;
+ }
+ else
+ {
+ /* input error, no character read */
+ if ( status->n == 0 )
+ {
+ status->n = -1;
+ }
+ return NULL;
+ }
+ }
+ case 's':
+ {
+ char * c = va_arg( status->arg, char * );
+ while ( ( status->current < status->width ) &&
+ ( ( rc = GET( status ) ) != EOF ) )
+ {
+ if ( isspace( rc ) )
+ {
+ UNGET( rc, status );
+ if ( value_parsed )
+ {
+ /* matching sequence terminated by whitespace */
+ *c = '\0';
+ ++status->n;
+ return ++spec;
+ }
+ else
+ {
+ /* matching error */
+ return NULL;
+ }
+ }
+ else
+ {
+ /* match */
+ value_parsed = 1;
+ *(c++) = rc;
+ }
+ }
+ /* width or input exhausted */
+ if ( value_parsed )
+ {
+ *c = '\0';
+ ++status->n;
+ return ++spec;
+ }
+ else
+ {
+ /* input error, no character read */
+ if ( status->n == 0 )
+ {
+ status->n = -1;
+ }
+ return NULL;
+ }
+ }
+ case '[':
+ {
+ const char * endspec = spec;
+ int negative_scanlist = 0;
+ char * c;
+ if ( *(++endspec) == '^' )
+ {
+ negative_scanlist = 1;
+ ++endspec;
+ }
+ spec = endspec;
+ do
+ {
+ /* TODO: This can run beyond a malformed format string */
+ ++endspec;
+ } while ( *endspec != ']' );
+ /* read according to scanlist, equiv. to %s above */
+ c = va_arg( status->arg, char * );
+ while ( ( status->current < status->width ) &&
+ ( ( rc = GET( status ) ) != EOF ) )
+ {
+ if ( negative_scanlist )
+ {
+ if ( IN_SCANSET( spec, endspec, rc ) )
+ {
+ UNGET( rc, status );
+ break;
+ }
+ }
+ else
+ {
+ if ( ! IN_SCANSET( spec, endspec, rc ) )
+ {
+ UNGET( rc, status );
+ break;
+ }
+ }
+ value_parsed = 1;
+ *(c++) = rc;
+ }
+ if ( value_parsed )
+ {
+ *c = '\0';
+ ++status->n;
+ return ++endspec;
+ }
+ else
+ {
+ if ( rc == EOF )
+ {
+ status->n = -1;
+ }
+ return NULL;
+ }
+ }
+ case 'p':
+ status->base = 16;
+ status->flags |= E_pointer;
+ break;
+ case 'n':
+ {
+ int * val = va_arg( status->arg, int * );
+ *val = status->i;
+ return ++spec;
+ }
+ default:
+ /* No conversion specifier. Bad conversion. */
+ return orig_spec;
+ }
+
+ if ( status->base != -1 )
+ {
+ /* integer conversion */
+ uintmax_t value = 0; /* absolute value read */
+ int prefix_parsed = 0;
+ int sign = 0;
+ while ( ( status->current < status->width ) &&
+ ( ( rc = GET( status ) ) != EOF ) )
+ {
+ if ( isspace( rc ) )
+ {
+ if ( sign )
+ {
+ /* matching sequence terminated by whitespace */
+ UNGET( rc, status );
+ break;
+ }
+ else
+ {
+ /* leading whitespace not counted against width */
+ status->current--;
+ }
+ }
+ else if ( ! sign )
+ {
+ /* no sign parsed yet */
+ switch ( rc )
+ {
+ case '-':
+ sign = -1;
+ break;
+ case '+':
+ sign = 1;
+ break;
+ default:
+ /* not a sign; put back character */
+ sign = 1;
+ UNGET( rc, status );
+ break;
+ }
+ }
+ else if ( ! prefix_parsed )
+ {
+ /* no prefix (0x... for hex, 0... for octal) parsed yet */
+ prefix_parsed = 1;
+ if ( rc != '0' )
+ {
+ /* not a prefix; if base not yet set, set to decimal */
+ if ( status->base == 0 )
+ {
+ status->base = 10;
+ }
+ UNGET( rc, status );
+ }
+ else
+ {
+ /* starts with zero, so it might be a prefix. */
+ /* check what follows next (might be 0x...) */
+ if ( ( status->current < status->width ) &&
+ ( ( rc = GET( status ) ) != EOF ) )
+ {
+ if ( tolower( rc ) == 'x' )
+ {
+ /* 0x... would be prefix for hex base... */
+ if ( ( status->base == 0 ) ||
+ ( status->base == 16 ) )
+ {
+ status->base = 16;
+ }
+ else
+ {
+ /* ...unless already set to other value */
+ UNGET( rc, status );
+ value_parsed = 1;
+ }
+ }
+ else
+ {
+ /* 0... but not 0x.... would be octal prefix */
+ UNGET( rc, status );
+ if ( status->base == 0 )
+ {
+ status->base = 8;
+ }
+ /* in any case we have read a zero */
+ value_parsed = 1;
+ }
+ }
+ else
+ {
+ /* failed to read beyond the initial zero */
+ value_parsed = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ char * digitptr = memchr( _PDCLIB_digits, tolower( rc ), status->base );
+ if ( digitptr == NULL )
+ {
+ /* end of input item */
+ UNGET( rc, status );
+ break;
+ }
+ value *= status->base;
+ value += digitptr - _PDCLIB_digits;
+ value_parsed = 1;
+ }
+ }
+ /* width or input exhausted, or non-matching character */
+ if ( ! value_parsed )
+ {
+ /* out of input before anything could be parsed - input error */
+ /* FIXME: if first character does not match, value_parsed is not set - but it is NOT an input error */
+ if ( ( status->n == 0 ) && ( rc == EOF ) )
+ {
+ status->n = -1;
+ }
+ return NULL;
+ }
+ /* convert value to target type and assign to parameter */
+ if ( ! ( status->flags & E_suppressed ) )
+ {
+ switch ( status->flags & ( E_char | E_short | E_long | E_llong |
+ E_intmax | E_size | E_ptrdiff | E_pointer |
+ E_unsigned ) )
+ {
+ case E_char:
+ *( va_arg( status->arg, char * ) ) = (char)( value * sign );
+ break;
+ case E_char | E_unsigned:
+ *( va_arg( status->arg, unsigned char * ) ) = (unsigned char)( value * sign );
+ break;
+
+ case E_short:
+ *( va_arg( status->arg, short * ) ) = (short)( value * sign );
+ break;
+ case E_short | E_unsigned:
+ *( va_arg( status->arg, unsigned short * ) ) = (unsigned short)( value * sign );
+ break;
+
+ case 0:
+ *( va_arg( status->arg, int * ) ) = (int)( value * sign );
+ break;
+ case E_unsigned:
+ *( va_arg( status->arg, unsigned int * ) ) = (unsigned int)( value * sign );
+ break;
+
+ case E_long:
+ *( va_arg( status->arg, long * ) ) = (long)( value * sign );
+ break;
+ case E_long | E_unsigned:
+ *( va_arg( status->arg, unsigned long * ) ) = (unsigned long)( value * sign );
+ break;
+
+ case E_llong:
+ *( va_arg( status->arg, long long * ) ) = (long long)( value * sign );
+ break;
+ case E_llong | E_unsigned:
+ *( va_arg( status->arg, unsigned long long * ) ) = (unsigned long long)( value * sign );
+ break;
+
+ case E_intmax:
+ *( va_arg( status->arg, intmax_t * ) ) = (intmax_t)( value * sign );
+ break;
+ case E_intmax | E_unsigned:
+ *( va_arg( status->arg, uintmax_t * ) ) = (uintmax_t)( value * sign );
+ break;
+
+ case E_size:
+ /* E_size always implies unsigned */
+ *( va_arg( status->arg, size_t * ) ) = (size_t)( value * sign );
+ break;
+
+ case E_ptrdiff:
+ /* E_ptrdiff always implies signed */
+ *( va_arg( status->arg, ptrdiff_t * ) ) = (ptrdiff_t)( value * sign );
+ break;
+
+ case E_pointer:
+ /* E_pointer always implies unsigned */
+ *( uintptr_t* )( va_arg( status->arg, void * ) ) = (uintptr_t)( value * sign );
+ break;
+
+ default:
+ puts( "UNSUPPORTED SCANF FLAG COMBINATION" );
+ return NULL; /* behaviour unspecified */
+ }
+ ++(status->n);
+ }
+ return ++spec;
+ }
+ /* TODO: Floats. */
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "_PDCLIB/scan.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+#ifndef REGTEST
+
+static int testscanf( const char * s, const char * format, ... )
+{
+ struct _PDCLIB_status_t status;
+ status.n = 0;
+ status.i = 0;
+ status.s = (char *)s;
+ status.stream = NULL;
+ va_start( status.arg, format );
+ if ( *(_PDCLIB_scan( format, &status )) != '\0' )
+ {
+ printf( "_PDCLIB_scan() did not return end-of-specifier on '%s'.\n", format );
+ ++TEST_RESULTS;
+ }
+ va_end( status.arg );
+ return status.n;
+}
+
+#endif
+
+#define TEST_CONVERSION_ONLY
+
+int main( void )
+{
+#ifndef REGTEST
+ char source[100];
+#include "scanf_testcases.h"
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c
new file mode 100644
index 0000000..ce7c31c
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_seed.c
@@ -0,0 +1,19 @@
+/* _PDCLIB_seed
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+unsigned long int _PDCLIB_seed = 1;
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* no tests for raw data */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c
new file mode 100644
index 0000000..4808952
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_main.c
@@ -0,0 +1,88 @@
+/* _PDCLIB_strtox_main( const char * *, int, _PDCLIB_uintmax_t, _PDCLIB_uintmax_t, int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifndef REGTEST
+
+_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char * sign )
+{
+ _PDCLIB_uintmax_t rc = 0;
+ int digit = -1;
+ const char * x;
+ while ( ( x = memchr( _PDCLIB_digits, tolower(**p), base ) ) != NULL )
+ {
+ digit = x - _PDCLIB_digits;
+ if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) )
+ {
+ rc = rc * base + (unsigned)digit;
+ ++(*p);
+ }
+ else
+ {
+ errno = ERANGE;
+ /* TODO: Only if endptr != NULL - but do we really want *another* parameter? */
+ /* TODO: Earlier version was missing tolower() here but was not caught by tests */
+ while ( memchr( _PDCLIB_digits, tolower(**p), base ) != NULL ) ++(*p);
+ /* TODO: This is ugly, but keeps caller from negating the error value */
+ *sign = '+';
+ return error;
+ }
+ }
+ if ( digit == -1 )
+ {
+ *p = NULL;
+ return 0;
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+int main( void )
+{
+#ifndef REGTEST
+ const char * p;
+ char test[] = "123_";
+ char fail[] = "xxx";
+ char sign = '-';
+ /* basic functionality */
+ p = test;
+ errno = 0;
+ TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 123 );
+ TESTCASE( errno == 0 );
+ TESTCASE( p == &test[3] );
+ /* proper functioning to smaller base */
+ p = test;
+ TESTCASE( _PDCLIB_strtox_main( &p, 8u, (uintmax_t)999, (uintmax_t)12, 3, &sign ) == 0123 );
+ TESTCASE( errno == 0 );
+ TESTCASE( p == &test[3] );
+ /* overflowing subject sequence must still return proper endptr */
+ p = test;
+ TESTCASE( _PDCLIB_strtox_main( &p, 4u, (uintmax_t)999, (uintmax_t)1, 2, &sign ) == 999 );
+ TESTCASE( errno == ERANGE );
+ TESTCASE( p == &test[3] );
+ TESTCASE( sign == '+' );
+ /* testing conversion failure */
+ errno = 0;
+ p = fail;
+ sign = '-';
+ TESTCASE( _PDCLIB_strtox_main( &p, 10u, (uintmax_t)999, (uintmax_t)99, 8, &sign ) == 0 );
+ TESTCASE( p == NULL );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c
new file mode 100644
index 0000000..6e16b35
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/_PDCLIB_strtox_prelim.c
@@ -0,0 +1,94 @@
+/* _PDCLIB_strtox_prelim( 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 <ctype.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base )
+{
+ /* skipping leading whitespace */
+ while ( isspace( *p ) ) ++p;
+ /* determining / skipping sign */
+ if ( *p != '+' && *p != '-' ) *sign = '+';
+ else *sign = *(p++);
+ /* determining base */
+ if ( *p == '0' )
+ {
+ ++p;
+ if ( ( *base == 0 || *base == 16 ) && ( *p == 'x' || *p == 'X' ) )
+ {
+ *base = 16;
+ ++p;
+ /* catching a border case here: "0x" followed by a non-digit should
+ be parsed as the unprefixed zero.
+ We have to "rewind" the parsing; having the base set to 16 if it
+ was zero previously does not hurt, as the result is zero anyway.
+ */
+ if ( memchr( _PDCLIB_digits, tolower(*p), *base ) == NULL )
+ {
+ p -= 2;
+ }
+ }
+ else if ( *base == 0 )
+ {
+ *base = 8;
+ }
+ else
+ {
+ --p;
+ }
+ }
+ else if ( ! *base )
+ {
+ *base = 10;
+ }
+ return ( ( *base >= 2 ) && ( *base <= 36 ) ) ? p : NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ int base = 0;
+ char sign = '\0';
+ char test1[] = " 123";
+ char test2[] = "\t+0123";
+ char test3[] = "\v-0x123";
+ TESTCASE( _PDCLIB_strtox_prelim( test1, &sign, &base ) == &test1[2] );
+ TESTCASE( sign == '+' );
+ TESTCASE( base == 10 );
+ base = 0;
+ sign = '\0';
+ TESTCASE( _PDCLIB_strtox_prelim( test2, &sign, &base ) == &test2[3] );
+ TESTCASE( sign == '+' );
+ TESTCASE( base == 8 );
+ base = 0;
+ sign = '\0';
+ TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == &test3[4] );
+ TESTCASE( sign == '-' );
+ TESTCASE( base == 16 );
+ base = 10;
+ sign = '\0';
+ TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == &test3[2] );
+ TESTCASE( sign == '-' );
+ TESTCASE( base == 10 );
+ base = 1;
+ TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == NULL );
+ base = 37;
+ TESTCASE( _PDCLIB_strtox_prelim( test3, &sign, &base ) == NULL );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/assert.c b/src/pdclib/functions/_PDCLIB/assert.c
new file mode 100644
index 0000000..f84265f
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/assert.c
@@ -0,0 +1,71 @@
+/* _PDCLIB_assert( 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_aux.h"
+
+void _PDCLIB_assert99( const char * const message1, const char * const function, const char * const message2 )
+{
+ fputs( message1, stderr );
+ fputs( function, stderr );
+ fputs( message2, stderr );
+ abort();
+}
+
+void _PDCLIB_assert89( const char * const message )
+{
+ fputs( message, stderr );
+ abort();
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <signal.h>
+
+static int EXPECTED_ABORT = 0;
+static int UNEXPECTED_ABORT = 1;
+
+static void aborthandler( int sig )
+{
+ TESTCASE( ! EXPECTED_ABORT );
+ exit( (signed int)TEST_RESULTS );
+}
+
+#define NDEBUG
+
+#include <assert.h>
+
+static int disabled_test( void )
+{
+ int i = 0;
+ assert( i == 0 ); /* NDEBUG set, condition met */
+ assert( i == 1 ); /* NDEBUG set, condition fails */
+ return i;
+}
+
+#undef NDEBUG
+
+#include <assert.h>
+
+int main( void )
+{
+ TESTCASE( signal( SIGABRT, &aborthandler ) != SIG_ERR );
+ TESTCASE( disabled_test() == 0 );
+ assert( UNEXPECTED_ABORT ); /* NDEBUG not set, condition met */
+ assert( EXPECTED_ABORT ); /* NDEBUG not set, condition fails - should abort */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/errno.c b/src/pdclib/functions/_PDCLIB/errno.c
new file mode 100644
index 0000000..13270fc
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/errno.c
@@ -0,0 +1,37 @@
+/* _PDCLIB_errno
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_int.h"
+
+int _PDCLIB_errno = 0;
+
+int * _PDCLIB_errno_func()
+{
+ return &_PDCLIB_errno;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+int main( void )
+{
+ errno = 0;
+ TESTCASE( errno == 0 );
+ errno = EDOM;
+ TESTCASE( errno == EDOM );
+ errno = ERANGE;
+ TESTCASE( errno == ERANGE );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/_PDCLIB/stdarg.c b/src/pdclib/functions/_PDCLIB/stdarg.c
new file mode 100644
index 0000000..7ad1087
--- /dev/null
+++ b/src/pdclib/functions/_PDCLIB/stdarg.c
@@ -0,0 +1,115 @@
+/* stdarg
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdarg.h>
+#include <limits.h>
+#include <float.h>
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+typedef int (*intfunc_t)( void );
+
+enum tag_t
+{
+ TAG_END,
+ TAG_INT,
+ TAG_LONG,
+ TAG_LLONG,
+ TAG_DBL,
+ TAG_LDBL,
+ TAG_INTPTR,
+ TAG_LDBLPTR,
+ TAG_FUNCPTR
+};
+
+static int dummy( void )
+{
+ return INT_MAX;
+}
+
+static int test( enum tag_t s, ... )
+{
+ enum tag_t tag = s;
+ va_list ap;
+ va_start( ap, s );
+ for (;;)
+ {
+ switch ( tag )
+ {
+ case TAG_INT:
+ {
+ TESTCASE( va_arg( ap, int ) == INT_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_LONG:
+ {
+ TESTCASE( va_arg( ap, long ) == LONG_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_LLONG:
+ {
+ TESTCASE( va_arg( ap, long long ) == LLONG_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_DBL:
+ {
+ TESTCASE( va_arg( ap, double ) == DBL_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_LDBL:
+ {
+ TESTCASE( va_arg( ap, long double ) == LDBL_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_INTPTR:
+ {
+ TESTCASE( *( va_arg( ap, int * ) ) == INT_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_LDBLPTR:
+ {
+ TESTCASE( *( va_arg( ap, long double * ) ) == LDBL_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_FUNCPTR:
+ {
+ intfunc_t function;
+ TESTCASE( ( function = va_arg( ap, intfunc_t ) ) == dummy );
+ TESTCASE( function() == INT_MAX );
+ tag = va_arg( ap, enum tag_t );
+ break;
+ }
+ case TAG_END:
+ {
+ va_end( ap );
+ return 0;
+ }
+ }
+ }
+}
+
+int main( void )
+{
+ int x = INT_MAX;
+ long double d = LDBL_MAX;
+ test( TAG_END );
+ test( TAG_INT, INT_MAX, TAG_END );
+ test( TAG_LONG, LONG_MAX, TAG_LLONG, LLONG_MAX, TAG_END );
+ test( TAG_DBL, DBL_MAX, TAG_LDBL, LDBL_MAX, TAG_END );
+ test( TAG_INTPTR, &x, TAG_LDBLPTR, &d, TAG_FUNCPTR, dummy, TAG_END );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isalnum.c b/src/pdclib/functions/ctype/isalnum.c
new file mode 100644
index 0000000..d3ef7c9
--- /dev/null
+++ b/src/pdclib/functions/ctype/isalnum.c
@@ -0,0 +1,38 @@
+/* isalnum( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isalnum( int c )
+{
+ return ( isdigit( c ) || isalpha( c ) );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isalnum( 'a' ) );
+ TESTCASE( isalnum( 'z' ) );
+ TESTCASE( isalnum( 'A' ) );
+ TESTCASE( isalnum( 'Z' ) );
+ TESTCASE( isalnum( '0' ) );
+ TESTCASE( isalnum( '9' ) );
+ TESTCASE( ! isalnum( ' ' ) );
+ TESTCASE( ! isalnum( '\n' ) );
+ TESTCASE( ! isalnum( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isalpha.c b/src/pdclib/functions/ctype/isalpha.c
new file mode 100644
index 0000000..b3fa513
--- /dev/null
+++ b/src/pdclib/functions/ctype/isalpha.c
@@ -0,0 +1,34 @@
+/* isalpha( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isalpha( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_ALPHA );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isalpha( 'a' ) );
+ TESTCASE( isalpha( 'z' ) );
+ TESTCASE( ! isalpha( ' ' ) );
+ TESTCASE( ! isalpha( '1' ) );
+ TESTCASE( ! isalpha( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isblank.c b/src/pdclib/functions/ctype/isblank.c
new file mode 100644
index 0000000..dd6af44
--- /dev/null
+++ b/src/pdclib/functions/ctype/isblank.c
@@ -0,0 +1,35 @@
+/* isblank( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isblank( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_BLANK );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isblank( ' ' ) );
+ TESTCASE( isblank( '\t' ) );
+ TESTCASE( ! isblank( '\v' ) );
+ TESTCASE( ! isblank( '\r' ) );
+ TESTCASE( ! isblank( 'x' ) );
+ TESTCASE( ! isblank( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/iscntrl.c b/src/pdclib/functions/ctype/iscntrl.c
new file mode 100644
index 0000000..14d50e5
--- /dev/null
+++ b/src/pdclib/functions/ctype/iscntrl.c
@@ -0,0 +1,33 @@
+/* iscntrl( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int iscntrl( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_CNTRL );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( iscntrl( '\a' ) );
+ TESTCASE( iscntrl( '\b' ) );
+ TESTCASE( iscntrl( '\n' ) );
+ TESTCASE( ! iscntrl( ' ' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isdigit.c b/src/pdclib/functions/ctype/isdigit.c
new file mode 100644
index 0000000..00d6bcf
--- /dev/null
+++ b/src/pdclib/functions/ctype/isdigit.c
@@ -0,0 +1,34 @@
+/* isdigit( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isdigit( int c )
+{
+ return ( c >= _PDCLIB_lc_ctype.digits_low && c <= _PDCLIB_lc_ctype.digits_high );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isdigit( '0' ) );
+ TESTCASE( isdigit( '9' ) );
+ TESTCASE( ! isdigit( ' ' ) );
+ TESTCASE( ! isdigit( 'a' ) );
+ TESTCASE( ! isdigit( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isgraph.c b/src/pdclib/functions/ctype/isgraph.c
new file mode 100644
index 0000000..fdc5819
--- /dev/null
+++ b/src/pdclib/functions/ctype/isgraph.c
@@ -0,0 +1,37 @@
+/* isgraph( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isgraph( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_GRAPH );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isgraph( 'a' ) );
+ TESTCASE( isgraph( 'z' ) );
+ TESTCASE( isgraph( 'A' ) );
+ TESTCASE( isgraph( 'Z' ) );
+ TESTCASE( isgraph( '@' ) );
+ TESTCASE( ! isgraph( '\t' ) );
+ TESTCASE( ! isgraph( '\0' ) );
+ TESTCASE( ! isgraph( ' ' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/islower.c b/src/pdclib/functions/ctype/islower.c
new file mode 100644
index 0000000..5d225db
--- /dev/null
+++ b/src/pdclib/functions/ctype/islower.c
@@ -0,0 +1,35 @@
+/* islower( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int islower( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_LOWER );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( islower( 'a' ) );
+ TESTCASE( islower( 'z' ) );
+ TESTCASE( ! islower( 'A' ) );
+ TESTCASE( ! islower( 'Z' ) );
+ TESTCASE( ! islower( ' ' ) );
+ TESTCASE( ! islower( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isprint.c b/src/pdclib/functions/ctype/isprint.c
new file mode 100644
index 0000000..d3f1489
--- /dev/null
+++ b/src/pdclib/functions/ctype/isprint.c
@@ -0,0 +1,38 @@
+/* isprint( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isprint( int c )
+{
+ /* FIXME: Space as of current locale charset, not source charset. */
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_GRAPH ) || ( c == ' ' );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isprint( 'a' ) );
+ TESTCASE( isprint( 'z' ) );
+ TESTCASE( isprint( 'A' ) );
+ TESTCASE( isprint( 'Z' ) );
+ TESTCASE( isprint( '@' ) );
+ TESTCASE( ! isprint( '\t' ) );
+ TESTCASE( ! isprint( '\0' ) );
+ TESTCASE( isprint( ' ' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/ispunct.c b/src/pdclib/functions/ctype/ispunct.c
new file mode 100644
index 0000000..2afdb0c
--- /dev/null
+++ b/src/pdclib/functions/ctype/ispunct.c
@@ -0,0 +1,38 @@
+/* ispunct( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int ispunct( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_PUNCT );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( ! ispunct( 'a' ) );
+ TESTCASE( ! ispunct( 'z' ) );
+ TESTCASE( ! ispunct( 'A' ) );
+ TESTCASE( ! ispunct( 'Z' ) );
+ TESTCASE( ispunct( '@' ) );
+ TESTCASE( ispunct( '.' ) );
+ TESTCASE( ! ispunct( '\t' ) );
+ TESTCASE( ! ispunct( '\0' ) );
+ TESTCASE( ! ispunct( ' ' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isspace.c b/src/pdclib/functions/ctype/isspace.c
new file mode 100644
index 0000000..a724de6
--- /dev/null
+++ b/src/pdclib/functions/ctype/isspace.c
@@ -0,0 +1,36 @@
+/* isspace( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isspace( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_SPACE );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isspace( ' ' ) );
+ TESTCASE( isspace( '\f' ) );
+ TESTCASE( isspace( '\n' ) );
+ TESTCASE( isspace( '\r' ) );
+ TESTCASE( isspace( '\t' ) );
+ TESTCASE( isspace( '\v' ) );
+ TESTCASE( ! isspace( 'a' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isupper.c b/src/pdclib/functions/ctype/isupper.c
new file mode 100644
index 0000000..79b55a3
--- /dev/null
+++ b/src/pdclib/functions/ctype/isupper.c
@@ -0,0 +1,35 @@
+/* isupper( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isupper( int c )
+{
+ return ( _PDCLIB_lc_ctype.entry[c].flags & _PDCLIB_CTYPE_UPPER );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isupper( 'A' ) );
+ TESTCASE( isupper( 'Z' ) );
+ TESTCASE( ! isupper( 'a' ) );
+ TESTCASE( ! isupper( 'z' ) );
+ TESTCASE( ! isupper( ' ' ) );
+ TESTCASE( ! isupper( '@' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/isxdigit.c b/src/pdclib/functions/ctype/isxdigit.c
new file mode 100644
index 0000000..30839c0
--- /dev/null
+++ b/src/pdclib/functions/ctype/isxdigit.c
@@ -0,0 +1,41 @@
+/* isxdigit( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int isxdigit( int c )
+{
+ return ( isdigit( c )
+ || ( c >= _PDCLIB_lc_ctype.Xdigits_low && c <= _PDCLIB_lc_ctype.Xdigits_high )
+ || ( c >= _PDCLIB_lc_ctype.xdigits_low && c <= _PDCLIB_lc_ctype.xdigits_high ) );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( isxdigit( '0' ) );
+ TESTCASE( isxdigit( '9' ) );
+ TESTCASE( isxdigit( 'a' ) );
+ TESTCASE( isxdigit( 'f' ) );
+ TESTCASE( ! isxdigit( 'g' ) );
+ TESTCASE( isxdigit( 'A' ) );
+ TESTCASE( isxdigit( 'F' ) );
+ TESTCASE( ! isxdigit( 'G' ) );
+ TESTCASE( ! isxdigit( '@' ) );
+ TESTCASE( ! isxdigit( ' ' ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/tolower.c b/src/pdclib/functions/ctype/tolower.c
new file mode 100644
index 0000000..bbb76d1
--- /dev/null
+++ b/src/pdclib/functions/ctype/tolower.c
@@ -0,0 +1,35 @@
+/* tolower( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int tolower( int c )
+{
+ return _PDCLIB_lc_ctype.entry[c].lower;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( tolower( 'A' ) == 'a' );
+ TESTCASE( tolower( 'Z' ) == 'z' );
+ TESTCASE( tolower( 'a' ) == 'a' );
+ TESTCASE( tolower( 'z' ) == 'z' );
+ TESTCASE( tolower( '@' ) == '@' );
+ TESTCASE( tolower( '[' ) == '[' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/ctype/toupper.c b/src/pdclib/functions/ctype/toupper.c
new file mode 100644
index 0000000..79e6e2b
--- /dev/null
+++ b/src/pdclib/functions/ctype/toupper.c
@@ -0,0 +1,35 @@
+/* toupper( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <ctype.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int toupper( int c )
+{
+ return _PDCLIB_lc_ctype.entry[c].upper;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( toupper( 'a' ) == 'A' );
+ TESTCASE( toupper( 'z' ) == 'Z' );
+ TESTCASE( toupper( 'A' ) == 'A' );
+ TESTCASE( toupper( 'Z' ) == 'Z' );
+ TESTCASE( toupper( '@' ) == '@' );
+ TESTCASE( toupper( '[' ) == '[' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/inttypes/imaxabs.c b/src/pdclib/functions/inttypes/imaxabs.c
new file mode 100644
index 0000000..06d029e
--- /dev/null
+++ b/src/pdclib/functions/inttypes/imaxabs.c
@@ -0,0 +1,32 @@
+/* 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 <inttypes.h>
+
+#ifndef REGTEST
+
+intmax_t imaxabs( intmax_t j )
+{
+ return ( j >= 0 ) ? j : -j;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <limits.h>
+
+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/src/pdclib/functions/inttypes/imaxdiv.c b/src/pdclib/functions/inttypes/imaxdiv.c
new file mode 100644
index 0000000..7143c3d
--- /dev/null
+++ b/src/pdclib/functions/inttypes/imaxdiv.c
@@ -0,0 +1,39 @@
+/* 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 <inttypes.h>
+
+#ifndef REGTEST
+
+imaxdiv_t imaxdiv( intmax_t numer, intmax_t denom )
+{
+ imaxdiv_t rc;
+ rc.quot = numer / denom;
+ rc.rem = numer % denom;
+ 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/src/pdclib/functions/inttypes/strtoimax.c b/src/pdclib/functions/inttypes/strtoimax.c
new file mode 100644
index 0000000..29a3c92
--- /dev/null
+++ b/src/pdclib/functions/inttypes/strtoimax.c
@@ -0,0 +1,147 @@
+/* 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 <limits.h>
+#include <inttypes.h>
+
+#ifndef REGTEST
+
+#include <stddef.h>
+
+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
+ {
+ 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 <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( 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 >> 62 == 1
+ /* testing "odd" overflow, i.e. base is not a power of two */
+ TESTCASE( strtoimax( "9223372036854775807", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "9223372036854775808", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoimax( "-9223372036854775807", NULL, 0 ) == (INTMAX_MIN + 1) );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-9223372036854775808", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-9223372036854775809", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == ERANGE );
+ /* testing "even" overflow, i.e. base is power of two */
+ errno = 0;
+ TESTCASE( strtoimax( "0x7fffffffffffffff", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "0x8000000000000000", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoimax( "-0x7fffffffffffffff", NULL, 0 ) == (INTMAX_MIN + 1) );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-0x8000000000000000", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-0x8000000000000001", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == ERANGE );
+#elif LLONG_MAX >> 126 == 1
+ /* testing "odd" overflow, i.e. base is not a power of two */
+ TESTCASE( strtoimax( "170141183460469231731687303715884105728", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "170141183460469231731687303715884105729", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoimax( "-170141183460469231731687303715884105728", NULL, 0 ) == (INTMAX_MIN + 1) );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-170141183460469231731687303715884105729", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-170141183460469231731687303715884105730", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == ERANGE );
+ /* testing "even" overflow, i.e. base is power of two */
+ errno = 0;
+ TESTCASE( strtoimax( "0x7fffffffffffffffffffffffffffffff", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ errno = 0;
+ TESTCASE( strtoimax( "-0x7fffffffffffffffffffffffffffffff", NULL, 0 ) == (INTMAX_MIN + 1) );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-0x80000000000000000000000000000000", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoimax( "-0x80000000000000000000000000000001", NULL, 0 ) == INTMAX_MIN );
+ TESTCASE( errno == ERANGE );
+#else
+#error Unsupported width of 'intmax_t' (neither 64 nor 128 bit).
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/inttypes/strtoumax.c b/src/pdclib/functions/inttypes/strtoumax.c
new file mode 100644
index 0000000..9ed16c1
--- /dev/null
+++ b/src/pdclib/functions/inttypes/strtoumax.c
@@ -0,0 +1,111 @@
+/* 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 <limits.h>
+#include <inttypes.h>
+
+#ifndef REGTEST
+
+#include <stddef.h>
+
+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 <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( 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 );
+ errno = 0;
+/* uintmax_t -> long long -> 64 bit */
+#if UINTMAX_MAX >> 63 == 1
+ /* testing "odd" overflow, i.e. base is not power of two */
+ TESTCASE( strtoumax( "18446744073709551615", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoumax( "18446744073709551616", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ /* testing "even" overflow, i.e. base is power of two */
+ errno = 0;
+ TESTCASE( strtoumax( "0xFFFFFFFFFFFFFFFF", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoumax( "0x10000000000000000", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+/* uintmax_t -> long long -> 128 bit */
+#elif UINTMAX_MAX >> 127 == 1
+ /* testing "odd" overflow, i.e. base is not power of two */
+ TESTCASE( strtoumax( "340282366920938463463374607431768211455", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoumax( "340282366920938463463374607431768211456", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+ /* testing "even" everflow, i.e. base is power of two */
+ errno = 0;
+ TESTCASE( strtoumax( "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == 0 );
+ TESTCASE( strtoumax( "0x100000000000000000000000000000000", NULL, 0 ) == UINTMAX_MAX );
+ TESTCASE( errno == ERANGE );
+#else
+#error Unsupported width of 'uintmax_t' (neither 64 nor 128 bit).
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/locale/localeconv.c b/src/pdclib/functions/locale/localeconv.c
new file mode 100644
index 0000000..cdcb1b0
--- /dev/null
+++ b/src/pdclib/functions/locale/localeconv.c
@@ -0,0 +1,28 @@
+/* localeconv( void )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <locale.h>
+
+#ifndef REGTEST
+
+struct lconv * localeconv( void )
+{
+ return _PDCLIB_lc_numeric_monetary.lconv;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/locale/setlocale.c b/src/pdclib/functions/locale/setlocale.c
new file mode 100644
index 0000000..585504a
--- /dev/null
+++ b/src/pdclib/functions/locale/setlocale.c
@@ -0,0 +1,257 @@
+/* setlocale( int, 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 <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+static const char * _PDCLIB_LC_category_name[ _PDCLIB_LC_COUNT ] = { NULL, "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LC_MESSAGES" };
+
+static const char * _PDCLIB_default_locale( int category )
+{
+ const char * s;
+
+ if ( ( s = getenv( "LC_ALL" ) ) == NULL )
+ {
+ if ( category == LC_ALL || ( s = getenv( _PDCLIB_LC_category_name[ category ] ) ) == NULL )
+ {
+ if ( ( s = getenv( "LANG" ) ) == NULL )
+ {
+ s = "C";
+ }
+ }
+ }
+
+ return s;
+}
+
+char * setlocale( int category, const char * locale )
+{
+ /* All below is very much work-in-progress, so we do a dumb-dummy
+ return here.
+ */
+ if ( locale == NULL || ! strcmp( locale, "C" ) )
+ {
+ return (char *)"C";
+ }
+ else
+ {
+ return NULL;
+ }
+
+#if 0
+ /* Path to locale data files - _PDCLIB_LOCALE_PATH unless overruled
+ by the environment variable whose name is defined by preprocessor
+ symbol _PDCLIB_LOCALE_PATH_ENV (defaulting to PDCLIB_I18N).
+ Both of these definitions are set in _PDCLIB_config.h.
+ */
+ const char * path = _PDCLIB_LOCALE_PATH;
+
+ struct _PDCLIB_lc_lconv_numeric_t * numeric = NULL;
+ struct _PDCLIB_lc_lconv_monetary_t * monetary = NULL;
+ struct _PDCLIB_lc_collate_t * collate = NULL;
+ struct _PDCLIB_lc_ctype_t * ctype = NULL;
+ struct _PDCLIB_lc_messages_t * messages = NULL;
+ struct _PDCLIB_lc_time_t * time = NULL;
+
+ char * rc = (char *)locale;
+
+ if ( category < 0 || category >= _PDCLIB_LC_COUNT )
+ {
+ /* Bad category */
+ return NULL;
+ }
+
+ if ( locale == NULL )
+ {
+ /* NULL - Return current locale settings */
+ /* TODO */
+ }
+
+ if ( strlen( locale ) == 0 )
+ {
+ /* "" - Use default locale */
+ locale = _PDCLIB_default_locale( category );
+ }
+
+ if ( getenv( _PDCLIB_symbol2string( _PDCLIB_LOCALE_PATH_ENV ) ) != NULL )
+ {
+ path = getenv( _PDCLIB_symbol2string( _PDCLIB_LOCALE_PATH_ENV ) );
+ }
+
+ /* We have to do this in two runs. As we might be facing LC_ALL, we
+ need to be certain all the loads are successful before we start
+ to overwrite the current locale settings, because there is no way
+ this function could report a _partial_ success.
+ */
+
+ /* Run One -- get all the data for the new locale setting */
+ if ( category == LC_COLLATE || category == LC_ALL )
+ {
+ if ( ! ( collate = _PDCLIB_load_lc_collate( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ if ( category == LC_CTYPE || category == LC_ALL )
+ {
+ if ( ! ( ctype = _PDCLIB_load_lc_ctype( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ if ( category == LC_MONETARY || category == LC_ALL )
+ {
+ if ( ! ( monetary = _PDCLIB_load_lc_monetary( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ if ( category == LC_NUMERIC || category == LC_ALL )
+ {
+ if ( ! ( numeric = _PDCLIB_load_lc_numeric( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ if ( category == LC_TIME || category == LC_ALL )
+ {
+ if ( ! ( time = _PDCLIB_load_lc_time( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ if ( category == LC_MESSAGES || category == LC_ALL )
+ {
+ if ( ! ( messages = _PDCLIB_load_lc_messages( path, locale ) ) )
+ {
+ rc = NULL;
+ }
+ }
+
+ /* Run Two -- continue or release resources */
+ if ( rc != NULL )
+ {
+ if ( category == LC_COLLATE || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_collate.alloced )
+ {
+ /* free resources */
+ }
+
+ _PDCLIB_lc_collate = *collate;
+ free( collate );
+ }
+
+ if ( category == LC_CTYPE || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_ctype.alloced )
+ {
+ free( _PDCLIB_lc_ctype.entry - 1 );
+ }
+
+ _PDCLIB_lc_ctype = *ctype;
+ free( ctype );
+ }
+
+ if ( category == LC_MONETARY || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_numeric_monetary.monetary_alloced )
+ {
+ free( _PDCLIB_lc_numeric_monetary.lconv->mon_decimal_point );
+ }
+
+ _PDCLIB_lc_numeric_monetary.lconv->mon_decimal_point = monetary->mon_decimal_point;
+ _PDCLIB_lc_numeric_monetary.lconv->mon_thousands_sep = monetary->mon_thousands_sep;
+ _PDCLIB_lc_numeric_monetary.lconv->mon_grouping = monetary->mon_grouping;
+ _PDCLIB_lc_numeric_monetary.lconv->positive_sign = monetary->positive_sign;
+ _PDCLIB_lc_numeric_monetary.lconv->negative_sign = monetary->negative_sign;
+ _PDCLIB_lc_numeric_monetary.lconv->currency_symbol = monetary->currency_symbol;
+ _PDCLIB_lc_numeric_monetary.lconv->int_curr_symbol = monetary->int_curr_symbol;
+ _PDCLIB_lc_numeric_monetary.lconv->frac_digits = monetary->frac_digits;
+ _PDCLIB_lc_numeric_monetary.lconv->p_cs_precedes = monetary->p_cs_precedes;
+ _PDCLIB_lc_numeric_monetary.lconv->n_cs_precedes = monetary->n_cs_precedes;
+ _PDCLIB_lc_numeric_monetary.lconv->p_sep_by_space = monetary->p_sep_by_space;
+ _PDCLIB_lc_numeric_monetary.lconv->n_sep_by_space = monetary->n_sep_by_space;
+ _PDCLIB_lc_numeric_monetary.lconv->p_sign_posn = monetary->p_sign_posn;
+ _PDCLIB_lc_numeric_monetary.lconv->n_sign_posn = monetary->n_sign_posn;
+ _PDCLIB_lc_numeric_monetary.lconv->int_frac_digits = monetary->int_frac_digits;
+ _PDCLIB_lc_numeric_monetary.lconv->int_p_cs_precedes = monetary->int_p_cs_precedes;
+ _PDCLIB_lc_numeric_monetary.lconv->int_n_cs_precedes = monetary->int_n_cs_precedes;
+ _PDCLIB_lc_numeric_monetary.lconv->int_p_sep_by_space = monetary->int_p_sep_by_space;
+ _PDCLIB_lc_numeric_monetary.lconv->int_n_sep_by_space = monetary->int_n_sep_by_space;
+ _PDCLIB_lc_numeric_monetary.lconv->int_p_sign_posn = monetary->int_p_sign_posn;
+ _PDCLIB_lc_numeric_monetary.lconv->int_n_sign_posn = monetary->int_n_sign_posn;
+
+ _PDCLIB_lc_numeric_monetary.monetary_alloced = 1;
+
+ free( monetary );
+ }
+
+ if ( category == LC_NUMERIC || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_numeric_monetary.numeric_alloced )
+ {
+ free( _PDCLIB_lc_numeric_monetary.lconv->decimal_point );
+ }
+
+ _PDCLIB_lc_numeric_monetary.lconv->decimal_point = numeric->decimal_point;
+ _PDCLIB_lc_numeric_monetary.lconv->thousands_sep = numeric->thousands_sep;
+ _PDCLIB_lc_numeric_monetary.lconv->grouping = numeric->grouping;
+
+ _PDCLIB_lc_numeric_monetary.numeric_alloced = 1;
+
+ free( numeric );
+ }
+
+ if ( category == LC_TIME || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_time.alloced )
+ {
+ free( _PDCLIB_lc_time.month_name_abbr[ 0 ] );
+ }
+
+ _PDCLIB_lc_time = *time;
+ free( time );
+ }
+
+ if ( category == LC_MESSAGES || category == LC_ALL )
+ {
+ if ( _PDCLIB_lc_messages.alloced )
+ {
+ free( _PDCLIB_lc_messages.errno_texts[ 0 ] );
+ }
+
+ _PDCLIB_lc_messages = *messages;
+ free( messages );
+ }
+ }
+
+ return NULL;
+#endif
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ setlocale(0,"");
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/clearerr.c b/src/pdclib/functions/stdio/clearerr.c
new file mode 100644
index 0000000..91cd00a
--- /dev/null
+++ b/src/pdclib/functions/stdio/clearerr.c
@@ -0,0 +1,52 @@
+/* clearerr( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+void clearerr( struct _PDCLIB_file_t * stream )
+{
+ stream->status &= ~( _PDCLIB_ERRORFLAG | _PDCLIB_EOFFLAG );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ /* Flags should be clear */
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ /* Reading from empty stream - should provoke EOF */
+ rewind( fh );
+ TESTCASE( fgetc( fh ) == EOF );
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( feof( fh ) );
+ /* clearerr() should clear flags */
+ clearerr( fh );
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ /* reopen() the file write-only */
+ TESTCASE( ( fh = freopen( NULL, "w", fh ) ) != NULL );
+ /* Reading from write-only stream - should provoke error */
+ TESTCASE( fgetc( fh ) == EOF );
+ TESTCASE( ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ /* clearerr() should clear flags */
+ clearerr( fh );
+ TESTCASE( ! ferror( fh ) );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fclose.c b/src/pdclib/functions/stdio/fclose.c
new file mode 100644
index 0000000..9a1388d
--- /dev/null
+++ b/src/pdclib/functions/stdio/fclose.c
@@ -0,0 +1,106 @@
+/* fclose( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int fclose( struct _PDCLIB_file_t * stream )
+{
+ struct _PDCLIB_file_t * current = _PDCLIB_filelist;
+ struct _PDCLIB_file_t * previous = NULL;
+ /* Checking that the FILE handle is actually one we had opened before. */
+ while ( current != NULL )
+ {
+ if ( stream == current )
+ {
+ /* Flush buffer */
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* Flush failed, errno already set */
+ return EOF;
+ }
+ }
+ /* Close handle */
+ _PDCLIB_close( stream->handle );
+ /* Remove stream from list */
+ if ( previous != NULL )
+ {
+ previous->next = stream->next;
+ }
+ else
+ {
+ _PDCLIB_filelist = stream->next;
+ }
+ /* Delete tmpfile() */
+ if ( stream->status & _PDCLIB_DELONCLOSE )
+ {
+ remove( stream->filename );
+ }
+ /* Free user buffer (SetVBuf allocated) */
+ if ( stream->status & _PDCLIB_FREEBUFFER )
+ {
+ free( stream->buffer );
+ }
+ /* Free stream */
+ if ( ! ( stream->status & _PDCLIB_STATIC ) )
+ {
+ free( stream );
+ }
+ return 0;
+ }
+ previous = current;
+ current = current->next;
+ }
+ /* See the comments on implementation-defined errno values in
+ <_PDCLIB_config.h>.
+ */
+ _PDCLIB_errno = _PDCLIB_ERROR;
+ return -1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+#ifndef REGTEST
+ struct _PDCLIB_file_t * file1;
+ struct _PDCLIB_file_t * file2;
+ remove( testfile1 );
+ remove( testfile2 );
+ TESTCASE( _PDCLIB_filelist == stdin );
+ TESTCASE( ( file1 = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file1 );
+ TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file2 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == file1 );
+ TESTCASE( ( file2 = fopen( testfile2, "w" ) ) != NULL );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file1 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == file2 );
+ TESTCASE( fclose( file2 ) == 0 );
+ TESTCASE( _PDCLIB_filelist == stdin );
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+#else
+ puts( " NOTEST fclose() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/feof.c b/src/pdclib/functions/stdio/feof.c
new file mode 100644
index 0000000..a57071f
--- /dev/null
+++ b/src/pdclib/functions/stdio/feof.c
@@ -0,0 +1,28 @@
+/* feof( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int feof( struct _PDCLIB_file_t * stream )
+{
+ return stream->status & _PDCLIB_EOFFLAG;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by clearerr(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ferror.c b/src/pdclib/functions/stdio/ferror.c
new file mode 100644
index 0000000..54f43f0
--- /dev/null
+++ b/src/pdclib/functions/stdio/ferror.c
@@ -0,0 +1,28 @@
+/* ferror( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int ferror( struct _PDCLIB_file_t * stream )
+{
+ return stream->status & _PDCLIB_ERRORFLAG;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by clearerr(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fflush.c b/src/pdclib/functions/stdio/fflush.c
new file mode 100644
index 0000000..3d0b297
--- /dev/null
+++ b/src/pdclib/functions/stdio/fflush.c
@@ -0,0 +1,53 @@
+/* fflush( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int fflush( struct _PDCLIB_file_t * stream )
+{
+ if ( stream == NULL )
+ {
+ int rc = 0;
+ stream = _PDCLIB_filelist;
+ /* TODO: Check what happens when fflush( NULL ) encounters write errors, in other libs */
+ while ( stream != NULL )
+ {
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ rc = EOF;
+ }
+ }
+ stream = stream->next;
+ }
+ return rc;
+ }
+ else
+ {
+ return _PDCLIB_flushbuffer( stream );
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgetc.c b/src/pdclib/functions/stdio/fgetc.c
new file mode 100644
index 0000000..bdb233e
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgetc.c
@@ -0,0 +1,38 @@
+/* fgetc( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fgetc( struct _PDCLIB_file_t * stream )
+{
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return EOF;
+ }
+ if ( stream->ungetidx > 0 )
+ {
+ return (unsigned char)stream->ungetbuf[ --(stream->ungetidx) ];
+ }
+ return (unsigned char)stream->buffer[stream->bufidx++];
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgetpos.c b/src/pdclib/functions/stdio/fgetpos.c
new file mode 100644
index 0000000..db9be06
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgetpos.c
@@ -0,0 +1,43 @@
+/* fgetpos( FILE * , fpos_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int fgetpos( struct _PDCLIB_file_t * _PDCLIB_restrict stream, struct _PDCLIB_fpos_t * _PDCLIB_restrict pos )
+{
+ pos->offset = stream->pos.offset + stream->bufidx - stream->ungetidx;
+ pos->status = stream->pos.status;
+ /* TODO: Add mbstate. */
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ fpos_t pos1, pos2;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fgetpos( fh, &pos1 ) == 0 );
+ TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) );
+ TESTCASE( fgetpos( fh, &pos2 ) == 0 );
+ TESTCASE( fsetpos( fh, &pos1 ) == 0 );
+ TESTCASE( ftell( fh ) == 0 );
+ TESTCASE( fsetpos( fh, &pos2 ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fgets.c b/src/pdclib/functions/stdio/fgets.c
new file mode 100644
index 0000000..0499afd
--- /dev/null
+++ b/src/pdclib/functions/stdio/fgets.c
@@ -0,0 +1,88 @@
+/* fgets( char *, int, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ char * dest = s;
+ if ( size == 0 )
+ {
+ return NULL;
+ }
+ if ( size == 1 )
+ {
+ *s = '\0';
+ return s;
+ }
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return NULL;
+ }
+ while ( ( ( *dest++ = stream->buffer[stream->bufidx++] ) != '\n' ) && --size > 0 )
+ {
+ if ( stream->bufidx == stream->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stream ) == EOF )
+ {
+ /* In case of error / EOF before a character is read, this
+ will lead to a \0 be written anyway. Since the results
+ are "indeterminate" by definition, this does not hurt.
+ */
+ break;
+ }
+ }
+ }
+ *dest = '\0';
+ return ( dest == s ) ? NULL : s;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ char buffer[10];
+ const char * fgets_test = "foo\nbar\0baz\nweenie";
+ TESTCASE( ( fh = fopen( testfile, "wb+" ) ) != NULL );
+ TESTCASE( fwrite( fgets_test, 1, 18, fh ) == 18 );
+ rewind( fh );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "foo\n" ) == 0 );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( memcmp( buffer, "bar\0baz\n", 8 ) == 0 );
+ TESTCASE( fgets( buffer, 10, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "weenie" ) == 0 );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fseek( fh, -1, SEEK_END ) == 0 );
+ TESTCASE( fgets( buffer, 1, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "" ) == 0 );
+ TESTCASE( fgets( buffer, 0, fh ) == NULL );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgets( buffer, 1, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "" ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgets( buffer, 2, fh ) == buffer );
+ TESTCASE( strcmp( buffer, "e" ) == 0 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( fgets( buffer, 2, fh ) == NULL );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fopen.c b/src/pdclib/functions/stdio/fopen.c
new file mode 100644
index 0000000..d5241a7
--- /dev/null
+++ b/src/pdclib/functions/stdio/fopen.c
@@ -0,0 +1,102 @@
+/* fopen( const char *, 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 <stdio.h>
+#include <stdlib.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+#include <string.h>
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+struct _PDCLIB_file_t * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode )
+{
+ struct _PDCLIB_file_t * rc;
+ size_t filename_len;
+ if ( mode == NULL || filename == NULL || filename[0] == '\0' )
+ {
+ /* Mode or filename invalid */
+ return NULL;
+ }
+ /* To reduce the number of malloc calls, all data fields are concatenated:
+ * the FILE structure itself,
+ * ungetc buffer,
+ * filename buffer,
+ * data buffer.
+ Data buffer comes last because it might change in size ( setvbuf() ).
+ */
+ filename_len = strlen( filename ) + 1;
+ if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + filename_len + BUFSIZ ) ) == NULL )
+ {
+ /* no memory */
+ return NULL;
+ }
+ if ( ( rc->status = _PDCLIB_filemode( mode ) ) == 0 )
+ {
+ /* invalid mode */
+ free( rc );
+ return NULL;
+ }
+ rc->handle = _PDCLIB_open( filename, rc->status );
+ if ( rc->handle == _PDCLIB_NOHANDLE )
+ {
+ /* OS open() failed */
+ free( rc );
+ return NULL;
+ }
+ /* Setting pointers into the memory block allocated above */
+ rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t );
+ rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE;
+ rc->buffer = rc->filename + filename_len;
+ /* Copying filename to FILE structure */
+ strcpy( rc->filename, filename );
+ /* Initializing the rest of the structure */
+ rc->bufsize = BUFSIZ;
+ rc->bufidx = 0;
+ rc->ungetidx = 0;
+ /* Setting buffer to _IOLBF because "when opened, a stream is fully
+ buffered if and only if it can be determined not to refer to an
+ interactive device."
+ */
+ rc->status |= _IOLBF;
+ /* TODO: Setting mbstate */
+ /* Adding to list of open files */
+ rc->next = _PDCLIB_filelist;
+ _PDCLIB_filelist = rc;
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Some of the tests are not executed for regression tests, as the libc on
+ my system is at once less forgiving (segfaults on mode NULL) and more
+ forgiving (accepts undefined modes).
+ */
+ FILE * fh;
+ remove( testfile );
+ TESTCASE_NOREG( fopen( NULL, NULL ) == NULL );
+ TESTCASE( fopen( NULL, "w" ) == NULL );
+ TESTCASE_NOREG( fopen( "", NULL ) == NULL );
+ TESTCASE( fopen( "", "w" ) == NULL );
+ TESTCASE( fopen( "foo", "" ) == NULL );
+ TESTCASE_NOREG( fopen( testfile, "wq" ) == NULL ); /* Undefined mode */
+ TESTCASE_NOREG( fopen( testfile, "wr" ) == NULL ); /* Undefined mode */
+ TESTCASE( ( fh = fopen( testfile, "w" ) ) != NULL );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fprintf.c b/src/pdclib/functions/stdio/fprintf.c
new file mode 100644
index 0000000..e16adf8
--- /dev/null
+++ b/src/pdclib/functions/stdio/fprintf.c
@@ -0,0 +1,43 @@
+/* fprintf( FILE *, 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int fprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfprintf( stream, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#include <stdint.h>
+#include <stddef.h>
+#define _PDCLIB_FILEID "stdio/fprintf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( stream, ... ) fprintf( stream, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = tmpfile() ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fputc.c b/src/pdclib/functions/stdio/fputc.c
new file mode 100644
index 0000000..05ac792
--- /dev/null
+++ b/src/pdclib/functions/stdio/fputc.c
@@ -0,0 +1,47 @@
+/* fputc( int, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+/* Write the value c (cast to unsigned char) to the given stream.
+ Returns c if successful, EOF otherwise.
+ If a write error occurs, the error indicator of the stream is set.
+*/
+int fputc( int c, struct _PDCLIB_file_t * stream )
+{
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return EOF;
+ }
+ stream->buffer[stream->bufidx++] = (char)c;
+ if ( ( stream->bufidx == stream->bufsize ) /* _IOFBF */
+ || ( ( stream->status & _IOLBF ) && ( (char)c == '\n' ) ) /* _IOLBF */
+ || ( stream->status & _IONBF ) /* _IONBF */
+ )
+ {
+ /* buffer filled, unbuffered stream, or end-of-line. */
+ return ( _PDCLIB_flushbuffer( stream ) == 0 ) ? c : EOF;
+ }
+ return c;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fputs.c b/src/pdclib/functions/stdio/fputs.c
new file mode 100644
index 0000000..a5d7e56
--- /dev/null
+++ b/src/pdclib/functions/stdio/fputs.c
@@ -0,0 +1,69 @@
+/* fputs( const char *, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fputs( const char * _PDCLIB_restrict s, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return EOF;
+ }
+ while ( *s != '\0' )
+ {
+ /* Unbuffered and line buffered streams get flushed when fputs() does
+ write the terminating end-of-line. All streams get flushed if the
+ buffer runs full.
+ */
+ stream->buffer[ stream->bufidx++ ] = *s;
+ if ( ( stream->bufidx == stream->bufsize ) ||
+ ( ( stream->status & _IOLBF ) && *s == '\n' )
+ )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ ++s;
+ }
+ if ( stream->status & _IONBF )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ const char * const message = "SUCCESS testing fputs()";
+ FILE * fh;
+ size_t i;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fputs( message, fh ) >= 0 );
+ rewind( fh );
+ for ( i = 0; i < 23; ++i )
+ {
+ TESTCASE( fgetc( fh ) == message[i] );
+ }
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fread.c b/src/pdclib/functions/stdio/fread.c
new file mode 100644
index 0000000..319e9ba
--- /dev/null
+++ b/src/pdclib/functions/stdio/fread.c
@@ -0,0 +1,81 @@
+/* fwrite( void *, size_t, size_t, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+size_t fread( void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ char * dest = (char *)ptr;
+ size_t nmemb_i;
+ if ( _PDCLIB_prepread( stream ) == EOF )
+ {
+ return 0;
+ }
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ size_t size_i;
+ for ( size_i = 0; size_i < size; ++size_i )
+ {
+ if ( stream->bufidx == stream->bufend )
+ {
+ if ( _PDCLIB_fillbuffer( stream ) == EOF )
+ {
+ /* Could not read requested data */
+ return nmemb_i;
+ }
+ }
+ dest[ nmemb_i * size + size_i ] = stream->buffer[ stream->bufidx++ ];
+ }
+ }
+ return nmemb_i;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ const char * message = "Testing fwrite()...\n";
+ char buffer[21];
+ buffer[20] = 'x';
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ /* fwrite() / readback */
+ TESTCASE( fwrite( message, 1, 20, fh ) == 20 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 20, fh ) == 20 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* same, different nmemb / size settings */
+ rewind( fh );
+ TESTCASE( memset( buffer, '\0', 20 ) == buffer );
+ TESTCASE( fwrite( message, 5, 4, fh ) == 4 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 5, 4, fh ) == 4 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* same... */
+ rewind( fh );
+ TESTCASE( memset( buffer, '\0', 20 ) == buffer );
+ TESTCASE( fwrite( message, 20, 1, fh ) == 1 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 20, 1, fh ) == 1 );
+ TESTCASE( memcmp( buffer, message, 20 ) == 0 );
+ TESTCASE( buffer[20] == 'x' );
+ /* Done. */
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/freopen.c b/src/pdclib/functions/stdio/freopen.c
new file mode 100644
index 0000000..2cb774c
--- /dev/null
+++ b/src/pdclib/functions/stdio/freopen.c
@@ -0,0 +1,104 @@
+/* freopen( const char *, const char *, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+struct _PDCLIB_file_t * freopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ unsigned int status = stream->status & ( _IONBF | _IOLBF | _IOFBF | _PDCLIB_FREEBUFFER | _PDCLIB_DELONCLOSE );
+ /* TODO: This function can change wide orientation of a stream */
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ _PDCLIB_flushbuffer( stream );
+ }
+ if ( ( filename == NULL ) && ( stream->filename == NULL ) )
+ {
+ /* TODO: Special handling for mode changes on std-streams */
+ return NULL;
+ }
+ _PDCLIB_close( stream->handle );
+ /* TODO: It is not nice to do this on a stream we just closed.
+ It does not matter with the current implementation of clearerr(),
+ but it might start to matter if someone replaced that implementation.
+ */
+ clearerr( stream );
+ /* The new filename might not fit the old buffer */
+ if ( filename == NULL )
+ {
+ /* Use previous filename */
+ filename = stream->filename;
+ }
+ else if ( ( stream->filename != NULL ) && ( strlen( stream->filename ) >= strlen( filename ) ) )
+ {
+ /* Copy new filename into existing buffer */
+ strcpy( stream->filename, filename );
+ }
+ else
+ {
+ /* Allocate new buffer */
+ if ( ( stream->filename = (char *)malloc( strlen( filename ) ) ) == NULL )
+ {
+ return NULL;
+ }
+ strcpy( stream->filename, filename );
+ }
+ if ( ( mode == NULL ) || ( filename[0] == '\0' ) )
+ {
+ return NULL;
+ }
+ if ( ( stream->status = _PDCLIB_filemode( mode ) ) == 0 )
+ {
+ return NULL;
+ }
+ /* Re-add the flags we saved above */
+ stream->status |= status;
+ stream->bufidx = 0;
+ stream->bufend = 0;
+ stream->ungetidx = 0;
+ /* TODO: Setting mbstate */
+ if ( ( stream->handle = _PDCLIB_open( filename, stream->status ) ) == _PDCLIB_NOHANDLE )
+ {
+ return NULL;
+ }
+ return stream;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fin;
+ FILE * fout;
+ TESTCASE( ( fin = fopen( testfile1, "wb+" ) ) != NULL );
+ TESTCASE( fputc( 'x', fin ) == 'x' );
+ TESTCASE( fclose( fin ) == 0 );
+ TESTCASE( ( fin = freopen( testfile1, "rb", stdin ) ) != NULL );
+ TESTCASE( getchar() == 'x' );
+
+ TESTCASE( ( fout = freopen( testfile2, "wb+", stdout ) ) != NULL );
+ TESTCASE( putchar( 'x' ) == 'x' );
+ rewind( fout );
+ TESTCASE( fgetc( fout ) == 'x' );
+
+ TESTCASE( fclose( fin ) == 0 );
+ TESTCASE( fclose( fout ) == 0 );
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fscanf.c b/src/pdclib/functions/stdio/fscanf.c
new file mode 100644
index 0000000..cc8c031
--- /dev/null
+++ b/src/pdclib/functions/stdio/fscanf.c
@@ -0,0 +1,41 @@
+/* fscanf( FILE *, 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfscanf( stream, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/fscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( stream, format, ... ) fscanf( stream, format, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = tmpfile() ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fseek.c b/src/pdclib/functions/stdio/fseek.c
new file mode 100644
index 0000000..54f4c4b
--- /dev/null
+++ b/src/pdclib/functions/stdio/fseek.c
@@ -0,0 +1,85 @@
+/* fseek( FILE *, 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 <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fseek( struct _PDCLIB_file_t * stream, long offset, int whence )
+{
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ stream->status &= ~ _PDCLIB_EOFFLAG;
+ if ( stream->status & _PDCLIB_FRW )
+ {
+ stream->status &= ~ ( _PDCLIB_FREAD | _PDCLIB_FWRITE );
+ }
+ return ( _PDCLIB_seek( stream, offset, whence ) != EOF ) ? 0 : EOF;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( fwrite( teststring, 1, strlen( teststring ), fh ) == strlen( teststring ) );
+ /* General functionality */
+ TESTCASE( fseek( fh, -1, SEEK_END ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) - 1 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( (size_t)ftell( fh ) == strlen( teststring ) );
+ TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 );
+ TESTCASE( ftell( fh ) == 0 );
+ TESTCASE( fseek( fh, 5, SEEK_CUR ) == 0 );
+ TESTCASE( ftell( fh ) == 5 );
+ TESTCASE( fseek( fh, -3, SEEK_CUR ) == 0 );
+ TESTCASE( ftell( fh ) == 2 );
+ /* Checking behaviour around EOF */
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ TESTCASE( fgetc( fh ) == EOF );
+ TESTCASE( feof( fh ) );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( ! feof( fh ) );
+ /* Checking undo of ungetc() */
+ TESTCASE( fseek( fh, 0, SEEK_SET ) == 0 );
+ TESTCASE( fgetc( fh ) == teststring[0] );
+ TESTCASE( fgetc( fh ) == teststring[1] );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 3 );
+ TESTCASE( ungetc( teststring[2], fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ TESTCASE( ftell( fh ) == 3 );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fgetc( fh ) == 'x' );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == 2 );
+ TESTCASE( fseek( fh, 2, SEEK_SET ) == 0 );
+ TESTCASE( fgetc( fh ) == teststring[2] );
+ /* Checking error handling */
+ TESTCASE( fseek( fh, -5, SEEK_SET ) == -1 );
+ TESTCASE( fseek( fh, 0, SEEK_END ) == 0 );
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fsetpos.c b/src/pdclib/functions/stdio/fsetpos.c
new file mode 100644
index 0000000..323aaae
--- /dev/null
+++ b/src/pdclib/functions/stdio/fsetpos.c
@@ -0,0 +1,43 @@
+/* fsetpos( FILE *, const fpos_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+int fsetpos( struct _PDCLIB_file_t * stream, const struct _PDCLIB_fpos_t * pos )
+{
+ if ( stream->status & _PDCLIB_FWRITE )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ if ( _PDCLIB_seek( stream, pos->offset, SEEK_SET ) == EOF )
+ {
+ return EOF;
+ }
+ stream->pos.status = pos->status;
+ /* TODO: Add mbstate. */
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* fsetpos() tested together with fsetpos(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ftell.c b/src/pdclib/functions/stdio/ftell.c
new file mode 100644
index 0000000..f4bd300
--- /dev/null
+++ b/src/pdclib/functions/stdio/ftell.c
@@ -0,0 +1,100 @@
+/* ftell( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <limits.h>
+
+#ifndef REGTEST
+
+long int ftell( struct _PDCLIB_file_t * stream )
+{
+ /* ftell() must take into account:
+ - the actual *physical* offset of the file, i.e. the offset as recognized
+ by the operating system (and stored in stream->pos.offset); and
+ - any buffers held by PDCLib, which
+ - in case of unwritten buffers, count in *addition* to the offset; or
+ - in case of unprocessed pre-read buffers, count in *substraction* to
+ the offset. (Remember to count ungetidx into this number.)
+ Conveniently, the calculation ( ( bufend - bufidx ) + ungetidx ) results
+ in just the right number in both cases:
+ - in case of unwritten buffers, ( ( 0 - unwritten ) + 0 )
+ i.e. unwritten bytes as negative number
+ - in case of unprocessed pre-read, ( ( preread - processed ) + unget )
+ i.e. unprocessed bytes as positive number.
+ That is how the somewhat obscure return-value calculation works.
+ */
+ /* If offset is too large for return type, report error instead of wrong
+ offset value.
+ */
+ /* TODO: Check what happens when ungetc() is called on a stream at offset 0 */
+ if ( ( stream->pos.offset - stream->bufend ) > ( LONG_MAX - ( stream->bufidx - stream->ungetidx ) ) )
+ {
+ /* integer overflow */
+ _PDCLIB_errno = _PDCLIB_ERANGE;
+ return -1;
+ }
+ return (long int)( stream->pos.offset - ( ( (int)stream->bufend - (int)stream->bufidx ) + stream->ungetidx ) );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ /* Testing all the basic I/O functions individually would result in lots
+ of duplicated code, so I took the liberty of lumping it all together
+ here.
+ */
+ /* The following functions delegate their tests to here:
+ fgetc fflush rewind fputc ungetc fseek
+ flushbuffer seek fillbuffer prepread prepwrite
+ */
+ char * buffer = (char*)malloc( 4 );
+ FILE * fh;
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IOLBF, 4 ) == 0 );
+ /* Testing ungetc() at offset 0 */
+ rewind( fh );
+ TESTCASE( ungetc( 'x', fh ) == 'x' );
+ TESTCASE( ftell( fh ) == -1l );
+ rewind( fh );
+ TESTCASE( ftell( fh ) == 0l );
+ /* Commence "normal" tests */
+ TESTCASE( fputc( '1', fh ) == '1' );
+ TESTCASE( fputc( '2', fh ) == '2' );
+ TESTCASE( fputc( '3', fh ) == '3' );
+ /* Positions incrementing as expected? */
+ TESTCASE( ftell( fh ) == 3l );
+ TESTCASE_NOREG( fh->pos.offset == 0l );
+ TESTCASE_NOREG( fh->bufidx == 3l );
+ /* Buffer properly flushed when full? */
+ TESTCASE( fputc( '4', fh ) == '4' );
+ TESTCASE_NOREG( fh->pos.offset == 4l );
+ TESTCASE_NOREG( fh->bufidx == 0 );
+ /* fflush() resetting positions as expected? */
+ TESTCASE( fputc( '5', fh ) == '5' );
+ TESTCASE( fflush( fh ) == 0 );
+ TESTCASE( ftell( fh ) == 5l );
+ TESTCASE_NOREG( fh->pos.offset == 5l );
+ TESTCASE_NOREG( fh->bufidx == 0l );
+ /* rewind() resetting positions as expected? */
+ rewind( fh );
+ TESTCASE( ftell( fh ) == 0l );
+ TESTCASE_NOREG( fh->pos.offset == 0 );
+ TESTCASE_NOREG( fh->bufidx == 0 );
+ /* Reading back first character after rewind for basic read check */
+ TESTCASE( fgetc( fh ) == '1' );
+ /* TODO: t.b.c. */
+ TESTCASE( fclose( fh ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/fwrite.c b/src/pdclib/functions/stdio/fwrite.c
new file mode 100644
index 0000000..7958a50
--- /dev/null
+++ b/src/pdclib/functions/stdio/fwrite.c
@@ -0,0 +1,93 @@
+/* fwrite( const void *, size_t, size_t, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream )
+{
+ _PDCLIB_size_t offset = 0;
+ /* TODO: lineend */
+ /* int lineend = 0; */
+ size_t nmemb_i;
+ if ( _PDCLIB_prepwrite( stream ) == EOF )
+ {
+ return 0;
+ }
+ for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i )
+ {
+ size_t size_i;
+ for ( size_i = 0; size_i < size; ++size_i )
+ {
+ if ( ( stream->buffer[ stream->bufidx++ ] = ((char*)ptr)[ nmemb_i * size + size_i ] ) == '\n' )
+ {
+ /* Remember last newline, in case we have to do a partial line-buffered flush */
+ offset = stream->bufidx;
+ /* lineend = true; */
+ }
+ if ( stream->bufidx == stream->bufsize )
+ {
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* Returning number of objects completely buffered */
+ return nmemb_i;
+ }
+ /* lineend = false; */
+ }
+ }
+ }
+ /* Fully-buffered streams are OK. Non-buffered streams must be flushed,
+ line-buffered streams only if there's a newline in the buffer.
+ */
+ switch ( stream->status & ( _IONBF | _IOLBF ) )
+ {
+ case _IONBF:
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* We are in a pinch here. We have an error, which requires a
+ return value < nmemb. On the other hand, all objects have
+ been written to buffer, which means all the caller had to
+ do was removing the error cause, and re-flush the stream...
+ Catch 22. We'll return a value one short, to indicate the
+ error, and can't really do anything about the inconsistency.
+ */
+ return nmemb_i - 1;
+ }
+ break;
+ case _IOLBF:
+ {
+ size_t bufidx = stream->bufidx;
+ stream->bufidx = offset;
+ if ( _PDCLIB_flushbuffer( stream ) == EOF )
+ {
+ /* See comment above. */
+ stream->bufidx = bufidx;
+ return nmemb_i - 1;
+ }
+ stream->bufidx = bufidx - offset;
+ memmove( stream->buffer, stream->buffer + offset, stream->bufidx );
+ }
+ }
+ return nmemb_i;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by fread(). */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/getc.c b/src/pdclib/functions/stdio/getc.c
new file mode 100644
index 0000000..3d082b3
--- /dev/null
+++ b/src/pdclib/functions/stdio/getc.c
@@ -0,0 +1,28 @@
+/* getc( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int getc( struct _PDCLIB_file_t * stream )
+{
+ return fgetc( stream );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/getchar.c b/src/pdclib/functions/stdio/getchar.c
new file mode 100644
index 0000000..34ee545
--- /dev/null
+++ b/src/pdclib/functions/stdio/getchar.c
@@ -0,0 +1,28 @@
+/* getchar( void )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int getchar( void )
+{
+ return fgetc( stdin );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/perror.c b/src/pdclib/functions/stdio/perror.c
new file mode 100644
index 0000000..dd6633c
--- /dev/null
+++ b/src/pdclib/functions/stdio/perror.c
@@ -0,0 +1,58 @@
+/* perror( 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 <stdio.h>
+#include <errno.h>
+#include <locale.h>
+
+#ifndef REGTEST
+
+/* TODO: Doing this via a static array is not the way to do it. */
+void perror( const char * s )
+{
+ if ( ( s != NULL ) && ( s[0] != '\n' ) )
+ {
+ fprintf( stderr, "%s: ", s );
+ }
+ if ( errno >= _PDCLIB_ERRNO_MAX )
+ {
+ fprintf( stderr, "Unknown error\n" );
+ }
+ else
+ {
+ fprintf( stderr, "%s\n", _PDCLIB_lc_messages.errno_texts[errno] );
+ }
+ return;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+int main( void )
+{
+ FILE * fh;
+ unsigned long long max = ULLONG_MAX;
+ char buffer[100];
+ sprintf( buffer, "%llu", max );
+ TESTCASE( ( fh = freopen( testfile, "wb+", stderr ) ) != NULL );
+ TESTCASE( strtol( buffer, NULL, 10 ) == LONG_MAX );
+ perror( "Test" );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 7, fh ) == 7 );
+ TESTCASE( memcmp( buffer, "Test: ", 6 ) == 0 );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/printf.c b/src/pdclib/functions/stdio/printf.c
new file mode 100644
index 0000000..6d10113
--- /dev/null
+++ b/src/pdclib/functions/stdio/printf.c
@@ -0,0 +1,44 @@
+/* printf( 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int printf( const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vfprintf( stdout, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/printf.c"
+#define _PDCLIB_FILEIO
+#include <stdint.h>
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( stream, ... ) printf( __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/putc.c b/src/pdclib/functions/stdio/putc.c
new file mode 100644
index 0000000..c1eb2b0
--- /dev/null
+++ b/src/pdclib/functions/stdio/putc.c
@@ -0,0 +1,28 @@
+/* putc( int, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int putc( int c, struct _PDCLIB_file_t * stream )
+{
+ return fputc( c, stream );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/putchar.c b/src/pdclib/functions/stdio/putchar.c
new file mode 100644
index 0000000..15bf299
--- /dev/null
+++ b/src/pdclib/functions/stdio/putchar.c
@@ -0,0 +1,28 @@
+/* putchar( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int putchar( int c )
+{
+ return fputc( c, stdout );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/puts.c b/src/pdclib/functions/stdio/puts.c
new file mode 100644
index 0000000..89240cb
--- /dev/null
+++ b/src/pdclib/functions/stdio/puts.c
@@ -0,0 +1,67 @@
+/* puts( 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 <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+extern char * _PDCLIB_eol;
+
+int puts( const char * s )
+{
+ if ( _PDCLIB_prepwrite( stdout ) == EOF )
+ {
+ return EOF;
+ }
+ while ( *s != '\0' )
+ {
+ stdout->buffer[ stdout->bufidx++ ] = *s++;
+ if ( stdout->bufidx == stdout->bufsize )
+ {
+ if ( _PDCLIB_flushbuffer( stdout ) == EOF )
+ {
+ return EOF;
+ }
+ }
+ }
+ stdout->buffer[ stdout->bufidx++ ] = '\n';
+ if ( ( stdout->bufidx == stdout->bufsize ) ||
+ ( stdout->status & ( _IOLBF | _IONBF ) ) )
+ {
+ return _PDCLIB_flushbuffer( stdout );
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ FILE * fh;
+ const char * message = "SUCCESS testing puts()";
+ char buffer[23];
+ buffer[22] = 'x';
+ TESTCASE( ( fh = freopen( testfile, "wb+", stdout ) ) != NULL );
+ TESTCASE( puts( message ) >= 0 );
+ rewind( fh );
+ TESTCASE( fread( buffer, 1, 22, fh ) == 22 );
+ TESTCASE( memcmp( buffer, message, 22 ) == 0 );
+ TESTCASE( buffer[22] == 'x' );
+ TESTCASE( fclose( fh ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/rename.c b/src/pdclib/functions/stdio/rename.c
new file mode 100644
index 0000000..5d45f1f
--- /dev/null
+++ b/src/pdclib/functions/stdio/rename.c
@@ -0,0 +1,84 @@
+/* rename( const char *, 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 <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+#include <string.h>
+
+extern struct _PDCLIB_file_t * _PDCLIB_filelist;
+
+int rename( const char * old, const char * new )
+{
+ struct _PDCLIB_file_t * current = _PDCLIB_filelist;
+ while ( current != NULL )
+ {
+ if ( ( current->filename != NULL ) && ( strcmp( current->filename, old ) == 0 ) )
+ {
+ /* File of that name currently open. Do not rename. */
+ return EOF;
+ }
+ current = current->next;
+ }
+ return _PDCLIB_rename( old, new );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ FILE * file;
+ remove( testfile1 );
+ remove( testfile2 );
+ /* make sure that neither file exists */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( fopen( testfile2, "r" ) == NULL );
+ /* rename file 1 to file 2 - expected to fail */
+ TESTCASE( rename( testfile1, testfile2 ) == -1 );
+ /* create file 1 */
+ TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( fputs( "x", file ) != EOF );
+ TESTCASE( fclose( file ) == 0 );
+ /* check that file 1 exists */
+ TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* rename file 1 to file 2 */
+ TESTCASE( rename( testfile1, testfile2 ) == 0 );
+ /* check that file 2 exists, file 1 does not */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( ( file = fopen( testfile2, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* create another file 1 */
+ TESTCASE( ( file = fopen( testfile1, "w" ) ) != NULL );
+ TESTCASE( fputs( "x", file ) != EOF );
+ TESTCASE( fclose( file ) == 0 );
+ /* check that file 1 exists */
+ TESTCASE( ( file = fopen( testfile1, "r" ) ) != NULL );
+ TESTCASE( fclose( file ) == 0 );
+ /* rename file 1 to file 2 - expected to fail, see comment in
+ _PDCLIB_rename() itself.
+ */
+ /* NOREG as glibc overwrites existing destination file. */
+ TESTCASE_NOREG( rename( testfile1, testfile2 ) == -1 );
+ /* remove both files */
+ TESTCASE( remove( testfile1 ) == 0 );
+ TESTCASE( remove( testfile2 ) == 0 );
+ /* check that they're gone */
+ TESTCASE( fopen( testfile1, "r" ) == NULL );
+ TESTCASE( fopen( testfile2, "r" ) == NULL );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/rewind.c b/src/pdclib/functions/stdio/rewind.c
new file mode 100644
index 0000000..a449b7d
--- /dev/null
+++ b/src/pdclib/functions/stdio/rewind.c
@@ -0,0 +1,29 @@
+/* rewind( FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+void rewind( struct _PDCLIB_file_t * stream )
+{
+ stream->status &= ~ _PDCLIB_ERRORFLAG;
+ fseek( stream, 0L, SEEK_SET );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/scanf.c b/src/pdclib/functions/stdio/scanf.c
new file mode 100644
index 0000000..b29b1d5
--- /dev/null
+++ b/src/pdclib/functions/stdio/scanf.c
@@ -0,0 +1,39 @@
+/* scanf( 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int scanf( const char * _PDCLIB_restrict format, ... )
+{
+ va_list ap;
+ va_start( ap, format );
+ return vfscanf( stdin, format, ap );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/scanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( stream, format, ... ) scanf( format, __VA_ARGS__ )
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/setbuf.c b/src/pdclib/functions/stdio/setbuf.c
new file mode 100644
index 0000000..6c32072
--- /dev/null
+++ b/src/pdclib/functions/stdio/setbuf.c
@@ -0,0 +1,55 @@
+/* setbuf( FILE *, char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+void setbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf )
+{
+ if ( buf == NULL )
+ {
+ setvbuf( stream, buf, _IONBF, BUFSIZ );
+ }
+ else
+ {
+ setvbuf( stream, buf, _IOFBF, BUFSIZ );
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdlib.h>
+
+int main( void )
+{
+ /* TODO: Extend testing once setvbuf() is finished. */
+#ifndef REGTEST
+ char buffer[ BUFSIZ + 1 ];
+ FILE * fh;
+ /* full buffered */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ setbuf( fh, buffer );
+ TESTCASE( fh->buffer == buffer );
+ TESTCASE( fh->bufsize == BUFSIZ );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* not buffered */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ setbuf( fh, NULL );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
+ TESTCASE( fclose( fh ) == 0 );
+#else
+ puts( " NOTEST setbuf() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/setvbuf.c b/src/pdclib/functions/stdio/setvbuf.c
new file mode 100644
index 0000000..00592ff
--- /dev/null
+++ b/src/pdclib/functions/stdio/setvbuf.c
@@ -0,0 +1,108 @@
+/* setvbuf( FILE *, char *, int, 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 <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifndef REGTEST
+
+int setvbuf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, char * _PDCLIB_restrict buf, int mode, size_t size )
+{
+ switch ( mode )
+ {
+ case _IONBF:
+ /* When unbuffered I/O is requested, we keep the buffer anyway, as
+ we don't want to e.g. flush the stream for every character of a
+ stream being printed.
+ */
+ break;
+ case _IOFBF:
+ case _IOLBF:
+ if ( size > INT_MAX || size == 0 )
+ {
+ /* PDCLib only supports buffers up to INT_MAX in size. A size
+ of zero doesn't make sense.
+ */
+ return -1;
+ }
+ if ( buf == NULL )
+ {
+ /* User requested buffer size, but leaves it to library to
+ allocate the buffer.
+ */
+ /* If current buffer is big enough for requested size, but not
+ over twice as big (and wasting memory space), we use the
+ current buffer (i.e., do nothing), to save the malloc() /
+ free() overhead.
+ */
+ if ( ( stream->bufsize < size ) || ( stream->bufsize > ( size << 1 ) ) )
+ {
+ /* Buffer too small, or much too large - allocate. */
+ if ( ( buf = (char *) malloc( size ) ) == NULL )
+ {
+ /* Out of memory error. */
+ return -1;
+ }
+ /* This buffer must be free()d on fclose() */
+ stream->status |= _PDCLIB_FREEBUFFER;
+ }
+ }
+ stream->buffer = buf;
+ stream->bufsize = size;
+ break;
+ default:
+ /* If mode is something else than _IOFBF, _IOLBF or _IONBF -> exit */
+ return -1;
+ }
+ /* Deleting current buffer mode */
+ stream->status &= ~( _IOFBF | _IOLBF | _IONBF );
+ /* Set user-defined mode */
+ stream->status |= mode;
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <errno.h>
+
+#define BUFFERSIZE 500
+
+int main( void )
+{
+#ifndef REGTEST
+ char buffer[ BUFFERSIZE ];
+ FILE * fh;
+ /* full buffered, user-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IOFBF, BUFFERSIZE ) == 0 );
+ TESTCASE( fh->buffer == buffer );
+ TESTCASE( fh->bufsize == BUFFERSIZE );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOFBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* line buffered, lib-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, NULL, _IOLBF, BUFFERSIZE ) == 0 );
+ TESTCASE( fh->buffer != NULL );
+ TESTCASE( fh->bufsize == BUFFERSIZE );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IOLBF );
+ TESTCASE( fclose( fh ) == 0 );
+ /* not buffered, user-supplied buffer */
+ TESTCASE( ( fh = tmpfile() ) != NULL );
+ TESTCASE( setvbuf( fh, buffer, _IONBF, BUFFERSIZE ) == 0 );
+ TESTCASE( ( fh->status & ( _IOFBF | _IONBF | _IOLBF ) ) == _IONBF );
+ TESTCASE( fclose( fh ) == 0 );
+#else
+ puts( " NOTEST setvbuf() test driver is PDCLib-specific." );
+#endif
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/snprintf.c b/src/pdclib/functions/stdio/snprintf.c
new file mode 100644
index 0000000..f095b8c
--- /dev/null
+++ b/src/pdclib/functions/stdio/snprintf.c
@@ -0,0 +1,43 @@
+/* snprintf( char *, size_t, 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int snprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, ...)
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsnprintf( s, n, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/snprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( s, ... ) snprintf( s, 100, __VA_ARGS__ )
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ TESTCASE( snprintf( NULL, 0, "foo" ) == 3 );
+ TESTCASE( snprintf( NULL, 0, "%d", 100 ) == 3 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/sprintf.c b/src/pdclib/functions/stdio/sprintf.c
new file mode 100644
index 0000000..ce3a7ff
--- /dev/null
+++ b/src/pdclib/functions/stdio/sprintf.c
@@ -0,0 +1,41 @@
+/* sprintf( char *, 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 <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int sprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ...)
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsnprintf( s, SIZE_MAX, format, ap ); /* TODO: replace with non-checking call */
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/sprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stddef.h>
+
+#include "_PDCLIB_test.h"
+
+#define testprintf( s, ... ) sprintf( s, __VA_ARGS__ )
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/sscanf.c b/src/pdclib/functions/stdio/sscanf.c
new file mode 100644
index 0000000..9ba830d
--- /dev/null
+++ b/src/pdclib/functions/stdio/sscanf.c
@@ -0,0 +1,39 @@
+/* sscanf( const char *, 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 <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... )
+{
+ int rc;
+ va_list ap;
+ va_start( ap, format );
+ rc = vsscanf( s, format, ap );
+ va_end( ap );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/sscanf.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+#define testscanf( s, format, ... ) sscanf( s, format, __VA_ARGS__ )
+
+int main( void )
+{
+ char source[100];
+#include "scanf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/testfile.txt b/src/pdclib/functions/stdio/testfile.txt
new file mode 100644
index 0000000..f08c4d3
--- /dev/null
+++ b/src/pdclib/functions/stdio/testfile.txt
Binary files differ
diff --git a/src/pdclib/functions/stdio/tmpnam.c b/src/pdclib/functions/stdio/tmpnam.c
new file mode 100644
index 0000000..5909aff
--- /dev/null
+++ b/src/pdclib/functions/stdio/tmpnam.c
@@ -0,0 +1,42 @@
+/* tmpnam( char * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+#include "pdclib/_PDCLIB_glue.h"
+
+#include <string.h>
+
+char * tmpnam( char * s )
+{
+ static char filename[ L_tmpnam ];
+ FILE * file = tmpfile();
+ if ( s == NULL )
+ {
+ s = filename;
+ }
+ strcpy( s, file->filename );
+ fclose( file );
+ return s;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <string.h>
+
+int main( void )
+{
+ TESTCASE( strlen( tmpnam( NULL ) ) < L_tmpnam );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/ungetc.c b/src/pdclib/functions/stdio/ungetc.c
new file mode 100644
index 0000000..dc5260b
--- /dev/null
+++ b/src/pdclib/functions/stdio/ungetc.c
@@ -0,0 +1,32 @@
+/* ungetc( int, FILE * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+
+#ifndef REGTEST
+
+int ungetc( int c, struct _PDCLIB_file_t * stream )
+{
+ if ( c == EOF || stream->ungetidx == _PDCLIB_UNGETCBUFSIZE )
+ {
+ return -1;
+ }
+ return stream->ungetbuf[stream->ungetidx++] = (unsigned char) c;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ /* Testing covered by ftell.c */
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vfprintf.c b/src/pdclib/functions/stdio/vfprintf.c
new file mode 100644
index 0000000..6f31bbd
--- /dev/null
+++ b/src/pdclib/functions/stdio/vfprintf.c
@@ -0,0 +1,74 @@
+/* vfprintf( FILE *, const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#ifndef REGTEST
+
+int vfprintf( struct _PDCLIB_file_t * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = SIZE_MAX;
+ status.i = 0;
+ status.current = 0;
+ status.s = NULL;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = stream;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, print verbatim */
+ putc( *(format++), stream );
+ status.i++;
+ }
+ else
+ {
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vfprintf.c"
+#define _PDCLIB_FILEIO
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vfprintf( stream, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = tmpfile() ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vfscanf.c b/src/pdclib/functions/stdio/vfscanf.c
new file mode 100644
index 0000000..bb24456
--- /dev/null
+++ b/src/pdclib/functions/stdio/vfscanf.c
@@ -0,0 +1,113 @@
+/* vfscanf( FILE *, const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifndef REGTEST
+
+int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 0;
+ status.i = 0;
+ status.current = 0;
+ status.s = NULL;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = stream;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) )
+ {
+ int c;
+ /* No conversion specifier, match verbatim */
+ if ( isspace( *format ) )
+ {
+ /* Whitespace char in format string: Skip all whitespaces */
+ /* No whitespaces in input does not result in matching error */
+ while ( isspace( c = getc( stream ) ) )
+ {
+ ++status.i;
+ }
+ if ( ! feof( stream ) )
+ {
+ ungetc( c, stream );
+ }
+ }
+ else
+ {
+ /* Non-whitespace char in format string: Match verbatim */
+ if ( ( ( c = getc( stream ) ) != *format ) || feof( stream ) )
+ {
+ /* Matching error */
+ if ( ! feof( stream ) && ! ferror( stream ) )
+ {
+ ungetc( c, stream );
+ }
+ else if ( status.n == 0 )
+ {
+ return EOF;
+ }
+ return status.n;
+ }
+ else
+ {
+ ++status.i;
+ }
+ }
+ ++format;
+ }
+ else
+ {
+ /* NULL return code indicates matching error */
+ if ( rc == NULL )
+ {
+ break;
+ }
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.n;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vfscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( FILE * stream, const char * format, ... )
+{
+ va_list ap;
+ int result;
+ va_start( ap, format );
+ result = vfscanf( stream, format, ap );
+ va_end( ap );
+ return result;
+}
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = tmpfile() ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vprintf.c b/src/pdclib/functions/stdio/vprintf.c
new file mode 100644
index 0000000..fe80152
--- /dev/null
+++ b/src/pdclib/functions/stdio/vprintf.c
@@ -0,0 +1,46 @@
+/* vprintf( const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int vprintf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ return vfprintf( stdout, format, arg );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vprintf.c"
+#define _PDCLIB_FILEIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vprintf( format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * target;
+ TESTCASE( ( target = freopen( testfile, "wb+", stdout ) ) != NULL );
+#include "printf_testcases.h"
+ TESTCASE( fclose( target ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vscanf.c b/src/pdclib/functions/stdio/vscanf.c
new file mode 100644
index 0000000..d5ae5b3
--- /dev/null
+++ b/src/pdclib/functions/stdio/vscanf.c
@@ -0,0 +1,45 @@
+/* vscanf( const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int vscanf( const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ return vfscanf( stdin, format, arg );
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vscanf.c"
+#define _PDCLIB_FILEIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( FILE * stream, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vscanf( format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ FILE * source;
+ TESTCASE( ( source = freopen( testfile, "wb+", stdin ) ) != NULL );
+#include "scanf_testcases.h"
+ TESTCASE( fclose( source ) == 0 );
+ TESTCASE( remove( testfile ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsnprintf.c b/src/pdclib/functions/stdio/vsnprintf.c
new file mode 100644
index 0000000..e57e682
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsnprintf.c
@@ -0,0 +1,80 @@
+/* vsnprintf( char *, size_t, const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int vsnprintf( char * _PDCLIB_restrict s, size_t n, const char * _PDCLIB_restrict format, _PDCLIB_va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = n;
+ status.i = 0;
+ status.current = 0;
+ status.s = s;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = NULL;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, print verbatim */
+ if ( status.i < n )
+ {
+ s[ status.i ] = *format;
+ }
+ status.i++;
+ format++;
+ }
+ else
+ {
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ if ( status.i < n )
+ {
+ s[ status.i ] = '\0';
+ }
+ va_end( status.arg );
+ return status.i;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsnprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( char * s, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vsnprintf( s, 100, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsprintf.c b/src/pdclib/functions/stdio/vsprintf.c
new file mode 100644
index 0000000..4ab2742
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsprintf.c
@@ -0,0 +1,44 @@
+/* vsprintf( char *, const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifndef REGTEST
+
+int vsprintf( char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+{
+ return vsnprintf( s, SIZE_MAX, format, arg ); /* TODO: Replace with a non-checking call */
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsprintf.c"
+#define _PDCLIB_STRINGIO
+#include <stdint.h>
+#include <stddef.h>
+#include "_PDCLIB_test.h"
+
+static int testprintf( char * s, const char * format, ... )
+{
+ int i;
+ va_list arg;
+ va_start( arg, format );
+ i = vsprintf( s, format, arg );
+ va_end( arg );
+ return i;
+}
+
+int main( void )
+{
+ char target[100];
+#include "printf_testcases.h"
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/stdio/vsscanf.c b/src/pdclib/functions/stdio/vsscanf.c
new file mode 100644
index 0000000..e76e70e
--- /dev/null
+++ b/src/pdclib/functions/stdio/vsscanf.c
@@ -0,0 +1,109 @@
+/* vsscanf( const char *, const char *, va_list )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifndef REGTEST
+
+int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, va_list arg )
+{
+ /* TODO: This function should interpret format as multibyte characters. */
+ struct _PDCLIB_status_t status;
+ status.base = 0;
+ status.flags = 0;
+ status.n = 0;
+ status.i = 0;
+ status.current = 0;
+ status.s = (char *) s;
+ status.width = 0;
+ status.prec = EOF;
+ status.stream = NULL;
+ va_copy( status.arg, arg );
+
+ while ( *format != '\0' )
+ {
+ const char * rc;
+ if ( ( *format != '%' ) || ( ( rc = _PDCLIB_scan( format, &status ) ) == format ) )
+ {
+ /* No conversion specifier, match verbatim */
+ if ( isspace( *format ) )
+ {
+ /* Whitespace char in format string: Skip all whitespaces */
+ /* No whitespaces in input do not result in matching error */
+ while ( isspace( *status.s ) )
+ {
+ ++status.s;
+ ++status.i;
+ }
+ }
+ else
+ {
+ /* Non-whitespace char in format string: Match verbatim */
+ if ( *status.s != *format )
+ {
+ if ( *status.s == '\0' && status.n == 0 )
+ {
+ /* Early input error */
+ return EOF;
+ }
+ /* Matching error */
+ return status.n;
+ }
+ else
+ {
+ ++status.s;
+ ++status.i;
+ }
+ }
+ ++format;
+ }
+ else
+ {
+ /* NULL return code indicates error */
+ if ( rc == NULL )
+ {
+ if ( ( *status.s == '\n' ) && ( status.n == 0 ) )
+ {
+ status.n = EOF;
+ }
+ break;
+ }
+ /* Continue parsing after conversion specifier */
+ format = rc;
+ }
+ }
+ va_end( status.arg );
+ return status.n;
+}
+
+#endif
+
+#ifdef TEST
+#define _PDCLIB_FILEID "stdio/vsscanf.c"
+#define _PDCLIB_STRINGIO
+
+#include "_PDCLIB_test.h"
+
+static int testscanf( const char * stream, const char * format, ... )
+{
+ va_list ap;
+ int result;
+ va_start( ap, format );
+ result = vsscanf( stream, format, ap );
+ va_end( ap );
+ return result;
+}
+
+int main( void )
+{
+ char source[100];
+#include "scanf_testcases.h"
+ 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..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
diff --git a/src/pdclib/functions/string/memchr.c b/src/pdclib/functions/string/memchr.c
new file mode 100644
index 0000000..29598a7
--- /dev/null
+++ b/src/pdclib/functions/string/memchr.c
@@ -0,0 +1,41 @@
+/* memchr( const void *, int, 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 <string.h>
+
+#ifndef REGTEST
+
+void * memchr( const void * s, int c, size_t n )
+{
+ const unsigned char * p = (const unsigned char *) s;
+ while ( n-- )
+ {
+ if ( *p == (unsigned char) c )
+ {
+ return (void *) p;
+ }
+ ++p;
+ }
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( memchr( abcde, 'c', 5 ) == &abcde[2] );
+ TESTCASE( memchr( abcde, 'a', 1 ) == &abcde[0] );
+ TESTCASE( memchr( abcde, 'a', 0 ) == NULL );
+ TESTCASE( memchr( abcde, '\0', 5 ) == NULL );
+ TESTCASE( memchr( abcde, '\0', 6 ) == &abcde[5] );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/memcmp.c b/src/pdclib/functions/string/memcmp.c
new file mode 100644
index 0000000..709b941
--- /dev/null
+++ b/src/pdclib/functions/string/memcmp.c
@@ -0,0 +1,43 @@
+/* memcmp( const void *, const 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 <string.h>
+
+#ifndef REGTEST
+
+int memcmp( const void * s1, const void * s2, size_t n )
+{
+ const unsigned char * p1 = (const unsigned char *) s1;
+ const unsigned char * p2 = (const unsigned char *) s2;
+ while ( n-- )
+ {
+ if ( *p1 != *p2 )
+ {
+ return *p1 - *p2;
+ }
+ ++p1;
+ ++p2;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ const char xxxxx[] = "xxxxx";
+ TESTCASE( memcmp( abcde, abcdx, 5 ) < 0 );
+ TESTCASE( memcmp( abcde, abcdx, 4 ) == 0 );
+ TESTCASE( memcmp( abcde, xxxxx, 0 ) == 0 );
+ TESTCASE( memcmp( xxxxx, abcde, 1 ) > 0 );
+ return 0;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/memcpy.c b/src/pdclib/functions/string/memcpy.c
new file mode 100644
index 0000000..21ef10e
--- /dev/null
+++ b/src/pdclib/functions/string/memcpy.c
@@ -0,0 +1,40 @@
+/* memcpy( void *, const 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 <string.h>
+
+#ifndef REGTEST
+
+void * memcpy( void * _PDCLIB_restrict s1, const void * _PDCLIB_restrict s2, size_t n )
+{
+ char * dest = (char *) s1;
+ const char * src = (const char *) s2;
+ while ( n-- )
+ {
+ *dest++ = *src++;
+ }
+ return s1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxxxxxxxx";
+ TESTCASE( memcpy( s, abcde, 6 ) == s );
+ TESTCASE( s[4] == 'e' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( memcpy( s + 5, abcde, 5 ) == s + 5 );
+ TESTCASE( s[9] == 'e' );
+ TESTCASE( s[10] == 'x' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/memmove.c b/src/pdclib/functions/string/memmove.c
new file mode 100644
index 0000000..af89813
--- /dev/null
+++ b/src/pdclib/functions/string/memmove.c
@@ -0,0 +1,52 @@
+/* memmove( void *, const 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 <string.h>
+
+#ifndef REGTEST
+
+void * memmove( void * s1, const void * s2, size_t n )
+{
+ char * dest = (char *) s1;
+ const char * src = (const char *) s2;
+ if ( dest <= src )
+ {
+ while ( n-- )
+ {
+ *dest++ = *src++;
+ }
+ }
+ else
+ {
+ src += n;
+ dest += n;
+ while ( n-- )
+ {
+ *--dest = *--src;
+ }
+ }
+ return s1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxabcde";
+ TESTCASE( memmove( s, s + 4, 5 ) == s );
+ TESTCASE( s[0] == 'a' );
+ TESTCASE( s[4] == 'e' );
+ TESTCASE( s[5] == 'b' );
+ TESTCASE( memmove( s + 4, s, 5 ) == s + 4 );
+ TESTCASE( s[4] == 'a' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/memset.c b/src/pdclib/functions/string/memset.c
new file mode 100644
index 0000000..522ad77
--- /dev/null
+++ b/src/pdclib/functions/string/memset.c
@@ -0,0 +1,40 @@
+/* memset( void *, int, 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 <string.h>
+
+#ifndef REGTEST
+
+void * memset( void * s, int c, size_t n )
+{
+ unsigned char * p = (unsigned char *) s;
+ while ( n-- )
+ {
+ *p++ = (unsigned char) c;
+ }
+ return s;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxxxxxx";
+ TESTCASE( memset( s, 'o', 10 ) == s );
+ TESTCASE( s[9] == 'o' );
+ TESTCASE( memset( s, '_', 0 ) == s );
+ TESTCASE( s[0] == 'o' );
+ TESTCASE( memset( s, '_', 1 ) == s );
+ TESTCASE( s[0] == '_' );
+ TESTCASE( s[1] == 'o' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strcat.c b/src/pdclib/functions/string/strcat.c
new file mode 100644
index 0000000..18fd409
--- /dev/null
+++ b/src/pdclib/functions/string/strcat.c
@@ -0,0 +1,46 @@
+/* strcat( char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strcat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 )
+{
+ char * rc = s1;
+ if ( *s1 )
+ {
+ while ( *++s1 );
+ }
+ while ( (*s1++ = *s2++) );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xx\0xxxxxx";
+ TESTCASE( strcat( s, abcde ) == s );
+ TESTCASE( s[2] == 'a' );
+ TESTCASE( s[6] == 'e' );
+ TESTCASE( s[7] == '\0' );
+ TESTCASE( s[8] == 'x' );
+ s[0] = '\0';
+ TESTCASE( strcat( s, abcdx ) == s );
+ TESTCASE( s[4] == 'x' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( strcat( s, "\0" ) == s );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( s[6] == 'e' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strchr.c b/src/pdclib/functions/string/strchr.c
new file mode 100644
index 0000000..621100e
--- /dev/null
+++ b/src/pdclib/functions/string/strchr.c
@@ -0,0 +1,40 @@
+/* strchr( const 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 <string.h>
+
+#ifndef REGTEST
+
+char * strchr( const char * s, int c )
+{
+ do
+ {
+ if ( *s == (char) c )
+ {
+ return (char *) s;
+ }
+ } while ( *s++ );
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char abccd[] = "abccd";
+ TESTCASE( strchr( abccd, 'x' ) == NULL );
+ TESTCASE( strchr( abccd, 'a' ) == &abccd[0] );
+ TESTCASE( strchr( abccd, 'd' ) == &abccd[4] );
+ TESTCASE( strchr( abccd, '\0' ) == &abccd[5] );
+ TESTCASE( strchr( abccd, 'c' ) == &abccd[2] );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strcmp.c b/src/pdclib/functions/string/strcmp.c
new file mode 100644
index 0000000..639fc10
--- /dev/null
+++ b/src/pdclib/functions/string/strcmp.c
@@ -0,0 +1,41 @@
+/* strcmp( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+int strcmp( const char * s1, const char * s2 )
+{
+ while ( ( *s1 ) && ( *s1 == *s2 ) )
+ {
+ ++s1;
+ ++s2;
+ }
+ return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char cmpabcde[] = "abcde";
+ char cmpabcd_[] = "abcd\xfc";
+ char empty[] = "";
+ TESTCASE( strcmp( abcde, cmpabcde ) == 0 );
+ TESTCASE( strcmp( abcde, abcdx ) < 0 );
+ TESTCASE( strcmp( abcdx, abcde ) > 0 );
+ TESTCASE( strcmp( empty, abcde ) < 0 );
+ TESTCASE( strcmp( abcde, empty ) > 0 );
+ TESTCASE( strcmp( abcde, cmpabcd_ ) < 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strcoll.c b/src/pdclib/functions/string/strcoll.c
new file mode 100644
index 0000000..41d466a
--- /dev/null
+++ b/src/pdclib/functions/string/strcoll.c
@@ -0,0 +1,46 @@
+/* strcoll( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+int strcoll( const char * s1, const char * s2 )
+{
+ return strcmp( s1, s2 );
+
+ /* FIXME: This code became invalid when we started doing *real* locales... */
+ /*
+ while ( ( *s1 ) && ( _PDCLIB_lc_ctype[(unsigned char)*s1].collation == _PDCLIB_lc_ctype[(unsigned char)*s2].collation ) )
+ {
+ ++s1;
+ ++s2;
+ }
+ return ( _PDCLIB_lc_ctype[(unsigned char)*s1].collation == _PDCLIB_lc_ctype[(unsigned char)*s2].collation );
+ */
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char cmpabcde[] = "abcde";
+ char empty[] = "";
+ TESTCASE( strcmp( abcde, cmpabcde ) == 0 );
+ TESTCASE( strcmp( abcde, abcdx ) < 0 );
+ TESTCASE( strcmp( abcdx, abcde ) > 0 );
+ TESTCASE( strcmp( empty, abcde ) < 0 );
+ TESTCASE( strcmp( abcde, empty ) > 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strcpy.c b/src/pdclib/functions/string/strcpy.c
new file mode 100644
index 0000000..e0357c8
--- /dev/null
+++ b/src/pdclib/functions/string/strcpy.c
@@ -0,0 +1,37 @@
+/* strcpy( char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strcpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 )
+{
+ char * rc = s1;
+ while ( ( *s1++ = *s2++ ) );
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxx";
+ TESTCASE( strcpy( s, "" ) == s );
+ TESTCASE( s[0] == '\0' );
+ TESTCASE( s[1] == 'x' );
+ TESTCASE( strcpy( s, abcde ) == s );
+ TESTCASE( s[0] == 'a' );
+ TESTCASE( s[4] == 'e' );
+ TESTCASE( s[5] == '\0' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strcspn.c b/src/pdclib/functions/string/strcspn.c
new file mode 100644
index 0000000..84f8af1
--- /dev/null
+++ b/src/pdclib/functions/string/strcspn.c
@@ -0,0 +1,50 @@
+/* strcspn( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+size_t strcspn( const char * s1, const char * s2 )
+{
+ size_t len = 0;
+ const char * p;
+ while ( s1[len] )
+ {
+ p = s2;
+ while ( *p )
+ {
+ if ( s1[len] == *p++ )
+ {
+ return len;
+ }
+ }
+ ++len;
+ }
+ return len;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( strcspn( abcde, "x" ) == 5 );
+ TESTCASE( strcspn( abcde, "xyz" ) == 5 );
+ TESTCASE( strcspn( abcde, "zyx" ) == 5 );
+ TESTCASE( strcspn( abcdx, "x" ) == 4 );
+ TESTCASE( strcspn( abcdx, "xyz" ) == 4 );
+ TESTCASE( strcspn( abcdx, "zyx" ) == 4 );
+ TESTCASE( strcspn( abcde, "a" ) == 0 );
+ TESTCASE( strcspn( abcde, "abc" ) == 0 );
+ TESTCASE( strcspn( abcde, "cba" ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strerror.c b/src/pdclib/functions/string/strerror.c
new file mode 100644
index 0000000..4506376
--- /dev/null
+++ b/src/pdclib/functions/string/strerror.c
@@ -0,0 +1,41 @@
+/* strerror( int )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <string.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+/* TODO: Doing this via a static array is not the way to do it. */
+char * strerror( int errnum )
+{
+ if ( errnum >= _PDCLIB_ERRNO_MAX )
+ {
+ return (char *)"Unknown error";
+ }
+ else
+ {
+ return _PDCLIB_lc_messages.errno_texts[errnum];
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+int main( void )
+{
+ TESTCASE( strerror( ERANGE ) != strerror( EDOM ) );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strlen.c b/src/pdclib/functions/string/strlen.c
new file mode 100644
index 0000000..c1a620e
--- /dev/null
+++ b/src/pdclib/functions/string/strlen.c
@@ -0,0 +1,34 @@
+/* strlen( 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 <string.h>
+
+#ifndef REGTEST
+
+size_t strlen( const char * s )
+{
+ size_t rc = 0;
+ while ( s[rc] )
+ {
+ ++rc;
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( strlen( abcde ) == 5 );
+ TESTCASE( strlen( "" ) == 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strncat.c b/src/pdclib/functions/string/strncat.c
new file mode 100644
index 0000000..ba20edc
--- /dev/null
+++ b/src/pdclib/functions/string/strncat.c
@@ -0,0 +1,60 @@
+/* strncat( char *, const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strncat( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n )
+{
+ char * rc = s1;
+ while ( *s1 )
+ {
+ ++s1;
+ }
+ while ( n && ( *s1++ = *s2++ ) )
+ {
+ --n;
+ }
+ if ( n == 0 )
+ {
+ *s1 = '\0';
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xx\0xxxxxx";
+ TESTCASE( strncat( s, abcde, 10 ) == s );
+ TESTCASE( s[2] == 'a' );
+ TESTCASE( s[6] == 'e' );
+ TESTCASE( s[7] == '\0' );
+ TESTCASE( s[8] == 'x' );
+ s[0] = '\0';
+ TESTCASE( strncat( s, abcdx, 10 ) == s );
+ TESTCASE( s[4] == 'x' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( strncat( s, "\0", 10 ) == s );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( s[6] == 'e' );
+ TESTCASE( strncat( s, abcde, 0 ) == s );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( s[6] == 'e' );
+ TESTCASE( strncat( s, abcde, 3 ) == s );
+ TESTCASE( s[5] == 'a' );
+ TESTCASE( s[7] == 'c' );
+ TESTCASE( s[8] == '\0' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strncmp.c b/src/pdclib/functions/string/strncmp.c
new file mode 100644
index 0000000..4bb3592
--- /dev/null
+++ b/src/pdclib/functions/string/strncmp.c
@@ -0,0 +1,54 @@
+/* strncmp( const char *, const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+int strncmp( const char * s1, const char * s2, size_t n )
+{
+ while ( n && *s1 && ( *s1 == *s2 ) )
+ {
+ ++s1;
+ ++s2;
+ --n;
+ }
+ if ( n == 0 )
+ {
+ return 0;
+ }
+ else
+ {
+ return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char cmpabcde[] = "abcde\0f";
+ char cmpabcd_[] = "abcde\xfc";
+ char empty[] = "";
+ char x[] = "x";
+ TESTCASE( strncmp( abcde, cmpabcde, 5 ) == 0 );
+ TESTCASE( strncmp( abcde, cmpabcde, 10 ) == 0 );
+ TESTCASE( strncmp( abcde, abcdx, 5 ) < 0 );
+ TESTCASE( strncmp( abcdx, abcde, 5 ) > 0 );
+ TESTCASE( strncmp( empty, abcde, 5 ) < 0 );
+ TESTCASE( strncmp( abcde, empty, 5 ) > 0 );
+ TESTCASE( strncmp( abcde, abcdx, 4 ) == 0 );
+ TESTCASE( strncmp( abcde, x, 0 ) == 0 );
+ TESTCASE( strncmp( abcde, x, 1 ) < 0 );
+ TESTCASE( strncmp( abcde, cmpabcd_, 10 ) < 0 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strncpy.c b/src/pdclib/functions/string/strncpy.c
new file mode 100644
index 0000000..0627c41
--- /dev/null
+++ b/src/pdclib/functions/string/strncpy.c
@@ -0,0 +1,56 @@
+/* strncpy( char *, const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strncpy( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n )
+{
+ char * rc = s1;
+ while ( n && ( *s1++ = *s2++ ) )
+ {
+ /* Cannot do "n--" in the conditional as size_t is unsigned and we have
+ to check it again for >0 in the next loop below, so we must not risk
+ underflow.
+ */
+ --n;
+ }
+ /* Checking against 1 as we missed the last --n in the loop above. */
+ while ( n-- > 1 )
+ {
+ *s1++ = '\0';
+ }
+ return rc;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxxxx";
+ TESTCASE( strncpy( s, "", 1 ) == s );
+ TESTCASE( s[0] == '\0' );
+ TESTCASE( s[1] == 'x' );
+ TESTCASE( strncpy( s, abcde, 6 ) == s );
+ TESTCASE( s[0] == 'a' );
+ TESTCASE( s[4] == 'e' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( s[6] == 'x' );
+ TESTCASE( strncpy( s, abcde, 7 ) == s );
+ TESTCASE( s[6] == '\0' );
+ TESTCASE( strncpy( s, "xxxx", 3 ) == s );
+ TESTCASE( s[0] == 'x' );
+ TESTCASE( s[2] == 'x' );
+ TESTCASE( s[3] == 'd' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strpbrk.c b/src/pdclib/functions/string/strpbrk.c
new file mode 100644
index 0000000..e95f0c1
--- /dev/null
+++ b/src/pdclib/functions/string/strpbrk.c
@@ -0,0 +1,49 @@
+/* strpbrk( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strpbrk( const char * s1, const char * s2 )
+{
+ const char * p1 = s1;
+ const char * p2;
+ while ( *p1 )
+ {
+ p2 = s2;
+ while ( *p2 )
+ {
+ if ( *p1 == *p2++ )
+ {
+ return (char *) p1;
+ }
+ }
+ ++p1;
+ }
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( strpbrk( abcde, "x" ) == NULL );
+ TESTCASE( strpbrk( abcde, "xyz" ) == NULL );
+ TESTCASE( strpbrk( abcdx, "x" ) == &abcdx[4] );
+ TESTCASE( strpbrk( abcdx, "xyz" ) == &abcdx[4] );
+ TESTCASE( strpbrk( abcdx, "zyx" ) == &abcdx[4] );
+ TESTCASE( strpbrk( abcde, "a" ) == &abcde[0] );
+ TESTCASE( strpbrk( abcde, "abc" ) == &abcde[0] );
+ TESTCASE( strpbrk( abcde, "cba" ) == &abcde[0] );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strrchr.c b/src/pdclib/functions/string/strrchr.c
new file mode 100644
index 0000000..c2369fa
--- /dev/null
+++ b/src/pdclib/functions/string/strrchr.c
@@ -0,0 +1,41 @@
+/* strrchr( const 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 <string.h>
+
+#ifndef REGTEST
+
+char * strrchr( const char * s, int c )
+{
+ size_t i = 0;
+ while ( s[i++] );
+ do
+ {
+ if ( s[--i] == (char) c )
+ {
+ return (char *) s + i;
+ }
+ } while ( i );
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char abccd[] = "abccd";
+ TESTCASE( strrchr( abcde, '\0' ) == &abcde[5] );
+ TESTCASE( strrchr( abcde, 'e' ) == &abcde[4] );
+ TESTCASE( strrchr( abcde, 'a' ) == &abcde[0] );
+ TESTCASE( strrchr( abccd, 'c' ) == &abccd[3] );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strspn.c b/src/pdclib/functions/string/strspn.c
new file mode 100644
index 0000000..7b55b08
--- /dev/null
+++ b/src/pdclib/functions/string/strspn.c
@@ -0,0 +1,49 @@
+/* strspn( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+size_t strspn( const char * s1, const char * s2 )
+{
+ size_t len = 0;
+ const char * p;
+ while ( s1[ len ] )
+ {
+ p = s2;
+ while ( *p )
+ {
+ if ( s1[len] == *p )
+ {
+ break;
+ }
+ ++p;
+ }
+ if ( ! *p )
+ {
+ return len;
+ }
+ ++len;
+ }
+ return len;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( strspn( abcde, "abc" ) == 3 );
+ TESTCASE( strspn( abcde, "b" ) == 0 );
+ TESTCASE( strspn( abcde, abcde ) == 5 );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strstr.c b/src/pdclib/functions/string/strstr.c
new file mode 100644
index 0000000..aee282f
--- /dev/null
+++ b/src/pdclib/functions/string/strstr.c
@@ -0,0 +1,51 @@
+/* strstr( const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strstr( const char * s1, const char * s2 )
+{
+ const char * p1 = s1;
+ const char * p2;
+ while ( *s1 )
+ {
+ p2 = s2;
+ while ( *p2 && ( *p1 == *p2 ) )
+ {
+ ++p1;
+ ++p2;
+ }
+ if ( ! *p2 )
+ {
+ return (char *) s1;
+ }
+ ++s1;
+ p1 = s1;
+ }
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "abcabcabcdabcde";
+ TESTCASE( strstr( s, "x" ) == NULL );
+ TESTCASE( strstr( s, "xyz" ) == NULL );
+ TESTCASE( strstr( s, "a" ) == &s[0] );
+ TESTCASE( strstr( s, "abc" ) == &s[0] );
+ TESTCASE( strstr( s, "abcd" ) == &s[6] );
+ TESTCASE( strstr( s, "abcde" ) == &s[10] );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strtok.c b/src/pdclib/functions/string/strtok.c
new file mode 100644
index 0000000..69c2d68
--- /dev/null
+++ b/src/pdclib/functions/string/strtok.c
@@ -0,0 +1,107 @@
+/* strtok( char *, 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 <string.h>
+
+#ifndef REGTEST
+
+char * strtok( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2 )
+{
+ static char * tmp = NULL;
+ const char * p = s2;
+
+ if ( s1 != NULL )
+ {
+ /* new string */
+ tmp = s1;
+ }
+ else
+ {
+ /* old string continued */
+ if ( tmp == NULL )
+ {
+ /* No old string, no new string, nothing to do */
+ return NULL;
+ }
+ s1 = tmp;
+ }
+
+ /* skipping leading s2 characters */
+ while ( *p && *s1 )
+ {
+ if ( *s1 == *p )
+ {
+ /* found seperator; skip and start over */
+ ++s1;
+ p = s2;
+ continue;
+ }
+ ++p;
+ }
+
+ if ( ! *s1 )
+ {
+ /* no more to parse */
+ return ( tmp = NULL );
+ }
+
+ /* skipping non-s2 characters */
+ tmp = s1;
+ while ( *tmp )
+ {
+ p = s2;
+ while ( *p )
+ {
+ if ( *tmp == *p++ )
+ {
+ /* found seperator; overwrite with '\0', position tmp, return */
+ *tmp++ = '\0';
+ return s1;
+ }
+ }
+ ++tmp;
+ }
+
+ /* parsed to end of string */
+ tmp = NULL;
+ return s1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "_a_bc__d_";
+ TESTCASE( strtok( s, "_" ) == &s[1] );
+ TESTCASE( s[1] == 'a' );
+ TESTCASE( s[2] == '\0' );
+ TESTCASE( strtok( NULL, "_" ) == &s[3] );
+ TESTCASE( s[3] == 'b' );
+ TESTCASE( s[4] == 'c' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( strtok( NULL, "_" ) == &s[7] );
+ TESTCASE( s[6] == '_' );
+ TESTCASE( s[7] == 'd' );
+ TESTCASE( s[8] == '\0' );
+ TESTCASE( strtok( NULL, "_" ) == NULL );
+ strcpy( s, "ab_cd" );
+ TESTCASE( strtok( s, "_" ) == &s[0] );
+ TESTCASE( s[0] == 'a' );
+ TESTCASE( s[1] == 'b' );
+ TESTCASE( s[2] == '\0' );
+ TESTCASE( strtok( NULL, "_" ) == &s[3] );
+ TESTCASE( s[3] == 'c' );
+ TESTCASE( s[4] == 'd' );
+ TESTCASE( s[5] == '\0' );
+ TESTCASE( strtok( NULL, "_" ) == NULL );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/string/strxfrm.c b/src/pdclib/functions/string/strxfrm.c
new file mode 100644
index 0000000..e08dba2
--- /dev/null
+++ b/src/pdclib/functions/string/strxfrm.c
@@ -0,0 +1,50 @@
+/* strxfrm( char *, const char *, 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 <string.h>
+
+#ifndef REGTEST
+
+#include <locale.h>
+
+size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n )
+{
+ size_t len = strlen( s2 );
+ if ( len < n )
+ {
+ /* Cannot use strncpy() here as the filling of s1 with '\0' is not part
+ of the spec.
+ */
+ /* FIXME: The code below became invalid when we started doing *real* locales... */
+ /*while ( n-- && ( *s1++ = _PDCLIB_lc_collate[(unsigned char)*s2++].collation ) );*/
+ while ( n-- && ( *s1++ = (unsigned char)*s2++ ) );
+ }
+ return len;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ char s[] = "xxxxxxxxxxx";
+ TESTCASE( strxfrm( NULL, "123456789012", 0 ) == 12 );
+ TESTCASE( strxfrm( s, "123456789012", 12 ) == 12 );
+ /*
+ The following test case is true in *this* implementation, but doesn't have to.
+ TESTCASE( s[0] == 'x' );
+ */
+ TESTCASE( strxfrm( s, "1234567890", 11 ) == 10 );
+ TESTCASE( s[0] == '1' );
+ TESTCASE( s[9] == '0' );
+ TESTCASE( s[10] == '\0' );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/asctime.c b/src/pdclib/functions/time/asctime.c
new file mode 100644
index 0000000..8c9db60
--- /dev/null
+++ b/src/pdclib/functions/time/asctime.c
@@ -0,0 +1,28 @@
+/* asctime( const struct tm * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+char * asctime( const struct tm * timeptr )
+{
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/ctime.c b/src/pdclib/functions/time/ctime.c
new file mode 100644
index 0000000..d021a7d
--- /dev/null
+++ b/src/pdclib/functions/time/ctime.c
@@ -0,0 +1,28 @@
+/* ctime( const time_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+char * ctime( const time_t * timer )
+{
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/difftime.c b/src/pdclib/functions/time/difftime.c
new file mode 100644
index 0000000..a6d94f8
--- /dev/null
+++ b/src/pdclib/functions/time/difftime.c
@@ -0,0 +1,70 @@
+/* difftime( time_t, time_t )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+double difftime( time_t time1, time_t time0 )
+{
+ /* If we want to avoid rounding errors and overflows, we need to be
+ careful with the exact type of time_t being unknown to us.
+ The code below is based on tzcode's difftime.c, which is in the
+ public domain, so clarified as of 1996-06-05 by Arthur David Olson.
+ */
+
+ /* If double is large enough, simply covert and substract
+ (assuming that the larger type has more precision).
+ */
+ if ( sizeof( time_t ) < sizeof( double ) )
+ {
+ return (double)time1 - (double)time0;
+ }
+
+ /* The difference of two unsigned values cannot overflow if the
+ minuend is greater or equal to the subtrahend.
+ */
+ if ( ! _PDCLIB_TYPE_SIGNED( time_t ) )
+ {
+ return ( time1 >= time0 ) ? (double)( time1 - time0 ) : -(double)( time0 - time1 );
+ }
+
+ /* Use uintmax_t if wide enough. */
+ if ( sizeof( time_t ) <= sizeof( _PDCLIB_uintmax_t ) )
+ {
+ _PDCLIB_uintmax_t t1 = time1, t0 = time0;
+ return ( time1 >= time0 ) ? t1 - t0 : -(double)( t0 - t1 );
+ }
+
+ /* If both times have the same sign, their difference cannot overflow. */
+ if ( ( time1 < 0 ) == ( time0 < 0 ) )
+ {
+ return time1 - time0;
+ }
+
+ /* The times have opposite signs, and uintmax_t is too narrow.
+ This suffers from double rounding; attempt to lessen that
+ by using long double temporaries.
+ */
+ {
+ long double t1 = time1, t0 = time0;
+ return t1 - t0;
+ }
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/gmtime.c b/src/pdclib/functions/time/gmtime.c
new file mode 100644
index 0000000..3bd001c
--- /dev/null
+++ b/src/pdclib/functions/time/gmtime.c
@@ -0,0 +1,28 @@
+/* gmtime( const time_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+struct tm * gmtime( const time_t * timer )
+{
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/localtime.c b/src/pdclib/functions/time/localtime.c
new file mode 100644
index 0000000..91c0618
--- /dev/null
+++ b/src/pdclib/functions/time/localtime.c
@@ -0,0 +1,28 @@
+/* localtime( const time_t * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+struct tm * localtime( const time_t * timer )
+{
+ return NULL;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/mktime.c b/src/pdclib/functions/time/mktime.c
new file mode 100644
index 0000000..0b8596a
--- /dev/null
+++ b/src/pdclib/functions/time/mktime.c
@@ -0,0 +1,28 @@
+/* mktime( struct tm * )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+
+#ifndef REGTEST
+
+time_t mktime( struct tm * timeptr )
+{
+ return -1;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+int main( void )
+{
+ TESTCASE( NO_TESTDRIVER );
+ return TEST_RESULTS;
+}
+
+#endif
diff --git a/src/pdclib/functions/time/strftime.c b/src/pdclib/functions/time/strftime.c
new file mode 100644
index 0000000..81ae13d
--- /dev/null
+++ b/src/pdclib/functions/time/strftime.c
@@ -0,0 +1,1719 @@
+/* strftime( char * restrict, size_t, const char * restrict, const struct tm * restrict )
+
+ This file is part of the Public Domain C Library (PDCLib).
+ Permission is granted to use, modify, and / or redistribute at will.
+*/
+
+#include <time.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+#include <assert.h>
+
+#ifndef REGTEST
+
+/* TODO: Alternative representations / numerals not supported. Multibyte support missing. */
+
+/* This implementation's code is highly repetitive, but I did not really
+ care for putting it into a number of macros / helper functions.
+*/
+
+enum wstart_t
+{
+ E_SUNDAY = 0,
+ E_MONDAY = 1,
+ E_ISO_WEEK,
+ E_ISO_YEAR
+};
+
+#include <stdio.h>
+
+static int week_calc( const struct tm * timeptr, int wtype )
+{
+ int wday;
+ int bias;
+ int week;
+
+ if ( wtype <= E_MONDAY )
+ {
+ /* Simple -- first week starting with E_SUNDAY / E_MONDAY,
+ days before that are week 0.
+ */
+ div_t weeks = div( timeptr->tm_yday, 7 );
+ wday = ( timeptr->tm_wday + 7 - wtype ) % 7;
+ if ( weeks.rem >= wday )
+ {
+ ++weeks.quot;
+ }
+ return weeks.quot;
+ }
+
+ /* calculating ISO week; relies on Sunday == 7 */
+ wday = timeptr->tm_wday;
+ if ( wday == 0 )
+ {
+ wday = 7;
+ }
+ /* https://en.wikipedia.org/wiki/ISO_week_date */
+ week = ( timeptr->tm_yday - wday + 11 ) / 7;
+ if ( week == 53 )
+ {
+ /* date *may* belong to the *next* year, if:
+ * it is 31.12. and Monday - Wednesday
+ * it is 30.12. and Monday - Tuesday
+ * it is 29.12. and Monday
+ We can safely assume December...
+ */
+ if ( ( timeptr->tm_yday - wday - _PDCLIB_is_leap( timeptr->tm_year ) ) > 360 )
+ {
+ week = 1;
+ }
+ }
+ else if ( week == 0 )
+ {
+ /* date *does* belong to *previous* year,
+ i.e. has week 52 *unless*...
+ * current year started on a Friday, or
+ * previous year is leap and this year
+ started on a Saturday.
+ */
+ int firstday = timeptr->tm_wday - ( timeptr->tm_yday % 7 );
+ if ( firstday < 0 )
+ {
+ firstday += 7;
+ }
+ if ( ( firstday == 5 ) || ( _PDCLIB_is_leap( timeptr->tm_year - 1 ) && firstday == 6 ) )
+ {
+ week = 53;
+ }
+ else
+ {
+ week = 52;
+ }
+ }
+ if ( wtype == E_ISO_WEEK )
+ {
+ return week;
+ }
+
+ /* E_ISO_YEAR -- determine the "week-based year" */
+ bias = 0;
+ if ( week >= 52 && timeptr->tm_mon == 0 )
+ {
+ --bias;
+ }
+ else if ( week == 1 && timeptr->tm_mon == 11 )
+ {
+ ++bias;
+ }
+ return timeptr->tm_year + 1900 + bias;
+}
+
+/* Assuming presence of s, rc, maxsize.
+ Checks index for valid range, target buffer for sufficient remaining
+ capacity, and copies the locale-specific string (or "?" if index out
+ of range). Returns with zero if buffer capacity insufficient.
+*/
+#define SPRINTSTR( array, index, max ) \
+ { \
+ int ind = (index); \
+ const char * str = "?"; \
+ size_t len; \
+ if ( ind >= 0 && ind <= max ) \
+ { \
+ str = array[ ind ]; \
+ } \
+ len = strlen( str ); \
+ if ( rc < ( maxsize - len ) ) \
+ { \
+ strcpy( s + rc, str ); \
+ rc += len; \
+ } \
+ else \
+ { \
+ return 0; \
+ } \
+ }
+
+#define SPRINTREC( format ) \
+ { \
+ size_t count = strftime( s + rc, maxsize - rc, format, timeptr ); \
+ if ( count == 0 ) \
+ { \
+ return 0; \
+ } \
+ else \
+ { \
+ rc += count; \
+ } \
+ }
+
+size_t strftime( char * _PDCLIB_restrict s, size_t maxsize, const char * _PDCLIB_restrict format, const struct tm * _PDCLIB_restrict timeptr )
+{
+ size_t rc = 0;
+
+ while ( rc < maxsize )
+ {
+ if ( *format != '%' )
+ {
+ if ( ( s[rc] = *format++ ) == '\0' )
+ {
+ return rc;
+ }
+ else
+ {
+ ++rc;
+ }
+ }
+ else
+ {
+ /* char flag = 0; */
+ switch ( *++format )
+ {
+ case 'E':
+ case 'O':
+ /* flag = *format++; */
+ break;
+ default:
+ /* EMPTY */
+ break;
+ }
+ switch( *format++ )
+ {
+ case 'a':
+ {
+ /* tm_wday abbreviated */
+ SPRINTSTR( _PDCLIB_lc_time.day_name_abbr, timeptr->tm_wday, 6 );
+ break;
+ }
+ case 'A':
+ {
+ /* tm_wday full */
+ SPRINTSTR( _PDCLIB_lc_time.day_name_full, timeptr->tm_wday, 6 );
+ break;
+ }
+ case 'b':
+ case 'h':
+ {
+ /* tm_mon abbreviated */
+ SPRINTSTR( _PDCLIB_lc_time.month_name_abbr, timeptr->tm_mon, 11 );
+ break;
+ }
+ case 'B':
+ {
+ /* tm_mon full */
+ SPRINTSTR( _PDCLIB_lc_time.month_name_full, timeptr->tm_mon, 11 );
+ break;
+ }
+ case 'c':
+ {
+ /* locale's date / time representation, %a %b %e %T %Y for C locale */
+ /* 'E' for locale's alternative representation */
+ SPRINTREC( _PDCLIB_lc_time.date_time_format );
+ break;
+ }
+ case 'C':
+ {
+ /* tm_year divided by 100, truncated to decimal (00-99) */
+ /* 'E' for base year (period) in locale's alternative representation */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t period = div( ( ( timeptr->tm_year + 1900 ) / 100 ), 10 );
+ s[rc++] = '0' + period.quot;
+ s[rc++] = '0' + period.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'd':
+ {
+ /* tm_mday as decimal (01-31) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t day = div( timeptr->tm_mday, 10 );
+ s[rc++] = '0' + day.quot;
+ s[rc++] = '0' + day.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'D':
+ {
+ /* %m/%d/%y */
+ SPRINTREC( "%m/%d/%y" );
+ break;
+ }
+ case 'e':
+ {
+ /* tm_mday as decimal ( 1-31) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t day = div( timeptr->tm_mday, 10 );
+ s[rc++] = ( day.quot > 0 ) ? '0' + day.quot : ' ';
+ s[rc++] = '0' + day.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'F':
+ {
+ /* %Y-%m-%d */
+ SPRINTREC( "%Y-%m-%d" );
+ break;
+ }
+ case 'g':
+ {
+ /* last 2 digits of the week-based year as decimal (00-99) */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t year = div( week_calc( timeptr, E_ISO_YEAR ) % 100, 10 );
+ s[rc++] = '0' + year.quot;
+ s[rc++] = '0' + year.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'G':
+ {
+ /* week-based year as decimal (e.g. 1997) */
+ if ( rc < ( maxsize - 4 ) )
+ {
+ int year = week_calc( timeptr, E_ISO_YEAR );
+ int i;
+ for ( i = 3; i >= 0; --i )
+ {
+ div_t digit = div( year, 10 );
+ s[ rc + i ] = '0' + digit.rem;
+ year = digit.quot;
+ }
+
+ rc += 4;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'H':
+ {
+ /* tm_hour as 24h decimal (00-23) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t hour = div( timeptr->tm_hour, 10 );
+ s[rc++] = '0' + hour.quot;
+ s[rc++] = '0' + hour.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'I':
+ {
+ /* tm_hour as 12h decimal (01-12) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t hour = div( ( timeptr->tm_hour + 11 ) % 12 + 1, 10 );
+ s[rc++] = '0' + hour.quot;
+ s[rc++] = '0' + hour.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'j':
+ {
+ /* tm_yday as decimal (001-366) */
+ if ( rc < ( maxsize - 3 ) )
+ {
+ div_t yday = div( timeptr->tm_yday + 1, 100 );
+ s[rc++] = '0' + yday.quot;
+ s[rc++] = '0' + yday.rem / 10;
+ s[rc++] = '0' + yday.rem % 10;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'm':
+ {
+ /* tm_mon as decimal (01-12) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t mon = div( timeptr->tm_mon + 1, 10 );
+ s[rc++] = '0' + mon.quot;
+ s[rc++] = '0' + mon.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'M':
+ {
+ /* tm_min as decimal (00-59) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t min = div( timeptr->tm_min, 10 );
+ s[rc++] = '0' + min.quot;
+ s[rc++] = '0' + min.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'n':
+ {
+ /* newline */
+ s[rc++] = '\n';
+ break;
+ }
+ case 'p':
+ {
+ /* tm_hour locale's AM/PM designations */
+ SPRINTSTR( _PDCLIB_lc_time.am_pm, timeptr->tm_hour > 11, 1 );
+ break;
+ }
+ case 'r':
+ {
+ /* tm_hour / tm_min / tm_sec as locale's 12-hour clock time, %I:%M:%S %p for C locale */
+ SPRINTREC( _PDCLIB_lc_time.time_format_12h );
+ break;
+ }
+ case 'R':
+ {
+ /* %H:%M */
+ SPRINTREC( "%H:%M" );
+ break;
+ }
+ case 'S':
+ {
+ /* tm_sec as decimal (00-60) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t sec = div( timeptr->tm_sec, 10 );
+ s[rc++] = '0' + sec.quot;
+ s[rc++] = '0' + sec.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 't':
+ {
+ /* tabulator */
+ s[rc++] = '\t';
+ break;
+ }
+ case 'T':
+ {
+ /* %H:%M:%S */
+ SPRINTREC( "%H:%M:%S" );
+ break;
+ }
+ case 'u':
+ {
+ /* tm_wday as decimal (1-7) with Monday == 1 */
+ /* 'O' for locale's alternative numeric symbols */
+ s[rc++] = ( timeptr->tm_wday == 0 ) ? '7' : '0' + timeptr->tm_wday;
+ break;
+ }
+ case 'U':
+ {
+ /* week number of the year (first Sunday as the first day of week 1) as decimal (00-53) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t week = div( week_calc( timeptr, E_SUNDAY ), 10 );
+ s[rc++] = '0' + week.quot;
+ s[rc++] = '0' + week.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'V':
+ {
+ /* ISO week number as decimal (01-53) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t week = div( week_calc( timeptr, E_ISO_WEEK ), 10 );
+ s[rc++] = '0' + week.quot;
+ s[rc++] = '0' + week.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'w':
+ {
+ /* tm_wday as decimal number (0-6) with Sunday == 0 */
+ /* 'O' for locale's alternative numeric symbols */
+ s[rc++] = '0' + timeptr->tm_wday;
+ break;
+ }
+ case 'W':
+ {
+ /* week number of the year (first Monday as the first day of week 1) as decimal (00-53) */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t week = div( week_calc( timeptr, E_MONDAY ), 10 );
+ s[rc++] = '0' + week.quot;
+ s[rc++] = '0' + week.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'x':
+ {
+ /* locale's date representation, %m/%d/%y for C locale */
+ /* 'E' for locale's alternative representation */
+ SPRINTREC( _PDCLIB_lc_time.date_format );
+ break;
+ }
+ case 'X':
+ {
+ /* locale's time representation, %T for C locale */
+ /* 'E' for locale's alternative representation */
+ SPRINTREC( _PDCLIB_lc_time.time_format );
+ break;
+ }
+ case 'y':
+ {
+ /* last 2 digits of tm_year as decimal (00-99) */
+ /* 'E' for offset from %EC (year only) in locale's alternative representation */
+ /* 'O' for locale's alternative numeric symbols */
+ if ( rc < ( maxsize - 2 ) )
+ {
+ div_t year = div( ( timeptr->tm_year % 100 ), 10 );
+ s[rc++] = '0' + year.quot;
+ s[rc++] = '0' + year.rem;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'Y':
+ {
+ /* tm_year as decimal (e.g. 1997) */
+ /* 'E' for locale's alternative representation */
+ if ( rc < ( maxsize - 4 ) )
+ {
+ int year = timeptr->tm_year + 1900;
+ int i;
+
+ for ( i = 3; i >= 0; --i )
+ {
+ div_t digit = div( year, 10 );
+ s[ rc + i ] = '0' + digit.rem;
+ year = digit.quot;
+ }
+
+ rc += 4;
+ }
+ else
+ {
+ return 0;
+ }
+ break;
+ }
+ case 'z':
+ {
+ /* tm_isdst / UTC offset in ISO8601 format (e.g. -0430 meaning 4 hours 30 minutes behind Greenwich), or no characters */
+ /* TODO: 'z' */
+ break;
+ }
+ case 'Z':
+ {
+ /* tm_isdst / locale's time zone name or abbreviation, or no characters */
+ /* TODO: 'Z' */
+ break;
+ }
+ case '%':
+ {
+ /* '%' character */
+ s[rc++] = '%';
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+#ifdef TEST
+
+#include "_PDCLIB_test.h"
+
+#define MKTIME( tm, sec, min, hour, day, month, year, wday, yday ) tm.tm_sec = sec; tm.tm_min = min; tm.tm_hour = hour; tm.tm_mday = day; tm.tm_mon = month; tm.tm_year = year; tm.tm_wday = wday; tm.tm_yday = yday; tm.tm_isdst = -1;
+
+/* Test data generated by reference mktime() / strftime(), listing:
+ * tm_year
+ * tm_wday
+ * tm_yday
+ * '%U' result
+ * '%V' result
+ * '%W' result
+*/
+int data[1020][6] =
+{
+{ 70, 4, 0, 0, 1, 0 },
+{ 70, 5, 1, 0, 1, 0 },
+{ 70, 6, 2, 0, 1, 0 },
+{ 70, 0, 3, 1, 1, 0 },
+{ 70, 1, 4, 1, 2, 1 },
+{ 70, 2, 5, 1, 2, 1 },
+{ 70, 3, 6, 1, 2, 1 },
+{ 70, 4, 357, 51, 52, 51 },
+{ 70, 5, 358, 51, 52, 51 },
+{ 70, 6, 359, 51, 52, 51 },
+{ 70, 0, 360, 52, 52, 51 },
+{ 70, 1, 361, 52, 53, 52 },
+{ 70, 2, 362, 52, 53, 52 },
+{ 70, 3, 363, 52, 53, 52 },
+{ 70, 4, 364, 52, 53, 52 },
+{ 71, 5, 0, 0, 53, 0 },
+{ 71, 6, 1, 0, 53, 0 },
+{ 71, 0, 2, 1, 53, 0 },
+{ 71, 1, 3, 1, 1, 1 },
+{ 71, 2, 4, 1, 1, 1 },
+{ 71, 3, 5, 1, 1, 1 },
+{ 71, 4, 6, 1, 1, 1 },
+{ 71, 5, 357, 51, 51, 51 },
+{ 71, 6, 358, 51, 51, 51 },
+{ 71, 0, 359, 52, 51, 51 },
+{ 71, 1, 360, 52, 52, 52 },
+{ 71, 2, 361, 52, 52, 52 },
+{ 71, 3, 362, 52, 52, 52 },
+{ 71, 4, 363, 52, 52, 52 },
+{ 71, 5, 364, 52, 52, 52 },
+{ 72, 6, 0, 0, 52, 0 },
+{ 72, 0, 1, 1, 52, 0 },
+{ 72, 1, 2, 1, 1, 1 },
+{ 72, 2, 3, 1, 1, 1 },
+{ 72, 3, 4, 1, 1, 1 },
+{ 72, 4, 5, 1, 1, 1 },
+{ 72, 5, 6, 1, 1, 1 },
+{ 72, 0, 358, 52, 51, 51 },
+{ 72, 1, 359, 52, 52, 52 },
+{ 72, 2, 360, 52, 52, 52 },
+{ 72, 3, 361, 52, 52, 52 },
+{ 72, 4, 362, 52, 52, 52 },
+{ 72, 5, 363, 52, 52, 52 },
+{ 72, 6, 364, 52, 52, 52 },
+{ 72, 0, 365, 53, 52, 52 },
+{ 73, 1, 0, 0, 1, 1 },
+{ 73, 2, 1, 0, 1, 1 },
+{ 73, 3, 2, 0, 1, 1 },
+{ 73, 4, 3, 0, 1, 1 },
+{ 73, 5, 4, 0, 1, 1 },
+{ 73, 6, 5, 0, 1, 1 },
+{ 73, 0, 6, 1, 1, 1 },
+{ 73, 1, 357, 51, 52, 52 },
+{ 73, 2, 358, 51, 52, 52 },
+{ 73, 3, 359, 51, 52, 52 },
+{ 73, 4, 360, 51, 52, 52 },
+{ 73, 5, 361, 51, 52, 52 },
+{ 73, 6, 362, 51, 52, 52 },
+{ 73, 0, 363, 52, 52, 52 },
+{ 73, 1, 364, 52, 1, 53 },
+{ 74, 2, 0, 0, 1, 0 },
+{ 74, 3, 1, 0, 1, 0 },
+{ 74, 4, 2, 0, 1, 0 },
+{ 74, 5, 3, 0, 1, 0 },
+{ 74, 6, 4, 0, 1, 0 },
+{ 74, 0, 5, 1, 1, 0 },
+{ 74, 1, 6, 1, 2, 1 },
+{ 74, 2, 357, 51, 52, 51 },
+{ 74, 3, 358, 51, 52, 51 },
+{ 74, 4, 359, 51, 52, 51 },
+{ 74, 5, 360, 51, 52, 51 },
+{ 74, 6, 361, 51, 52, 51 },
+{ 74, 0, 362, 52, 52, 51 },
+{ 74, 1, 363, 52, 1, 52 },
+{ 74, 2, 364, 52, 1, 52 },
+{ 75, 3, 0, 0, 1, 0 },
+{ 75, 4, 1, 0, 1, 0 },
+{ 75, 5, 2, 0, 1, 0 },
+{ 75, 6, 3, 0, 1, 0 },
+{ 75, 0, 4, 1, 1, 0 },
+{ 75, 1, 5, 1, 2, 1 },
+{ 75, 2, 6, 1, 2, 1 },
+{ 75, 3, 357, 51, 52, 51 },
+{ 75, 4, 358, 51, 52, 51 },
+{ 75, 5, 359, 51, 52, 51 },
+{ 75, 6, 360, 51, 52, 51 },
+{ 75, 0, 361, 52, 52, 51 },
+{ 75, 1, 362, 52, 1, 52 },
+{ 75, 2, 363, 52, 1, 52 },
+{ 75, 3, 364, 52, 1, 52 },
+{ 76, 4, 0, 0, 1, 0 },
+{ 76, 5, 1, 0, 1, 0 },
+{ 76, 6, 2, 0, 1, 0 },
+{ 76, 0, 3, 1, 1, 0 },
+{ 76, 1, 4, 1, 2, 1 },
+{ 76, 2, 5, 1, 2, 1 },
+{ 76, 3, 6, 1, 2, 1 },
+{ 76, 5, 358, 51, 52, 51 },
+{ 76, 6, 359, 51, 52, 51 },
+{ 76, 0, 360, 52, 52, 51 },
+{ 76, 1, 361, 52, 53, 52 },
+{ 76, 2, 362, 52, 53, 52 },
+{ 76, 3, 363, 52, 53, 52 },
+{ 76, 4, 364, 52, 53, 52 },
+{ 76, 5, 365, 52, 53, 52 },
+{ 77, 6, 0, 0, 53, 0 },
+{ 77, 0, 1, 1, 53, 0 },
+{ 77, 1, 2, 1, 1, 1 },
+{ 77, 2, 3, 1, 1, 1 },
+{ 77, 3, 4, 1, 1, 1 },
+{ 77, 4, 5, 1, 1, 1 },
+{ 77, 5, 6, 1, 1, 1 },
+{ 77, 6, 357, 51, 51, 51 },
+{ 77, 0, 358, 52, 51, 51 },
+{ 77, 1, 359, 52, 52, 52 },
+{ 77, 2, 360, 52, 52, 52 },
+{ 77, 3, 361, 52, 52, 52 },
+{ 77, 4, 362, 52, 52, 52 },
+{ 77, 5, 363, 52, 52, 52 },
+{ 77, 6, 364, 52, 52, 52 },
+{ 78, 0, 0, 1, 52, 0 },
+{ 78, 1, 1, 1, 1, 1 },
+{ 78, 2, 2, 1, 1, 1 },
+{ 78, 3, 3, 1, 1, 1 },
+{ 78, 4, 4, 1, 1, 1 },
+{ 78, 5, 5, 1, 1, 1 },
+{ 78, 6, 6, 1, 1, 1 },
+{ 78, 0, 357, 52, 51, 51 },
+{ 78, 1, 358, 52, 52, 52 },
+{ 78, 2, 359, 52, 52, 52 },
+{ 78, 3, 360, 52, 52, 52 },
+{ 78, 4, 361, 52, 52, 52 },
+{ 78, 5, 362, 52, 52, 52 },
+{ 78, 6, 363, 52, 52, 52 },
+{ 78, 0, 364, 53, 52, 52 },
+{ 79, 1, 0, 0, 1, 1 },
+{ 79, 2, 1, 0, 1, 1 },
+{ 79, 3, 2, 0, 1, 1 },
+{ 79, 4, 3, 0, 1, 1 },
+{ 79, 5, 4, 0, 1, 1 },
+{ 79, 6, 5, 0, 1, 1 },
+{ 79, 0, 6, 1, 1, 1 },
+{ 79, 1, 357, 51, 52, 52 },
+{ 79, 2, 358, 51, 52, 52 },
+{ 79, 3, 359, 51, 52, 52 },
+{ 79, 4, 360, 51, 52, 52 },
+{ 79, 5, 361, 51, 52, 52 },
+{ 79, 6, 362, 51, 52, 52 },
+{ 79, 0, 363, 52, 52, 52 },
+{ 79, 1, 364, 52, 1, 53 },
+{ 80, 2, 0, 0, 1, 0 },
+{ 80, 3, 1, 0, 1, 0 },
+{ 80, 4, 2, 0, 1, 0 },
+{ 80, 5, 3, 0, 1, 0 },
+{ 80, 6, 4, 0, 1, 0 },
+{ 80, 0, 5, 1, 1, 0 },
+{ 80, 1, 6, 1, 2, 1 },
+{ 80, 3, 358, 51, 52, 51 },
+{ 80, 4, 359, 51, 52, 51 },
+{ 80, 5, 360, 51, 52, 51 },
+{ 80, 6, 361, 51, 52, 51 },
+{ 80, 0, 362, 52, 52, 51 },
+{ 80, 1, 363, 52, 1, 52 },
+{ 80, 2, 364, 52, 1, 52 },
+{ 80, 3, 365, 52, 1, 52 },
+{ 81, 4, 0, 0, 1, 0 },
+{ 81, 5, 1, 0, 1, 0 },
+{ 81, 6, 2, 0, 1, 0 },
+{ 81, 0, 3, 1, 1, 0 },
+{ 81, 1, 4, 1, 2, 1 },
+{ 81, 2, 5, 1, 2, 1 },
+{ 81, 3, 6, 1, 2, 1 },
+{ 81, 4, 357, 51, 52, 51 },
+{ 81, 5, 358, 51, 52, 51 },
+{ 81, 6, 359, 51, 52, 51 },
+{ 81, 0, 360, 52, 52, 51 },
+{ 81, 1, 361, 52, 53, 52 },
+{ 81, 2, 362, 52, 53, 52 },
+{ 81, 3, 363, 52, 53, 52 },
+{ 81, 4, 364, 52, 53, 52 },
+{ 82, 5, 0, 0, 53, 0 },
+{ 82, 6, 1, 0, 53, 0 },
+{ 82, 0, 2, 1, 53, 0 },
+{ 82, 1, 3, 1, 1, 1 },
+{ 82, 2, 4, 1, 1, 1 },
+{ 82, 3, 5, 1, 1, 1 },
+{ 82, 4, 6, 1, 1, 1 },
+{ 82, 5, 357, 51, 51, 51 },
+{ 82, 6, 358, 51, 51, 51 },
+{ 82, 0, 359, 52, 51, 51 },
+{ 82, 1, 360, 52, 52, 52 },
+{ 82, 2, 361, 52, 52, 52 },
+{ 82, 3, 362, 52, 52, 52 },
+{ 82, 4, 363, 52, 52, 52 },
+{ 82, 5, 364, 52, 52, 52 },
+{ 83, 6, 0, 0, 52, 0 },
+{ 83, 0, 1, 1, 52, 0 },
+{ 83, 1, 2, 1, 1, 1 },
+{ 83, 2, 3, 1, 1, 1 },
+{ 83, 3, 4, 1, 1, 1 },
+{ 83, 4, 5, 1, 1, 1 },
+{ 83, 5, 6, 1, 1, 1 },
+{ 83, 6, 357, 51, 51, 51 },
+{ 83, 0, 358, 52, 51, 51 },
+{ 83, 1, 359, 52, 52, 52 },
+{ 83, 2, 360, 52, 52, 52 },
+{ 83, 3, 361, 52, 52, 52 },
+{ 83, 4, 362, 52, 52, 52 },
+{ 83, 5, 363, 52, 52, 52 },
+{ 83, 6, 364, 52, 52, 52 },
+{ 84, 0, 0, 1, 52, 0 },
+{ 84, 1, 1, 1, 1, 1 },
+{ 84, 2, 2, 1, 1, 1 },
+{ 84, 3, 3, 1, 1, 1 },
+{ 84, 4, 4, 1, 1, 1 },
+{ 84, 5, 5, 1, 1, 1 },
+{ 84, 6, 6, 1, 1, 1 },
+{ 84, 1, 358, 52, 52, 52 },
+{ 84, 2, 359, 52, 52, 52 },
+{ 84, 3, 360, 52, 52, 52 },
+{ 84, 4, 361, 52, 52, 52 },
+{ 84, 5, 362, 52, 52, 52 },
+{ 84, 6, 363, 52, 52, 52 },
+{ 84, 0, 364, 53, 52, 52 },
+{ 84, 1, 365, 53, 1, 53 },
+{ 85, 2, 0, 0, 1, 0 },
+{ 85, 3, 1, 0, 1, 0 },
+{ 85, 4, 2, 0, 1, 0 },
+{ 85, 5, 3, 0, 1, 0 },
+{ 85, 6, 4, 0, 1, 0 },
+{ 85, 0, 5, 1, 1, 0 },
+{ 85, 1, 6, 1, 2, 1 },
+{ 85, 2, 357, 51, 52, 51 },
+{ 85, 3, 358, 51, 52, 51 },
+{ 85, 4, 359, 51, 52, 51 },
+{ 85, 5, 360, 51, 52, 51 },
+{ 85, 6, 361, 51, 52, 51 },
+{ 85, 0, 362, 52, 52, 51 },
+{ 85, 1, 363, 52, 1, 52 },
+{ 85, 2, 364, 52, 1, 52 },
+{ 86, 3, 0, 0, 1, 0 },
+{ 86, 4, 1, 0, 1, 0 },
+{ 86, 5, 2, 0, 1, 0 },
+{ 86, 6, 3, 0, 1, 0 },
+{ 86, 0, 4, 1, 1, 0 },
+{ 86, 1, 5, 1, 2, 1 },
+{ 86, 2, 6, 1, 2, 1 },
+{ 86, 3, 357, 51, 52, 51 },
+{ 86, 4, 358, 51, 52, 51 },
+{ 86, 5, 359, 51, 52, 51 },
+{ 86, 6, 360, 51, 52, 51 },
+{ 86, 0, 361, 52, 52, 51 },
+{ 86, 1, 362, 52, 1, 52 },
+{ 86, 2, 363, 52, 1, 52 },
+{ 86, 3, 364, 52, 1, 52 },
+{ 87, 4, 0, 0, 1, 0 },
+{ 87, 5, 1, 0, 1, 0 },
+{ 87, 6, 2, 0, 1, 0 },
+{ 87, 0, 3, 1, 1, 0 },
+{ 87, 1, 4, 1, 2, 1 },
+{ 87, 2, 5, 1, 2, 1 },
+{ 87, 3, 6, 1, 2, 1 },
+{ 87, 4, 357, 51, 52, 51 },
+{ 87, 5, 358, 51, 52, 51 },
+{ 87, 6, 359, 51, 52, 51 },
+{ 87, 0, 360, 52, 52, 51 },
+{ 87, 1, 361, 52, 53, 52 },
+{ 87, 2, 362, 52, 53, 52 },
+{ 87, 3, 363, 52, 53, 52 },
+{ 87, 4, 364, 52, 53, 52 },
+{ 88, 5, 0, 0, 53, 0 },
+{ 88, 6, 1, 0, 53, 0 },
+{ 88, 0, 2, 1, 53, 0 },
+{ 88, 1, 3, 1, 1, 1 },
+{ 88, 2, 4, 1, 1, 1 },
+{ 88, 3, 5, 1, 1, 1 },
+{ 88, 4, 6, 1, 1, 1 },
+{ 88, 6, 358, 51, 51, 51 },
+{ 88, 0, 359, 52, 51, 51 },
+{ 88, 1, 360, 52, 52, 52 },
+{ 88, 2, 361, 52, 52, 52 },
+{ 88, 3, 362, 52, 52, 52 },
+{ 88, 4, 363, 52, 52, 52 },
+{ 88, 5, 364, 52, 52, 52 },
+{ 88, 6, 365, 52, 52, 52 },
+{ 89, 0, 0, 1, 52, 0 },
+{ 89, 1, 1, 1, 1, 1 },
+{ 89, 2, 2, 1, 1, 1 },
+{ 89, 3, 3, 1, 1, 1 },
+{ 89, 4, 4, 1, 1, 1 },
+{ 89, 5, 5, 1, 1, 1 },
+{ 89, 6, 6, 1, 1, 1 },
+{ 89, 0, 357, 52, 51, 51 },
+{ 89, 1, 358, 52, 52, 52 },
+{ 89, 2, 359, 52, 52, 52 },
+{ 89, 3, 360, 52, 52, 52 },
+{ 89, 4, 361, 52, 52, 52 },
+{ 89, 5, 362, 52, 52, 52 },
+{ 89, 6, 363, 52, 52, 52 },
+{ 89, 0, 364, 53, 52, 52 },
+{ 90, 1, 0, 0, 1, 1 },
+{ 90, 2, 1, 0, 1, 1 },
+{ 90, 3, 2, 0, 1, 1 },
+{ 90, 4, 3, 0, 1, 1 },
+{ 90, 5, 4, 0, 1, 1 },
+{ 90, 6, 5, 0, 1, 1 },
+{ 90, 0, 6, 1, 1, 1 },
+{ 90, 1, 357, 51, 52, 52 },
+{ 90, 2, 358, 51, 52, 52 },
+{ 90, 3, 359, 51, 52, 52 },
+{ 90, 4, 360, 51, 52, 52 },
+{ 90, 5, 361, 51, 52, 52 },
+{ 90, 6, 362, 51, 52, 52 },
+{ 90, 0, 363, 52, 52, 52 },
+{ 90, 1, 364, 52, 1, 53 },
+{ 91, 2, 0, 0, 1, 0 },
+{ 91, 3, 1, 0, 1, 0 },
+{ 91, 4, 2, 0, 1, 0 },
+{ 91, 5, 3, 0, 1, 0 },
+{ 91, 6, 4, 0, 1, 0 },
+{ 91, 0, 5, 1, 1, 0 },
+{ 91, 1, 6, 1, 2, 1 },
+{ 91, 2, 357, 51, 52, 51 },
+{ 91, 3, 358, 51, 52, 51 },
+{ 91, 4, 359, 51, 52, 51 },
+{ 91, 5, 360, 51, 52, 51 },
+{ 91, 6, 361, 51, 52, 51 },
+{ 91, 0, 362, 52, 52, 51 },
+{ 91, 1, 363, 52, 1, 52 },
+{ 91, 2, 364, 52, 1, 52 },
+{ 92, 3, 0, 0, 1, 0 },
+{ 92, 4, 1, 0, 1, 0 },
+{ 92, 5, 2, 0, 1, 0 },
+{ 92, 6, 3, 0, 1, 0 },
+{ 92, 0, 4, 1, 1, 0 },
+{ 92, 1, 5, 1, 2, 1 },
+{ 92, 2, 6, 1, 2, 1 },
+{ 92, 4, 358, 51, 52, 51 },
+{ 92, 5, 359, 51, 52, 51 },
+{ 92, 6, 360, 51, 52, 51 },
+{ 92, 0, 361, 52, 52, 51 },
+{ 92, 1, 362, 52, 53, 52 },
+{ 92, 2, 363, 52, 53, 52 },
+{ 92, 3, 364, 52, 53, 52 },
+{ 92, 4, 365, 52, 53, 52 },
+{ 93, 5, 0, 0, 53, 0 },
+{ 93, 6, 1, 0, 53, 0 },
+{ 93, 0, 2, 1, 53, 0 },
+{ 93, 1, 3, 1, 1, 1 },
+{ 93, 2, 4, 1, 1, 1 },
+{ 93, 3, 5, 1, 1, 1 },
+{ 93, 4, 6, 1, 1, 1 },
+{ 93, 5, 357, 51, 51, 51 },
+{ 93, 6, 358, 51, 51, 51 },
+{ 93, 0, 359, 52, 51, 51 },
+{ 93, 1, 360, 52, 52, 52 },
+{ 93, 2, 361, 52, 52, 52 },
+{ 93, 3, 362, 52, 52, 52 },
+{ 93, 4, 363, 52, 52, 52 },
+{ 93, 5, 364, 52, 52, 52 },
+{ 94, 6, 0, 0, 52, 0 },
+{ 94, 0, 1, 1, 52, 0 },
+{ 94, 1, 2, 1, 1, 1 },
+{ 94, 2, 3, 1, 1, 1 },
+{ 94, 3, 4, 1, 1, 1 },
+{ 94, 4, 5, 1, 1, 1 },
+{ 94, 5, 6, 1, 1, 1 },
+{ 94, 6, 357, 51, 51, 51 },
+{ 94, 0, 358, 52, 51, 51 },
+{ 94, 1, 359, 52, 52, 52 },
+{ 94, 2, 360, 52, 52, 52 },
+{ 94, 3, 361, 52, 52, 52 },
+{ 94, 4, 362, 52, 52, 52 },
+{ 94, 5, 363, 52, 52, 52 },
+{ 94, 6, 364, 52, 52, 52 },
+{ 95, 0, 0, 1, 52, 0 },
+{ 95, 1, 1, 1, 1, 1 },
+{ 95, 2, 2, 1, 1, 1 },
+{ 95, 3, 3, 1, 1, 1 },
+{ 95, 4, 4, 1, 1, 1 },
+{ 95, 5, 5, 1, 1, 1 },
+{ 95, 6, 6, 1, 1, 1 },
+{ 95, 0, 357, 52, 51, 51 },
+{ 95, 1, 358, 52, 52, 52 },
+{ 95, 2, 359, 52, 52, 52 },
+{ 95, 3, 360, 52, 52, 52 },
+{ 95, 4, 361, 52, 52, 52 },
+{ 95, 5, 362, 52, 52, 52 },
+{ 95, 6, 363, 52, 52, 52 },
+{ 95, 0, 364, 53, 52, 52 },
+{ 96, 1, 0, 0, 1, 1 },
+{ 96, 2, 1, 0, 1, 1 },
+{ 96, 3, 2, 0, 1, 1 },
+{ 96, 4, 3, 0, 1, 1 },
+{ 96, 5, 4, 0, 1, 1 },
+{ 96, 6, 5, 0, 1, 1 },
+{ 96, 0, 6, 1, 1, 1 },
+{ 96, 2, 358, 51, 52, 52 },
+{ 96, 3, 359, 51, 52, 52 },
+{ 96, 4, 360, 51, 52, 52 },
+{ 96, 5, 361, 51, 52, 52 },
+{ 96, 6, 362, 51, 52, 52 },
+{ 96, 0, 363, 52, 52, 52 },
+{ 96, 1, 364, 52, 1, 53 },
+{ 96, 2, 365, 52, 1, 53 },
+{ 97, 3, 0, 0, 1, 0 },
+{ 97, 4, 1, 0, 1, 0 },
+{ 97, 5, 2, 0, 1, 0 },
+{ 97, 6, 3, 0, 1, 0 },
+{ 97, 0, 4, 1, 1, 0 },
+{ 97, 1, 5, 1, 2, 1 },
+{ 97, 2, 6, 1, 2, 1 },
+{ 97, 3, 357, 51, 52, 51 },
+{ 97, 4, 358, 51, 52, 51 },
+{ 97, 5, 359, 51, 52, 51 },
+{ 97, 6, 360, 51, 52, 51 },
+{ 97, 0, 361, 52, 52, 51 },
+{ 97, 1, 362, 52, 1, 52 },
+{ 97, 2, 363, 52, 1, 52 },
+{ 97, 3, 364, 52, 1, 52 },
+{ 98, 4, 0, 0, 1, 0 },
+{ 98, 5, 1, 0, 1, 0 },
+{ 98, 6, 2, 0, 1, 0 },
+{ 98, 0, 3, 1, 1, 0 },
+{ 98, 1, 4, 1, 2, 1 },
+{ 98, 2, 5, 1, 2, 1 },
+{ 98, 3, 6, 1, 2, 1 },
+{ 98, 4, 357, 51, 52, 51 },
+{ 98, 5, 358, 51, 52, 51 },
+{ 98, 6, 359, 51, 52, 51 },
+{ 98, 0, 360, 52, 52, 51 },
+{ 98, 1, 361, 52, 53, 52 },
+{ 98, 2, 362, 52, 53, 52 },
+{ 98, 3, 363, 52, 53, 52 },
+{ 98, 4, 364, 52, 53, 52 },
+{ 99, 5, 0, 0, 53, 0 },
+{ 99, 6, 1, 0, 53, 0 },
+{ 99, 0, 2, 1, 53, 0 },
+{ 99, 1, 3, 1, 1, 1 },
+{ 99, 2, 4, 1, 1, 1 },
+{ 99, 3, 5, 1, 1, 1 },
+{ 99, 4, 6, 1, 1, 1 },
+{ 99, 5, 357, 51, 51, 51 },
+{ 99, 6, 358, 51, 51, 51 },
+{ 99, 0, 359, 52, 51, 51 },
+{ 99, 1, 360, 52, 52, 52 },
+{ 99, 2, 361, 52, 52, 52 },
+{ 99, 3, 362, 52, 52, 52 },
+{ 99, 4, 363, 52, 52, 52 },
+{ 99, 5, 364, 52, 52, 52 },
+{ 100, 6, 0, 0, 52, 0 },
+{ 100, 0, 1, 1, 52, 0 },
+{ 100, 1, 2, 1, 1, 1 },
+{ 100, 2, 3, 1, 1, 1 },
+{ 100, 3, 4, 1, 1, 1 },
+{ 100, 4, 5, 1, 1, 1 },
+{ 100, 5, 6, 1, 1, 1 },
+{ 100, 0, 358, 52, 51, 51 },
+{ 100, 1, 359, 52, 52, 52 },
+{ 100, 2, 360, 52, 52, 52 },
+{ 100, 3, 361, 52, 52, 52 },
+{ 100, 4, 362, 52, 52, 52 },
+{ 100, 5, 363, 52, 52, 52 },
+{ 100, 6, 364, 52, 52, 52 },
+{ 100, 0, 365, 53, 52, 52 },
+{ 101, 1, 0, 0, 1, 1 },
+{ 101, 2, 1, 0, 1, 1 },
+{ 101, 3, 2, 0, 1, 1 },
+{ 101, 4, 3, 0, 1, 1 },
+{ 101, 5, 4, 0, 1, 1 },
+{ 101, 6, 5, 0, 1, 1 },
+{ 101, 0, 6, 1, 1, 1 },
+{ 101, 1, 357, 51, 52, 52 },
+{ 101, 2, 358, 51, 52, 52 },
+{ 101, 3, 359, 51, 52, 52 },
+{ 101, 4, 360, 51, 52, 52 },
+{ 101, 5, 361, 51, 52, 52 },
+{ 101, 6, 362, 51, 52, 52 },
+{ 101, 0, 363, 52, 52, 52 },
+{ 101, 1, 364, 52, 1, 53 },
+{ 102, 2, 0, 0, 1, 0 },
+{ 102, 3, 1, 0, 1, 0 },
+{ 102, 4, 2, 0, 1, 0 },
+{ 102, 5, 3, 0, 1, 0 },
+{ 102, 6, 4, 0, 1, 0 },
+{ 102, 0, 5, 1, 1, 0 },
+{ 102, 1, 6, 1, 2, 1 },
+{ 102, 2, 357, 51, 52, 51 },
+{ 102, 3, 358, 51, 52, 51 },
+{ 102, 4, 359, 51, 52, 51 },
+{ 102, 5, 360, 51, 52, 51 },
+{ 102, 6, 361, 51, 52, 51 },
+{ 102, 0, 362, 52, 52, 51 },
+{ 102, 1, 363, 52, 1, 52 },
+{ 102, 2, 364, 52, 1, 52 },
+{ 103, 3, 0, 0, 1, 0 },
+{ 103, 4, 1, 0, 1, 0 },
+{ 103, 5, 2, 0, 1, 0 },
+{ 103, 6, 3, 0, 1, 0 },
+{ 103, 0, 4, 1, 1, 0 },
+{ 103, 1, 5, 1, 2, 1 },
+{ 103, 2, 6, 1, 2, 1 },
+{ 103, 3, 357, 51, 52, 51 },
+{ 103, 4, 358, 51, 52, 51 },
+{ 103, 5, 359, 51, 52, 51 },
+{ 103, 6, 360, 51, 52, 51 },
+{ 103, 0, 361, 52, 52, 51 },
+{ 103, 1, 362, 52, 1, 52 },
+{ 103, 2, 363, 52, 1, 52 },
+{ 103, 3, 364, 52, 1, 52 },
+{ 104, 4, 0, 0, 1, 0 },
+{ 104, 5, 1, 0, 1, 0 },
+{ 104, 6, 2, 0, 1, 0 },
+{ 104, 0, 3, 1, 1, 0 },
+{ 104, 1, 4, 1, 2, 1 },
+{ 104, 2, 5, 1, 2, 1 },
+{ 104, 3, 6, 1, 2, 1 },
+{ 104, 5, 358, 51, 52, 51 },
+{ 104, 6, 359, 51, 52, 51 },
+{ 104, 0, 360, 52, 52, 51 },
+{ 104, 1, 361, 52, 53, 52 },
+{ 104, 2, 362, 52, 53, 52 },
+{ 104, 3, 363, 52, 53, 52 },
+{ 104, 4, 364, 52, 53, 52 },
+{ 104, 5, 365, 52, 53, 52 },
+{ 105, 6, 0, 0, 53, 0 },
+{ 105, 0, 1, 1, 53, 0 },
+{ 105, 1, 2, 1, 1, 1 },
+{ 105, 2, 3, 1, 1, 1 },
+{ 105, 3, 4, 1, 1, 1 },
+{ 105, 4, 5, 1, 1, 1 },
+{ 105, 5, 6, 1, 1, 1 },
+{ 105, 6, 357, 51, 51, 51 },
+{ 105, 0, 358, 52, 51, 51 },
+{ 105, 1, 359, 52, 52, 52 },
+{ 105, 2, 360, 52, 52, 52 },
+{ 105, 3, 361, 52, 52, 52 },
+{ 105, 4, 362, 52, 52, 52 },
+{ 105, 5, 363, 52, 52, 52 },
+{ 105, 6, 364, 52, 52, 52 },
+{ 106, 0, 0, 1, 52, 0 },
+{ 106, 1, 1, 1, 1, 1 },
+{ 106, 2, 2, 1, 1, 1 },
+{ 106, 3, 3, 1, 1, 1 },
+{ 106, 4, 4, 1, 1, 1 },
+{ 106, 5, 5, 1, 1, 1 },
+{ 106, 6, 6, 1, 1, 1 },
+{ 106, 0, 357, 52, 51, 51 },
+{ 106, 1, 358, 52, 52, 52 },
+{ 106, 2, 359, 52, 52, 52 },
+{ 106, 3, 360, 52, 52, 52 },
+{ 106, 4, 361, 52, 52, 52 },
+{ 106, 5, 362, 52, 52, 52 },
+{ 106, 6, 363, 52, 52, 52 },
+{ 106, 0, 364, 53, 52, 52 },
+{ 107, 1, 0, 0, 1, 1 },
+{ 107, 2, 1, 0, 1, 1 },
+{ 107, 3, 2, 0, 1, 1 },
+{ 107, 4, 3, 0, 1, 1 },
+{ 107, 5, 4, 0, 1, 1 },
+{ 107, 6, 5, 0, 1, 1 },
+{ 107, 0, 6, 1, 1, 1 },
+{ 107, 1, 357, 51, 52, 52 },
+{ 107, 2, 358, 51, 52, 52 },
+{ 107, 3, 359, 51, 52, 52 },
+{ 107, 4, 360, 51, 52, 52 },
+{ 107, 5, 361, 51, 52, 52 },
+{ 107, 6, 362, 51, 52, 52 },
+{ 107, 0, 363, 52, 52, 52 },
+{ 107, 1, 364, 52, 1, 53 },
+{ 108, 2, 0, 0, 1, 0 },
+{ 108, 3, 1, 0, 1, 0 },
+{ 108, 4, 2, 0, 1, 0 },
+{ 108, 5, 3, 0, 1, 0 },
+{ 108, 6, 4, 0, 1, 0 },
+{ 108, 0, 5, 1, 1, 0 },
+{ 108, 1, 6, 1, 2, 1 },
+{ 108, 3, 358, 51, 52, 51 },
+{ 108, 4, 359, 51, 52, 51 },
+{ 108, 5, 360, 51, 52, 51 },
+{ 108, 6, 361, 51, 52, 51 },
+{ 108, 0, 362, 52, 52, 51 },
+{ 108, 1, 363, 52, 1, 52 },
+{ 108, 2, 364, 52, 1, 52 },
+{ 108, 3, 365, 52, 1, 52 },
+{ 109, 4, 0, 0, 1, 0 },
+{ 109, 5, 1, 0, 1, 0 },
+{ 109, 6, 2, 0, 1, 0 },
+{ 109, 0, 3, 1, 1, 0 },
+{ 109, 1, 4, 1, 2, 1 },
+{ 109, 2, 5, 1, 2, 1 },
+{ 109, 3, 6, 1, 2, 1 },
+{ 109, 4, 357, 51, 52, 51 },
+{ 109, 5, 358, 51, 52, 51 },
+{ 109, 6, 359, 51, 52, 51 },
+{ 109, 0, 360, 52, 52, 51 },
+{ 109, 1, 361, 52, 53, 52 },
+{ 109, 2, 362, 52, 53, 52 },
+{ 109, 3, 363, 52, 53, 52 },
+{ 109, 4, 364, 52, 53, 52 },
+{ 110, 5, 0, 0, 53, 0 },
+{ 110, 6, 1, 0, 53, 0 },
+{ 110, 0, 2, 1, 53, 0 },
+{ 110, 1, 3, 1, 1, 1 },
+{ 110, 2, 4, 1, 1, 1 },
+{ 110, 3, 5, 1, 1, 1 },
+{ 110, 4, 6, 1, 1, 1 },
+{ 110, 5, 357, 51, 51, 51 },
+{ 110, 6, 358, 51, 51, 51 },
+{ 110, 0, 359, 52, 51, 51 },
+{ 110, 1, 360, 52, 52, 52 },
+{ 110, 2, 361, 52, 52, 52 },
+{ 110, 3, 362, 52, 52, 52 },
+{ 110, 4, 363, 52, 52, 52 },
+{ 110, 5, 364, 52, 52, 52 },
+{ 111, 6, 0, 0, 52, 0 },
+{ 111, 0, 1, 1, 52, 0 },
+{ 111, 1, 2, 1, 1, 1 },
+{ 111, 2, 3, 1, 1, 1 },
+{ 111, 3, 4, 1, 1, 1 },
+{ 111, 4, 5, 1, 1, 1 },
+{ 111, 5, 6, 1, 1, 1 },
+{ 111, 6, 357, 51, 51, 51 },
+{ 111, 0, 358, 52, 51, 51 },
+{ 111, 1, 359, 52, 52, 52 },
+{ 111, 2, 360, 52, 52, 52 },
+{ 111, 3, 361, 52, 52, 52 },
+{ 111, 4, 362, 52, 52, 52 },
+{ 111, 5, 363, 52, 52, 52 },
+{ 111, 6, 364, 52, 52, 52 },
+{ 112, 0, 0, 1, 52, 0 },
+{ 112, 1, 1, 1, 1, 1 },
+{ 112, 2, 2, 1, 1, 1 },
+{ 112, 3, 3, 1, 1, 1 },
+{ 112, 4, 4, 1, 1, 1 },
+{ 112, 5, 5, 1, 1, 1 },
+{ 112, 6, 6, 1, 1, 1 },
+{ 112, 1, 358, 52, 52, 52 },
+{ 112, 2, 359, 52, 52, 52 },
+{ 112, 3, 360, 52, 52, 52 },
+{ 112, 4, 361, 52, 52, 52 },
+{ 112, 5, 362, 52, 52, 52 },
+{ 112, 6, 363, 52, 52, 52 },
+{ 112, 0, 364, 53, 52, 52 },
+{ 112, 1, 365, 53, 1, 53 },
+{ 113, 2, 0, 0, 1, 0 },
+{ 113, 3, 1, 0, 1, 0 },
+{ 113, 4, 2, 0, 1, 0 },
+{ 113, 5, 3, 0, 1, 0 },
+{ 113, 6, 4, 0, 1, 0 },
+{ 113, 0, 5, 1, 1, 0 },
+{ 113, 1, 6, 1, 2, 1 },
+{ 113, 2, 357, 51, 52, 51 },
+{ 113, 3, 358, 51, 52, 51 },
+{ 113, 4, 359, 51, 52, 51 },
+{ 113, 5, 360, 51, 52, 51 },
+{ 113, 6, 361, 51, 52, 51 },
+{ 113, 0, 362, 52, 52, 51 },
+{ 113, 1, 363, 52, 1, 52 },
+{ 113, 2, 364, 52, 1, 52 },
+{ 114, 3, 0, 0, 1, 0 },
+{ 114, 4, 1, 0, 1, 0 },
+{ 114, 5, 2, 0, 1, 0 },
+{ 114, 6, 3, 0, 1, 0 },
+{ 114, 0, 4, 1, 1, 0 },
+{ 114, 1, 5, 1, 2, 1 },
+{ 114, 2, 6, 1, 2, 1 },
+{ 114, 3, 357, 51, 52, 51 },
+{ 114, 4, 358, 51, 52, 51 },
+{ 114, 5, 359, 51, 52, 51 },
+{ 114, 6, 360, 51, 52, 51 },
+{ 114, 0, 361, 52, 52, 51 },
+{ 114, 1, 362, 52, 1, 52 },
+{ 114, 2, 363, 52, 1, 52 },
+{ 114, 3, 364, 52, 1, 52 },
+{ 115, 4, 0, 0, 1, 0 },
+{ 115, 5, 1, 0, 1, 0 },
+{ 115, 6, 2, 0, 1, 0 },
+{ 115, 0, 3, 1, 1, 0 },
+{ 115, 1, 4, 1, 2, 1 },
+{ 115, 2, 5, 1, 2, 1 },
+{ 115, 3, 6, 1, 2, 1 },
+{ 115, 4, 357, 51, 52, 51 },
+{ 115, 5, 358, 51, 52, 51 },
+{ 115, 6, 359, 51, 52, 51 },
+{ 115, 0, 360, 52, 52, 51 },
+{ 115, 1, 361, 52, 53, 52 },
+{ 115, 2, 362, 52, 53, 52 },
+{ 115, 3, 363, 52, 53, 52 },
+{ 115, 4, 364, 52, 53, 52 },
+{ 116, 5, 0, 0, 53, 0 },
+{ 116, 6, 1, 0, 53, 0 },
+{ 116, 0, 2, 1, 53, 0 },
+{ 116, 1, 3, 1, 1, 1 },
+{ 116, 2, 4, 1, 1, 1 },
+{ 116, 3, 5, 1, 1, 1 },
+{ 116, 4, 6, 1, 1, 1 },
+{ 116, 6, 358, 51, 51, 51 },
+{ 116, 0, 359, 52, 51, 51 },
+{ 116, 1, 360, 52, 52, 52 },
+{ 116, 2, 361, 52, 52, 52 },
+{ 116, 3, 362, 52, 52, 52 },
+{ 116, 4, 363, 52, 52, 52 },
+{ 116, 5, 364, 52, 52, 52 },
+{ 116, 6, 365, 52, 52, 52 },
+{ 117, 0, 0, 1, 52, 0 },
+{ 117, 1, 1, 1, 1, 1 },
+{ 117, 2, 2, 1, 1, 1 },
+{ 117, 3, 3, 1, 1, 1 },
+{ 117, 4, 4, 1, 1, 1 },
+{ 117, 5, 5, 1, 1, 1 },
+{ 117, 6, 6, 1, 1, 1 },
+{ 117, 0, 357, 52, 51, 51 },
+{ 117, 1, 358, 52, 52, 52 },
+{ 117, 2, 359, 52, 52, 52 },
+{ 117, 3, 360, 52, 52, 52 },
+{ 117, 4, 361, 52, 52, 52 },
+{ 117, 5, 362, 52, 52, 52 },
+{ 117, 6, 363, 52, 52, 52 },
+{ 117, 0, 364, 53, 52, 52 },
+{ 118, 1, 0, 0, 1, 1 },
+{ 118, 2, 1, 0, 1, 1 },
+{ 118, 3, 2, 0, 1, 1 },
+{ 118, 4, 3, 0, 1, 1 },
+{ 118, 5, 4, 0, 1, 1 },
+{ 118, 6, 5, 0, 1, 1 },
+{ 118, 0, 6, 1, 1, 1 },
+{ 118, 1, 357, 51, 52, 52 },
+{ 118, 2, 358, 51, 52, 52 },
+{ 118, 3, 359, 51, 52, 52 },
+{ 118, 4, 360, 51, 52, 52 },
+{ 118, 5, 361, 51, 52, 52 },
+{ 118, 6, 362, 51, 52, 52 },
+{ 118, 0, 363, 52, 52, 52 },
+{ 118, 1, 364, 52, 1, 53 },
+{ 119, 2, 0, 0, 1, 0 },
+{ 119, 3, 1, 0, 1, 0 },
+{ 119, 4, 2, 0, 1, 0 },
+{ 119, 5, 3, 0, 1, 0 },
+{ 119, 6, 4, 0, 1, 0 },
+{ 119, 0, 5, 1, 1, 0 },
+{ 119, 1, 6, 1, 2, 1 },
+{ 119, 2, 357, 51, 52, 51 },
+{ 119, 3, 358, 51, 52, 51 },
+{ 119, 4, 359, 51, 52, 51 },
+{ 119, 5, 360, 51, 52, 51 },
+{ 119, 6, 361, 51, 52, 51 },
+{ 119, 0, 362, 52, 52, 51 },
+{ 119, 1, 363, 52, 1, 52 },
+{ 119, 2, 364, 52, 1, 52 },
+{ 120, 3, 0, 0, 1, 0 },
+{ 120, 4, 1, 0, 1, 0 },
+{ 120, 5, 2, 0, 1, 0 },
+{ 120, 6, 3, 0, 1, 0 },
+{ 120, 0, 4, 1, 1, 0 },
+{ 120, 1, 5, 1, 2, 1 },
+{ 120, 2, 6, 1, 2, 1 },
+{ 120, 4, 358, 51, 52, 51 },
+{ 120, 5, 359, 51, 52, 51 },
+{ 120, 6, 360, 51, 52, 51 },
+{ 120, 0, 361, 52, 52, 51 },
+{ 120, 1, 362, 52, 53, 52 },
+{ 120, 2, 363, 52, 53, 52 },
+{ 120, 3, 364, 52, 53, 52 },
+{ 120, 4, 365, 52, 53, 52 },
+{ 121, 5, 0, 0, 53, 0 },
+{ 121, 6, 1, 0, 53, 0 },
+{ 121, 0, 2, 1, 53, 0 },
+{ 121, 1, 3, 1, 1, 1 },
+{ 121, 2, 4, 1, 1, 1 },
+{ 121, 3, 5, 1, 1, 1 },
+{ 121, 4, 6, 1, 1, 1 },
+{ 121, 5, 357, 51, 51, 51 },
+{ 121, 6, 358, 51, 51, 51 },
+{ 121, 0, 359, 52, 51, 51 },
+{ 121, 1, 360, 52, 52, 52 },
+{ 121, 2, 361, 52, 52, 52 },
+{ 121, 3, 362, 52, 52, 52 },
+{ 121, 4, 363, 52, 52, 52 },
+{ 121, 5, 364, 52, 52, 52 },
+{ 122, 6, 0, 0, 52, 0 },
+{ 122, 0, 1, 1, 52, 0 },
+{ 122, 1, 2, 1, 1, 1 },
+{ 122, 2, 3, 1, 1, 1 },
+{ 122, 3, 4, 1, 1, 1 },
+{ 122, 4, 5, 1, 1, 1 },
+{ 122, 5, 6, 1, 1, 1 },
+{ 122, 6, 357, 51, 51, 51 },
+{ 122, 0, 358, 52, 51, 51 },
+{ 122, 1, 359, 52, 52, 52 },
+{ 122, 2, 360, 52, 52, 52 },
+{ 122, 3, 361, 52, 52, 52 },
+{ 122, 4, 362, 52, 52, 52 },
+{ 122, 5, 363, 52, 52, 52 },
+{ 122, 6, 364, 52, 52, 52 },
+{ 123, 0, 0, 1, 52, 0 },
+{ 123, 1, 1, 1, 1, 1 },
+{ 123, 2, 2, 1, 1, 1 },
+{ 123, 3, 3, 1, 1, 1 },
+{ 123, 4, 4, 1, 1, 1 },
+{ 123, 5, 5, 1, 1, 1 },
+{ 123, 6, 6, 1, 1, 1 },
+{ 123, 0, 357, 52, 51, 51 },
+{ 123, 1, 358, 52, 52, 52 },
+{ 123, 2, 359, 52, 52, 52 },
+{ 123, 3, 360, 52, 52, 52 },
+{ 123, 4, 361, 52, 52, 52 },
+{ 123, 5, 362, 52, 52, 52 },
+{ 123, 6, 363, 52, 52, 52 },
+{ 123, 0, 364, 53, 52, 52 },
+{ 124, 1, 0, 0, 1, 1 },
+{ 124, 2, 1, 0, 1, 1 },
+{ 124, 3, 2, 0, 1, 1 },
+{ 124, 4, 3, 0, 1, 1 },
+{ 124, 5, 4, 0, 1, 1 },
+{ 124, 6, 5, 0, 1, 1 },
+{ 124, 0, 6, 1, 1, 1 },
+{ 124, 2, 358, 51, 52, 52 },
+{ 124, 3, 359, 51, 52, 52 },
+{ 124, 4, 360, 51, 52, 52 },
+{ 124, 5, 361, 51, 52, 52 },
+{ 124, 6, 362, 51, 52, 52 },
+{ 124, 0, 363, 52, 52, 52 },
+{ 124, 1, 364, 52, 1, 53 },
+{ 124, 2, 365, 52, 1, 53 },
+{ 125, 3, 0, 0, 1, 0 },
+{ 125, 4, 1, 0, 1, 0 },
+{ 125, 5, 2, 0, 1, 0 },
+{ 125, 6, 3, 0, 1, 0 },
+{ 125, 0, 4, 1, 1, 0 },
+{ 125, 1, 5, 1, 2, 1 },
+{ 125, 2, 6, 1, 2, 1 },
+{ 125, 3, 357, 51, 52, 51 },
+{ 125, 4, 358, 51, 52, 51 },
+{ 125, 5, 359, 51, 52, 51 },
+{ 125, 6, 360, 51, 52, 51 },
+{ 125, 0, 361, 52, 52, 51 },
+{ 125, 1, 362, 52, 1, 52 },
+{ 125, 2, 363, 52, 1, 52 },
+{ 125, 3, 364, 52, 1, 52 },
+{ 126, 4, 0, 0, 1, 0 },
+{ 126, 5, 1, 0, 1, 0 },
+{ 126, 6, 2, 0, 1, 0 },
+{ 126, 0, 3, 1, 1, 0 },
+{ 126, 1, 4, 1, 2, 1 },
+{ 126, 2, 5, 1, 2, 1 },
+{ 126, 3, 6, 1, 2, 1 },
+{ 126, 4, 357, 51, 52, 51 },
+{ 126, 5, 358, 51, 52, 51 },
+{ 126, 6, 359, 51, 52, 51 },
+{ 126, 0, 360, 52, 52, 51 },
+{ 126, 1, 361, 52, 53, 52 },
+{ 126, 2, 362, 52, 53, 52 },
+{ 126, 3, 363, 52, 53, 52 },
+{ 126, 4, 364, 52, 53, 52 },
+{ 127, 5, 0, 0, 53, 0 },
+{ 127, 6, 1, 0, 53, 0 },
+{ 127, 0, 2, 1, 53, 0 },
+{ 127, 1, 3, 1, 1, 1 },
+{ 127, 2, 4, 1, 1, 1 },
+{ 127, 3, 5, 1, 1, 1 },
+{ 127, 4, 6, 1, 1, 1 },
+{ 127, 5, 357, 51, 51, 51 },
+{ 127, 6, 358, 51, 51, 51 },
+{ 127, 0, 359, 52, 51, 51 },
+{ 127, 1, 360, 52, 52, 52 },
+{ 127, 2, 361, 52, 52, 52 },
+{ 127, 3, 362, 52, 52, 52 },
+{ 127, 4, 363, 52, 52, 52 },
+{ 127, 5, 364, 52, 52, 52 },
+{ 128, 6, 0, 0, 52, 0 },
+{ 128, 0, 1, 1, 52, 0 },
+{ 128, 1, 2, 1, 1, 1 },
+{ 128, 2, 3, 1, 1, 1 },
+{ 128, 3, 4, 1, 1, 1 },
+{ 128, 4, 5, 1, 1, 1 },
+{ 128, 5, 6, 1, 1, 1 },
+{ 128, 0, 358, 52, 51, 51 },
+{ 128, 1, 359, 52, 52, 52 },
+{ 128, 2, 360, 52, 52, 52 },
+{ 128, 3, 361, 52, 52, 52 },
+{ 128, 4, 362, 52, 52, 52 },
+{ 128, 5, 363, 52, 52, 52 },
+{ 128, 6, 364, 52, 52, 52 },
+{ 128, 0, 365, 53, 52, 52 },
+{ 129, 1, 0, 0, 1, 1 },
+{ 129, 2, 1, 0, 1, 1 },
+{ 129, 3, 2, 0, 1, 1 },
+{ 129, 4, 3, 0, 1, 1 },
+{ 129, 5, 4, 0, 1, 1 },
+{ 129, 6, 5, 0, 1, 1 },
+{ 129, 0, 6, 1, 1, 1 },
+{ 129, 1, 357, 51, 52, 52 },
+{ 129, 2, 358, 51, 52, 52 },
+{ 129, 3, 359, 51, 52, 52 },
+{ 129, 4, 360, 51, 52, 52 },
+{ 129, 5, 361, 51, 52, 52 },
+{ 129, 6, 362, 51, 52, 52 },
+{ 129, 0, 363, 52, 52, 52 },
+{ 129, 1, 364, 52, 1, 53 },
+{ 130, 2, 0, 0, 1, 0 },
+{ 130, 3, 1, 0, 1, 0 },
+{ 130, 4, 2, 0, 1, 0 },
+{ 130, 5, 3, 0, 1, 0 },
+{ 130, 6, 4, 0, 1, 0 },
+{ 130, 0, 5, 1, 1, 0 },
+{ 130, 1, 6, 1, 2, 1 },
+{ 130, 2, 357, 51, 52, 51 },
+{ 130, 3, 358, 51, 52, 51 },
+{ 130, 4, 359, 51, 52, 51 },
+{ 130, 5, 360, 51, 52, 51 },
+{ 130, 6, 361, 51, 52, 51 },
+{ 130, 0, 362, 52, 52, 51 },
+{ 130, 1, 363, 52, 1, 52 },
+{ 130, 2, 364, 52, 1, 52 },
+{ 131, 3, 0, 0, 1, 0 },
+{ 131, 4, 1, 0, 1, 0 },
+{ 131, 5, 2, 0, 1, 0 },
+{ 131, 6, 3, 0, 1, 0 },
+{ 131, 0, 4, 1, 1, 0 },
+{ 131, 1, 5, 1, 2, 1 },
+{ 131, 2, 6, 1, 2, 1 },
+{ 131, 3, 357, 51, 52, 51 },
+{ 131, 4, 358, 51, 52, 51 },
+{ 131, 5, 359, 51, 52, 51 },
+{ 131, 6, 360, 51, 52, 51 },
+{ 131, 0, 361, 52, 52, 51 },
+{ 131, 1, 362, 52, 1, 52 },
+{ 131, 2, 363, 52, 1, 52 },
+{ 131, 3, 364, 52, 1, 52 },
+{ 132, 4, 0, 0, 1, 0 },
+{ 132, 5, 1, 0, 1, 0 },
+{ 132, 6, 2, 0, 1, 0 },
+{ 132, 0, 3, 1, 1, 0 },
+{ 132, 1, 4, 1, 2, 1 },
+{ 132, 2, 5, 1, 2, 1 },
+{ 132, 3, 6, 1, 2, 1 },
+{ 132, 5, 358, 51, 52, 51 },
+{ 132, 6, 359, 51, 52, 51 },
+{ 132, 0, 360, 52, 52, 51 },
+{ 132, 1, 361, 52, 53, 52 },
+{ 132, 2, 362, 52, 53, 52 },
+{ 132, 3, 363, 52, 53, 52 },
+{ 132, 4, 364, 52, 53, 52 },
+{ 132, 5, 365, 52, 53, 52 },
+{ 133, 6, 0, 0, 53, 0 },
+{ 133, 0, 1, 1, 53, 0 },
+{ 133, 1, 2, 1, 1, 1 },
+{ 133, 2, 3, 1, 1, 1 },
+{ 133, 3, 4, 1, 1, 1 },
+{ 133, 4, 5, 1, 1, 1 },
+{ 133, 5, 6, 1, 1, 1 },
+{ 133, 6, 357, 51, 51, 51 },
+{ 133, 0, 358, 52, 51, 51 },
+{ 133, 1, 359, 52, 52, 52 },
+{ 133, 2, 360, 52, 52, 52 },
+{ 133, 3, 361, 52, 52, 52 },
+{ 133, 4, 362, 52, 52, 52 },
+{ 133, 5, 363, 52, 52, 52 },
+{ 133, 6, 364, 52, 52, 52 },
+{ 134, 0, 0, 1, 52, 0 },
+{ 134, 1, 1, 1, 1, 1 },
+{ 134, 2, 2, 1, 1, 1 },
+{ 134, 3, 3, 1, 1, 1 },
+{ 134, 4, 4, 1, 1, 1 },
+{ 134, 5, 5, 1, 1, 1 },
+{ 134, 6, 6, 1, 1, 1 },
+{ 134, 0, 357, 52, 51, 51 },
+{ 134, 1, 358, 52, 52, 52 },
+{ 134, 2, 359, 52, 52, 52 },
+{ 134, 3, 360, 52, 52, 52 },
+{ 134, 4, 361, 52, 52, 52 },
+{ 134, 5, 362, 52, 52, 52 },
+{ 134, 6, 363, 52, 52, 52 },
+{ 134, 0, 364, 53, 52, 52 },
+{ 135, 1, 0, 0, 1, 1 },
+{ 135, 2, 1, 0, 1, 1 },
+{ 135, 3, 2, 0, 1, 1 },
+{ 135, 4, 3, 0, 1, 1 },
+{ 135, 5, 4, 0, 1, 1 },
+{ 135, 6, 5, 0, 1, 1 },
+{ 135, 0, 6, 1, 1, 1 },
+{ 135, 1, 357, 51, 52, 52 },
+{ 135, 2, 358, 51, 52, 52 },
+{ 135, 3, 359, 51, 52, 52 },
+{ 135, 4, 360, 51, 52, 52 },
+{ 135, 5, 361, 51, 52, 52 },
+{ 135, 6, 362, 51, 52, 52 },
+{ 135, 0, 363, 52, 52, 52 },
+{ 135, 1, 364, 52, 1, 53 },
+{ 136, 2, 0, 0, 1, 0 },
+{ 136, 3, 1, 0, 1, 0 },
+{ 136, 4, 2, 0, 1, 0 },
+{ 136, 5, 3, 0, 1, 0 },
+{ 136, 6, 4, 0, 1, 0 },
+{ 136, 0, 5, 1, 1, 0 },
+{ 136, 1, 6, 1, 2, 1 },
+{ 136, 3, 358, 51, 52, 51 },
+{ 136, 4, 359, 51, 52, 51 },
+{ 136, 5, 360, 51, 52, 51 },
+{ 136, 6, 361, 51, 52, 51 },
+{ 136, 0, 362, 52, 52, 51 },
+{ 136, 1, 363, 52, 1, 52 },
+{ 136, 2, 364, 52, 1, 52 },
+{ 136, 3, 365, 52, 1, 52 },
+{ 137, 4, 0, 0, 1, 0 },
+{ 137, 5, 1, 0, 1, 0 },
+{ 137, 6, 2, 0, 1, 0 },
+{ 137, 0, 3, 1, 1, 0 },
+{ 137, 1, 4, 1, 2, 1 },
+{ 137, 2, 5, 1, 2, 1 },
+{ 137, 3, 6, 1, 2, 1 },
+{ 137, 4, 357, 51, 52, 51 },
+{ 137, 5, 358, 51, 52, 51 },
+{ 137, 6, 359, 51, 52, 51 },
+{ 137, 0, 360, 52, 52, 51 },
+{ 137, 1, 361, 52, 53, 52 },
+{ 137, 2, 362, 52, 53, 52 },
+{ 137, 3, 363, 52, 53, 52 },
+{ 137, 4, 364, 52, 53, 52 },
+};
+
+static int test_week_calc( void )
+{
+ char buffer[100];
+ int rc = 1;
+ int i;
+ for ( i = 0; i < 1020; ++i )
+ {
+ struct tm t = { 0 };
+ int U, V, W;
+ t.tm_year = data[i][0];
+ t.tm_wday = data[i][1];
+ t.tm_yday = data[i][2];
+ assert( strftime( buffer, 100, "%U %V %W", &t ) == 8 );
+ assert( sscanf( buffer, "%d %d %d", &U, &V, &W ) == 3 );
+ if ( data[i][3] != U || data[i][4] != V || data[i][5] != W )
+ {
+ printf( "Fehler in { %d, %d, %d, %d, %d, %d } (encountered { %d, %d, %d })\n", data[i][0], data[i][1], data[i][2], data[i][3], data[i][4], data[i][5], U, V, W );
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+int main( void )
+{
+ char buffer[100];
+ /* Basic functionality */
+ struct tm timeptr;
+ MKTIME( timeptr, 59, 30, 12, 1, 9, 72, 0, 274 );
+ TESTCASE( strftime( buffer, 100, "%a ", &timeptr ) == 4 );
+ TESTCASE( strcmp( buffer, "Sun " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%A ", &timeptr ) == 7 );
+ TESTCASE( strcmp( buffer, "Sunday " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%b ", &timeptr ) == 4 );
+ TESTCASE( strcmp( buffer, "Oct " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%h ", &timeptr ) == 4 );
+ TESTCASE( strcmp( buffer, "Oct " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%B ", &timeptr ) == 8 );
+ TESTCASE( strcmp( buffer, "October " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%c ", &timeptr ) == 25 );
+ TESTCASE( strcmp( buffer, "Sun Oct 1 12:30:59 1972 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%C ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "19 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%d ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "01 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%D ", &timeptr ) == 9 );
+ TESTCASE( strcmp( buffer, "10/01/72 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%e ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, " 1 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%F ", &timeptr ) == 11 );
+ TESTCASE( strcmp( buffer, "1972-10-01 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%H ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "12 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%I ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "12 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%j ", &timeptr ) == 4 );
+ TESTCASE( strcmp( buffer, "275 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%m ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "10 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%M ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "30 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%p ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "PM " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%r ", &timeptr ) == 12 );
+ TESTCASE( strcmp( buffer, "12:30:59 PM " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%R ", &timeptr ) == 6 );
+ TESTCASE( strcmp( buffer, "12:30 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%S ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "59 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%T ", &timeptr ) == 9 );
+ TESTCASE( strcmp( buffer, "12:30:59 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%u ", &timeptr ) == 2 );
+ TESTCASE( strcmp( buffer, "7 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%w ", &timeptr ) == 2 );
+ TESTCASE( strcmp( buffer, "0 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%x ", &timeptr ) == 9 );
+ TESTCASE( strcmp( buffer, "10/01/72 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%X ", &timeptr ) == 9 );
+ TESTCASE( strcmp( buffer, "12:30:59 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%y ", &timeptr ) == 3 );
+ TESTCASE( strcmp( buffer, "72 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%Y ", &timeptr ) == 5 );
+ TESTCASE( strcmp( buffer, "1972 " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%% ", &timeptr ) == 2 );
+ TESTCASE( strcmp( buffer, "% " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%n ", &timeptr ) == 2 );
+ TESTCASE( strcmp( buffer, "\n " ) == 0 );
+ TESTCASE( strftime( buffer, 100, "%t ", &timeptr ) == 2 );
+ TESTCASE( strcmp( buffer, "\t " ) == 0 );
+ TESTCASE( test_week_calc() );
+ return TEST_RESULTS;
+}
+
+#endif